Skip to content

Repository files navigation

Satori QA Validator

A React + Electron application for validating analytics event implementations against Excel-based tracking plans. Testers run bounded QA sessions that poll a Satori identity in real time, automatically matching observed events and properties against expected definitions, and producing exportable pass/fail reports for regression sign-off.

Table of Contents

Overview

QA and product teams need a reliable way to verify that analytics events fire correctly during regression testing. Manual validation is fragmented and error-prone. This tool automates the process by:

  1. Importing an Excel tracking plan that defines expected events, event metadata properties, and identity properties
  2. Polling the Satori API for a specific identity to capture live events
  3. Auto-matching received events against the expected checklist in real time
  4. Tracking identity and event metadata properties for completeness
  5. Generating a pass/fail report exportable as JSON or CSV

How It Works

Sign in to Satori (Dev or Prod)
         ↓
Upload Excel Tracking Plan
         ↓
Enter Identity ID → Click "Start Session"
         ↓
Polls Satori API every 6 seconds:
  • GET /v1/console/identity/{id}/event
  • GET /v1/console/identity/{id}
         ↓
Auto-matches events against expected checklist
Tracks identity properties and event metadata
         ↓
Tester reviews results, flags data issues
         ↓
Click "Stop Session" → View Report → Export (JSON / CSV)

Features

  • Per-engineer authentication — OAuth-style login (email + password + MFA) against the engineer's chosen Satori environment. No shared API keys.
  • Configurable endpoints — Each engineer types their Satori endpoint URL once and it's saved to the browser. The codebase itself contains no infrastructure URLs.
  • Session management — Start, pause, resume, and stop bounded QA sessions
  • Live event feed — Wide, dominant feed with pretty-printed JSON payloads, filter chips (All / Expected / Unexpected / Hide property syncs), and expand-all toggle
  • Tabbed inspector — Expected events, identity properties, and event properties all share a single tabbed pane on the right
  • Consolidated stat bar — Three summary cards at the top show pass/fail/pending and completion percent for each tracking dimension
  • Event checklist — Expected events auto-check as they arrive; manually mark missing events as failed with notes
  • Identity properties tracking — Monitors identity properties (default, custom, computed) against expectations; tracks value changes over time
  • Event metadata properties tracking — Validates event metadata properties across all received events
  • Property flagging — Flag incorrect event metadata values with expected-value annotations
  • Auth-lost recovery — If a token expires mid-session, an overlay prompts for re-login and resumes the QA session with all in-flight state intact
  • Status filtering — Filter checklist items by Excel status (e.g., "Active", "In Progress", "Done")
  • Report generation — Summary overlay with overall verdict (PASS / FAIL / INCOMPLETE), progress bars, and detailed tables
  • Export — Download reports as JSON or CSV; copy summary to clipboard
  • Resilient ingestion — Defensive parsing layer drops malformed payloads, coerces non-string property values to safe strings, and pretty-prints stringified-JSON values (including doubly-stringified Flutter SDK payloads). Per-panel error boundaries contain rendering failures.
  • Electron support — Runs as a desktop app via Electron or as a standard web app

Architecture

Technology Stack

Layer Technology
Framework React 19 + TypeScript 5.8
Build Vite 7
State Management Zustand 5
Routing React Router 7
Excel Parsing SheetJS (xlsx)
Desktop Electron 35 + electron-builder

State Management

Three Zustand stores drive the application:

  • authStore — Auth lifecycle (unauthenticated / authenticated / lost). Token + refresh token live in services/auth.ts module memory, never persisted. The store exposes a lost state distinct from unauthenticated so the UI can preserve QA session data while prompting for re-login.
  • qaSessionStore — Session lifecycle (idlerunningcompleted), event checklist, identity property checklist, event metadata property checklist, received events, unexpected events/properties, deduplication, and session summary computation
  • trackingPlanStore — Parsed Excel tracking plan data (MasterJson)

