Skip to Content
DocumentationAdaptersOverview

@lytics/playwright-adapters

Storage adapters for the Playwright reporter framework.

Installation

npm install @lytics/playwright-adapters

Available Adapters

Quick Start

Playwright reporters must be specified as file paths. Create a reporter file:

Single Adapter

// reporter.ts import { CoreReporter } from '@lytics/playwright-reporter'; import { FilesystemAdapter } from '@lytics/playwright-adapters/filesystem'; class CustomReporter extends CoreReporter { constructor() { super({ adapters: [ new FilesystemAdapter({ outputDir: './test-results' }) ] }); } } export default CustomReporter;
// playwright.config.ts export default { reporter: [['list'], ['./reporter.ts']], };

Multiple Adapters

All adapters run in parallel:

// reporter.ts import { CoreReporter } from '@lytics/playwright-reporter'; import { FilesystemAdapter } from '@lytics/playwright-adapters/filesystem'; import { SlackAdapter } from '@lytics/playwright-adapters/slack'; import { FirestoreAdapter } from '@lytics/playwright-adapters/firestore'; class CustomReporter extends CoreReporter { constructor() { super({ adapters: [ // Always write to filesystem for debugging new FilesystemAdapter({ outputDir: './test-results' }), // Send Slack notifications in production new SlackAdapter({ webhookUrl: process.env.SLACK_WEBHOOK_URL!, environment: 'Production', productionOnly: true, }), // Store in Firestore for dashboards new FirestoreAdapter({ projectId: 'my-gcp-project', collections: { testRuns: 'e2e_test_runs', testCases: 'e2e_test_cases', latestTestCases: 'e2e_latest_test_cases', }, }), ] }); } } export default CustomReporter;

Import Paths

Each adapter has its own import path:

// Filesystem adapter import { FilesystemAdapter } from '@lytics/playwright-adapters/filesystem'; // Slack adapter import { SlackAdapter } from '@lytics/playwright-adapters/slack'; // Firestore adapter import { FirestoreAdapter } from '@lytics/playwright-adapters/firestore';

Creating Custom Adapters

Implement the ResultAdapter interface from @lytics/playwright-reporter:

import type { ResultAdapter, CoreTestResult, CoreTestRun } from '@lytics/playwright-reporter'; export class MyCustomAdapter implements ResultAdapter { async initialize(): Promise<void> { // Setup: connect to database, create directories, etc. } async writeTestResult(result: CoreTestResult): Promise<void> { // Write individual test result } async writeTestRun(run: CoreTestRun): Promise<void> { // Write test run summary } async close(): Promise<void> { // Cleanup: close connections, flush buffers, etc. } }

Best Practice: Handle errors gracefully in adapters. A failing adapter shouldn’t crash the test run or prevent other adapters from working.

Example: Console Adapter

A simple adapter that logs to console:

import type { ResultAdapter, CoreTestResult, CoreTestRun } from '@lytics/playwright-reporter'; export class ConsoleAdapter implements ResultAdapter { async initialize(): Promise<void> { console.log('πŸ“‹ Test run starting...'); } async writeTestResult(result: CoreTestResult): Promise<void> { const icon = result.status === 'passed' ? 'βœ…' : '❌'; console.log(`${icon} ${result.testCaseId}: ${result.status} (${result.durationMs}ms)`); } async writeTestRun(run: CoreTestRun): Promise<void> { console.log('\nπŸ“Š Test Run Summary'); console.log(` Total: ${run.totalTests}`); console.log(` Passed: ${run.passed}`); console.log(` Failed: ${run.failed}`); console.log(` Pass Rate: ${(run.passRate * 100).toFixed(1)}%`); console.log(` Duration: ${run.durationMs}ms`); if (run.flakyTests > 0) { console.log(` Flaky: ${run.flakyTests}`); } } async close(): Promise<void> { console.log('πŸ“‹ Test run complete.'); } }

Adapter Lifecycle

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 1. initialize() β”‚ β”‚ Called once before any tests run β”‚ β”‚ Use for: connections, directory creation, validation β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 2. writeTestResult(result) - called N times β”‚ β”‚ Called after each test completes β”‚ β”‚ Use for: writing individual test results β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 3. writeTestRun(run) β”‚ β”‚ Called once after all tests complete β”‚ β”‚ Use for: writing summary, sending notifications β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ↓ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 4. close() β”‚ β”‚ Called after writeTestRun β”‚ β”‚ Use for: cleanup, closing connections, flushing buffers β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Error Handling

Adapters should handle errors gracefully:

async writeTestResult(result: CoreTestResult): Promise<void> { try { await this.doWrite(result); } catch (error) { // Log but don't throw - allow other adapters to continue console.error(`[MyAdapter] Failed to write result: ${error}`); } }

If an adapter throws during initialize(), the reporter will log the error but continue with other adapters.

Last updated on