Playwright E2E Testing Setup with Traffic Tracking and OpenTelemetry

Complete E2E testing infrastructure for schema-org-file-system dashboard with traffic tracking headers, OpenTelemetry distributed tracing, HAR recording, and Core Web Vitals measurement.

Playwright E2E Testing Setup with Traffic Tracking and OpenTelemetry

Session Date: 2026-01-19 Project: schema-org-file-system Focus: Implement comprehensive E2E testing infrastructure with observability Session Type: Implementation

Executive Summary

Implemented a complete Playwright E2E testing framework for the schema-org-file-system dashboard. The setup includes traffic tracking headers for request correlation, OpenTelemetry integration for distributed tracing, HAR recording for network analysis, and Core Web Vitals measurement for performance monitoring.

Created 14 files including 4 test fixtures, 4 test spec files covering all dashboard pages, global setup/teardown for OTEL initialization, and configuration files. Installed 199 npm packages and 3 Playwright browsers (Chromium, Firefox, WebKit).

Key Metrics: | Metric | Value | |——–|——-| | Files Created | 14 | | Test Spec Files | 4 | | Fixture Modules | 5 | | NPM Packages Added | 199 | | Browsers Installed | 3 | | Build Errors | 0 |

Problem Statement

The schema-org-file-system project has a dashboard (_site/) with multiple HTML pages but no automated E2E testing infrastructure. Key requirements:

  1. Traffic Tracking: Ability to identify test traffic in production logs
  2. Distributed Tracing: OpenTelemetry integration for observability
  3. Network Analysis: HAR file recording for debugging
  4. Performance Monitoring: Core Web Vitals measurement (LCP, FCP, CLS, TTFB)
  5. Multi-Browser Testing: Chromium, Firefox, WebKit, and mobile viewports

Implementation Details

Configuration Files

File: playwright.config.ts

export default defineConfig({
  testDir: './tests/e2e',
  fullyParallel: true,
  reporter: [
    ['html', { outputFolder: 'playwright-report' }],
    ['json', { outputFile: 'results/e2e-results.json' }],
    ['list']
  ],
  globalSetup: './tests/e2e/global-setup.ts',
  globalTeardown: './tests/e2e/global-teardown.ts',
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
    { name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
    { name: 'mobile-safari', use: { ...devices['iPhone 12'] } },
  ],
  webServer: {
    command: 'npm run serve',
    url: 'http://localhost:3000',
  },
});

Traffic Tracking Fixture

File: tests/e2e/fixtures/traffic-tracking.ts

Injects tracking headers on all requests:

await page.route('**/*', async (route) => {
  const headers = {
    ...route.request().headers(),
    'X-Test-Traffic': 'playwright-e2e',
    'X-Request-ID': uuidv4(),
    'X-Correlation-ID': correlationId,
    'X-Test-Name': testName,
    'X-Test-File': testFile,
  };
  await route.continue({ headers });
});

Headers Injected: | Header | Description | |——–|————-| | X-Test-Traffic | Identifies traffic as E2E test (always playwright-e2e) | | X-Request-ID | UUID per request for individual request tracking | | X-Correlation-ID | UUID per test run for correlating all requests | | X-Test-Name | Test title for debugging | | X-Test-File | Spec filename for traceability |

OpenTelemetry Integration

File: tests/e2e/fixtures/otel-tracing.ts

Creates spans for tests and network requests:

page.on('request', (request: Request) => {
  const span = tracer.startSpan(`HTTP ${request.method()} ${pathname}`, {
    attributes: {
      'http.method': request.method(),
      'http.url': request.url(),
      'resource.type': request.resourceType(),
    },
  });
  requestSpans.set(key, span);
});

page.on('response', (response: Response) => {
  span.setAttributes({ 'http.status_code': response.status() });
  span.setStatus({ code: response.status() >= 400 ? ERROR : OK });
  span.end();
});

Core Web Vitals Measurement

File: tests/e2e/fixtures/performance.ts

Measures key performance metrics:

export interface CoreWebVitals {
  lcp: number | null;  // Largest Contentful Paint
  fcp: number | null;  // First Contentful Paint
  cls: number | null;  // Cumulative Layout Shift
  ttfb: number | null; // Time to First Byte
}

export const DEFAULT_THRESHOLDS: PerformanceThresholds = {
  lcp: 2500,   // 2.5s for "good"
  fcp: 1800,   // 1.8s for "good"
  cls: 0.1,    // 0.1 for "good"
  ttfb: 800,   // 800ms for "good"
};

HAR Recording

File: tests/e2e/fixtures/har-recording.ts

Records network traffic per test:

const context = await browser.newContext({
  recordHar: {
    path: harPath,
    mode: 'full',
    content: 'embed',
  },
});

Output: test-results/har/<test-file>-<test-name>.har

Global Setup/Teardown

File: tests/e2e/global-setup.ts

Initializes OTEL SDK and creates test run metadata:

const metadata: TestRunMetadata = {
  runId: uuidv4(),
  correlationId: uuidv4(),
  startTime: new Date().toISOString(),
  playwright: { version, projects },
  otel: { enabled, endpoint },
  environment: { nodeVersion, platform, ci },
};
fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));

Test Specifications

Created 4 comprehensive test spec files:

Spec FileTestsCoverage
dashboard.spec.ts14Hero, stats, cards, navigation, performance
metadata-viewer.spec.ts17Filters, search, dark mode, large JSON
timeline.spec.ts12Visualization, interactions, FPS
correction-interface.spec.ts14Forms, validation, export