Key Design Decisions

  • No persisted credentials — Access and refresh tokens live in memory only. A page reload or app relaunch returns the engineer to the login screen. The security stance is: tokens that don't exist on disk can't be stolen from a lost/borrowed machine.
  • No infrastructure in the bundle — Satori endpoint URLs are entered by the engineer at login and saved to their browser's localStorage. The compiled bundle contains no URLs, no keys, no tenant identifiers — safe to host publicly. Optional VITE_SATORI_{DEV,PROD}_BASE env vars can pre-fill the field for trusted internal builds.
  • Polling over WebSockets — Uses a 6-second polling interval against the Satori console API. No instrumentation changes needed in the app under test.
  • Token-based auth with auto-refresh — Bearer tokens attached on every request. On 401, the http layer attempts a single inline refresh and retries; on refresh failure it flips authStore.status to lost, which pauses polling and surfaces the re-login overlay without unmounting any QA state.
  • Event deduplication — A Set<string> of seen event IDs prevents double-counting across poll cycles.
  • Time-window filtering — Only events after the session start time are processed.
  • Defensive ingestion — Polling rejects events without a string name and normalizes metadata to a plain object before storing. Identity property values are coerced to strings via JSON.stringify so nested API responses can't crash the React tree.
  • Flexible Excel parsing — Column name matching is case-insensitive, ignores punctuation, and scores header rows to find the best match.
  • Per-panel error boundaries — Each major panel is wrapped so a single malformed payload contains the failure to one pane instead of blanking the app.

File Structure

src/
├── pages/
│   └── qa-validation.tsx            # Main page layout (AuthGate + feed-dominant 2-column grid)
├── components/
│   ├── auth/
│   │   ├── AuthGate.tsx             # Renders LoginScreen when unauthenticated; children otherwise
│   │   ├── LoginScreen.tsx          # Full-page sign-in with env toggle + endpoint URL field
│   │   └── AuthLostOverlay.tsx      # Mid-session re-login modal that preserves QA state
│   ├── qa/
│   │   ├── QASessionHeader.tsx      # Session controls, identity input, status cluster, sign-out
│   │   ├── StatBar.tsx              # Three summary cards (Events / Identity / Event Props)
│   │   ├── InspectorTabs.tsx        # Tab switcher for the three checklist panels
│   │   ├── EventFeedPanel.tsx       # Live event stream with filter chips + expand-all
│   │   ├── ChecklistPanel.tsx       # Expected events tracker (pass/fail/pending)
│   │   ├── IdentityPropsPanel.tsx   # Identity properties checklist + change history
│   │   ├── EventPropsPanel.tsx      # Event metadata properties tracker
│   │   ├── QAReportOverlay.tsx      # Report modal with export options
│   │   └── PollRing.tsx             # Animated polling countdown indicator
│   ├── ui/
│   │   ├── Button.tsx               # Button variants (Primary, Secondary, Success, Danger)
│   │   ├── Badge.tsx                # Status badges
│   │   ├── Card.tsx                 # Card containers
│   │   ├── Table.tsx                # Table components
│   │   └── index.ts                 # UI barrel exports
│   ├── PanelErrorBoundary.tsx       # Contains render-time exceptions to a single panel
│   ├── excel_drop_zone.tsx          # File upload for .xlsx/.xls tracking plans
│   ├── stat.tsx                     # Statistics display card
│   └── toast.tsx                    # Toast notification component
├── hooks/
│   ├── useQAPolling.ts              # Polling loop (6s interval, auth-aware pause/resume)
│   ├── useToast.ts                  # Toast notification hook
│   └── index.ts
├── store/
│   ├── authStore.ts                 # Auth lifecycle (unauthenticated / authenticated / lost)
│   ├── qaSessionStore.ts            # QA session state + actions
│   ├── trackingPlanStore.ts         # Excel tracking plan state
│   └── index.ts
├── services/
│   ├── auth.ts                      # Login, refresh, logout. In-memory token state only.
│   ├── environment.ts               # Per-env URL resolution (localStorage + optional env-var pre-fill)
│   ├── satori.ts                    # API methods (getIdentityEvents, getIdentity)
│   └── http.ts                      # Bearer-token fetcher with 401 → refresh → retry / auth-lost
├── excel/
│   └── masterJson.ts                # Excel parsing + normalization logic
├── types/
│   ├── qa.ts                        # QA types (ChecklistItem, PropertyChecklistItem, etc.)
│   └── master.ts                    # Excel types (ExcelEvent, ExcelProperty, etc.)
├── utils/
│   ├── qaExport.ts                  # Session export to JSON
│   ├── qaReportExport.ts            # Report generation, CSV export, clipboard copy
│   ├── statusVariants.ts            # Status string → color variant mapping
│   └── validators.ts                # Validation helpers
├── App.tsx                          # Root component (HashRouter for Electron, BrowserRouter for web)
├── main.tsx                         # React entry point
└── vite-env.d.ts                    # Vite type declarations

