Back to Repositories

Validating Analytics Event Tracking Workflow in Insomnia

This test suite validates analytics event tracking in the Insomnia application, focusing on Segment integration and event capture. It ensures proper event transmission and data structure for user interactions and application states.

Test Coverage Overview

The test suite provides comprehensive coverage of analytics event tracking functionality.

Key areas tested include:
  • Application start event capture
  • User interaction events (collection and request creation)
  • Event batch processing
  • User identification (anonymousId and userId)
Integration points focus on Segment API communication and session management.

Implementation Analysis

The testing approach utilizes Playwright’s evaluation capabilities to intercept and validate Segment analytics requests. The implementation leverages TypeScript interfaces for type-safe event data structure validation and employs session-level web request interception for comprehensive analytics tracking.

Key patterns include request interception, event batching, and buffer data decoding.

Technical Details

Testing tools and configuration:
  • Playwright test framework
  • TypeScript for type safety
  • Custom interfaces for Segment data validation
  • Web request interception via session.defaultSession.webRequest
  • Buffer encoding/decoding for data verification

Best Practices Demonstrated

The test demonstrates excellent testing practices through structured event validation and comprehensive assertion coverage.

Notable practices include:
  • Type-safe data structure validation
  • Atomic test assertions
  • Real-world user interaction simulation
  • Robust event batch verification
  • Clear separation of setup and verification phases

kong/insomnia

packages/insomnia-smoke-test/tests/smoke/analytics.test.ts

            
import { expect } from '@playwright/test';

import { test } from '../../playwright/test';

interface SegmentRequestData {
    batch: {
        timestamp: string;
        integrations: {};
        type: string;
        properties: {};
        name?: string;
        context: {
            app: {
                name: string;
                version: string;
            };
            os: {
                name: string;
                version: string;
            };
            library: {
                name: string;
                version: string;
            };
        };
        anonymousId: string;
        userId: string;
        messageId: string;
        _metadata: {
            nodeVersion: string;
            jsRuntime: string;
        };
        event?: string;
    }[];
    writeKey: string;
    sentAt: string;
}

interface SegmentLog {
    url: string;
    data: SegmentRequestData[];
}

test('analytics events are sent', async ({ page, app }) => {
    await app.evaluate(async ({ session }) => {
        // Capture segment requests to a global variable in main process
        globalThis.segmentLogs = [];

        session.defaultSession.webRequest.onBeforeRequest((details, callback) => {
            if (details.url.includes('segment')) {
                globalThis.segmentLogs.push({ url: details.url, data: details.uploadData });
            }
            callback({ cancel: false });
        });
    });

    // Create a collection and requests that cause analytics events:
    await page.getByRole('button', { name: 'New Collection' }).click();
    await page.getByRole('button', { name: 'Create', exact: true }).click();

    for (let i = 0; i < 10; i++) {
        await page.getByLabel('Create in collection').click();
        await page.getByRole('menuitemradio', { name: 'HTTP Request' }).press('Enter');
    }

    const segmentLogs = await app.evaluate(() => globalThis.segmentLogs);

    const decodedLogs: SegmentLog[] = segmentLogs.map((log: { url: string; data: { type: string; bytes: number[] }[] }) => {
        return {
            url: log.url,
            data: log.data.map(data => JSON.parse(Buffer.from(Object.values(data.bytes)).toString('utf-8'))),
        };
    });

    const analyticsBatch = decodedLogs[0].data[0].batch;
    const [appStartEvent, ...restEvents] = analyticsBatch;

    // Analytics need at least 15 events to be sent
    expect(analyticsBatch.length).toBeGreaterThanOrEqual(15);

    // App start event
    expect(appStartEvent.anonymousId).toBeTruthy();
    expect(appStartEvent.event).toBe('App Started');

    // First event should have userId and anonymousId
    expect(restEvents[0].anonymousId).toBeTruthy();
    expect(restEvents[0].userId).toBeTruthy();

    // Last event should have userId and anonymousId
    expect(restEvents.at(-1)?.anonymousId).toBeTruthy();
    expect(restEvents.at(-1)?.userId).toBeTruthy();

});