Example Test (dashboard.spec.ts):

test('should meet Core Web Vitals thresholds', async ({ page }) => {
  await page.goto('/');
  await page.waitForLoadState('load');

  const metrics = await measurePagePerformance(page);
  console.log(formatMetrics(metrics));

  const violations = checkThresholds(metrics, DEFAULT_THRESHOLDS);
  if (metrics.lcp !== null) {
    expect(metrics.lcp).toBeLessThan(2500);
  }
});

Files Created

Configuration (3 files)

| File | Lines | Purpose | |——|——-|———| | package.json | 32 | Updated with Playwright + OTEL dependencies | | tsconfig.json | 26 | TypeScript configuration for E2E tests | | playwright.config.ts | 55 | Multi-browser, HAR, webServer configuration |

Test Fixtures (5 files)

| File | Lines | Purpose | |——|——-|———| | tests/e2e/fixtures/traffic-tracking.ts | 95 | X-Test-Traffic header injection | | tests/e2e/fixtures/har-recording.ts | 135 | HAR file recording per test | | tests/e2e/fixtures/otel-tracing.ts | 165 | OpenTelemetry spans for tests | | tests/e2e/fixtures/performance.ts | 195 | Core Web Vitals measurement | | tests/e2e/fixtures/index.ts | 35 | Merged fixture export |

Global Setup/Teardown (2 files)

| File | Lines | Purpose | |——|——-|———| | tests/e2e/global-setup.ts | 85 | OTEL SDK init, test metadata | | tests/e2e/global-teardown.ts | 70 | Flush spans, update metadata |

Test Specs (4 files)

| File | Tests | Purpose | |——|——-|———| | tests/e2e/dashboard.spec.ts | 14 | Main dashboard tests | | tests/e2e/metadata-viewer.spec.ts | 17 | Metadata viewer tests | | tests/e2e/timeline.spec.ts | 12 | Timeline visualization tests | | tests/e2e/correction-interface.spec.ts | 14 | Correction form tests |

Dependencies Installed

NPM Packages (199 total)

Core Testing:

  • @playwright/test ^1.40.0
  • typescript ^5.3.0
  • @types/node ^20.10.0

OpenTelemetry:

  • @opentelemetry/api ^1.7.0
  • @opentelemetry/sdk-node ^0.46.0
  • @opentelemetry/sdk-trace-node ^1.19.0
  • @opentelemetry/exporter-trace-otlp-http ^0.46.0
  • @opentelemetry/resources ^1.19.0
  • @opentelemetry/semantic-conventions ^1.19.0

Utilities:

  • uuid ^9.0.1
  • serve ^14.2.0

Playwright Browsers

BrowserVersionBuild
Chromium(cached)-
Firefox144.0.2v1497
WebKit26.0v2227

NPM Scripts

{
  "test:e2e": "playwright test",
  "test:e2e:ui": "playwright test --ui",
  "test:e2e:report": "playwright show-report",
  "test:e2e:debug": "playwright test --debug",
  "test:e2e:headed": "playwright test --headed",
  "test:e2e:trace": "playwright test --trace on",
  "serve": "serve _site -l 3000"
}

Output Directory Structure

test-results/
├── har/                    # HAR files per test
└── telemetry/
    └── test-run-metadata.json
playwright-report/          # HTML test report
results/
└── e2e-results.json        # JSON test results

Environment Variables

VariableDescription
OTEL_EXPORTER_OTLP_ENDPOINTOTLP collector endpoint
OTEL_DEBUGEnable OTEL debug logging
BASE_URLOverride base URL (default: http://localhost:3000)

Verification

# Install dependencies
npm install
# Output: added 199 packages in 7s

# Install Playwright browsers
npx playwright install
# Output: Firefox 144.0.2, WebKit 26.0 downloaded

# Run tests
npm run test:e2e

# View report
npm run test:e2e:report

Key Decisions and Trade-offs

Decision 1: Merged Fixtures vs Separate Test Files

Choice: Merged fixtures with selective imports available Rationale: Provides convenience while maintaining flexibility Alternative Considered: Separate test files per fixture Trade-off: Slightly larger test context for simpler usage

Decision 2: HAR Recording Per Test vs Per Suite

Choice: Per test recording Rationale: Easier debugging of specific test failures Alternative Considered: Single HAR per test suite Trade-off: More files, but better isolation

Decision 3: Default OTEL Disabled Unless Endpoint Set

Choice: Opt-in OTEL via environment variable Rationale: No overhead for local development Alternative Considered: Always enabled with console exporter Trade-off: Requires setup for OTEL benefits

Next Steps

Immediate

  1. Run npm run test:e2e to verify all tests pass
  2. Configure OTEL endpoint for trace collection

Short-term

  1. Add visual regression testing with Playwright snapshots
  2. Integrate with CI/CD pipeline (GitHub Actions)

Medium-term

  1. Add accessibility testing (axe-core integration)
  2. Create custom reporters for metrics aggregation

References

Code Files

  • playwright.config.ts - Main configuration
  • tests/e2e/fixtures/index.ts - Merged fixtures
  • tests/e2e/global-setup.ts - OTEL initialization

Documentation

Dashboard Pages Tested

  • _site/index.html - Main dashboard
  • _site/metadata_viewer.html - Metadata viewer
  • _site/timeline.html - Timeline visualization
  • _site/correction_interface.html - Correction interface