Setup & Usage

Prerequisites

  • Node.js 18+
  • A Satori Analytics account with login credentials (and MFA if your tenant requires it)
  • The Satori API endpoint URL for the environment(s) you want to test against
  • An Excel tracking plan (.xlsx)

Installation

npm install

Environment Variables (optional)

A .env file is not required. Engineers enter their Satori endpoint URL on the login screen and it's saved per-browser to localStorage.

For internal/Electron builds you control, you can pre-fill the endpoint fields by setting:

VITE_SATORI_DEV_BASE=https://your-dev-instance.satoricloud.io
VITE_SATORI_PROD_BASE=https://your-prod-instance.satoricloud.io

Engineers can still override these values from the login screen if needed. Public/CI builds should leave them unset so the bundle contains no infrastructure references.

Running

Web (development)

npm run dev

Electron (development)

npm run electron:dev

Production build (web)

npm run build
npm run preview

Production build (Electron)

npm run electron:build

Usage Flow

  1. Sign in — Pick Dev or Prod, enter (or paste) the Satori endpoint URL, then your email + password + MFA
  2. Upload your Excel tracking plan using the file upload button
  3. Enter the identity ID you want to monitor
  4. Start Session — polling begins, events appear in the live feed
  5. Interact with the application under test to trigger analytics events
  6. Watch the checklist auto-check as expected events arrive
  7. Flag any event metadata properties that contain incorrect values
  8. Stop Session to freeze results
  9. View Report for overall verdict and detailed breakdown
  10. Export the report as JSON or CSV for regression evidence

If your access token expires mid-session, a re-login overlay appears — sign in again and polling resumes with all your in-flight QA data intact.

Excel Tracking Plan Format

The Excel file should contain up to three sheets:

Events Sheet

Column Description
TRACK this event Event name
WHEN Trigger condition
Status Active / Parked / Remove
SATORI VALUE Expected value type
Feature Product feature
Action User action
NOTES Additional context

Properties Sheet

Column Description
TRACK this property Property name
WHEN below event occurs: Associated event name
Type Data type (String, Number, Boolean, Object)
Status Active / Parked / Remove
Description Property description
Example Example values

Identity Props Sheet (optional)

Column Description
Property Name Identity property name
WHEN When the property is set
Type Data type
Status Active / Parked / Remove
Example Example value
Description Property description

Column matching is flexible — headers are matched case-insensitively with punctuation removed.

API Integration

Authentication

Per-engineer OAuth-style login. The login screen POSTs credentials to the configured endpoint and receives a bearer token:

POST {endpoint}/v1/console/authenticate
Content-Type: application/json

{ "email": "...", "password": "...", "mfa": "..." }

Successful response:

{ "token": "...", "refresh_token": "..." }

Subsequent requests attach the access token:

Authorization: Bearer {token}

When a request returns 401, the http layer attempts a single inline refresh:

POST {endpoint}/v1/console/authenticate/refresh
{ "refresh_token": "..." }

If refresh succeeds, the original request is retried once with the new token. If refresh fails, the auth store transitions to lost, polling pauses, and the re-login overlay mounts over the existing QA UI — preserving all session data until the engineer re-authenticates.

Endpoints Used

Method Endpoint Purpose
POST /v1/console/authenticate Login (email + password + MFA → token)
POST /v1/console/authenticate/refresh Exchange refresh token for new access token
GET /v1/console/identity/{id}/event Fetch events for an identity
GET /v1/console/identity/{id} Fetch identity with properties

Development

Scripts

Command Description
npm run dev Start Vite dev server
npm run build TypeScript compile + Vite production build
npm run preview Preview production build
npm run lint Run ESLint
npm run electron:dev Start Vite + Electron with hot reload
npm run electron:build Package as distributable Electron app
npm run electron:preview Preview Electron app locally

Key Dependencies

Package Purpose
react / react-dom UI framework
react-router-dom Client-side routing
zustand Lightweight state management
xlsx Excel file parsing
electron Desktop app shell
electron-builder Desktop packaging
vite Build tool with HMR

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages