npm package: @lytics/playwright-adapters
Description: Storage adapters for Playwright reporter (filesystem, Slack, Firestore)
Latest version: 1.0.1

# @lytics/playwright-adapters

Storage adapters for the Playwright reporter framework (filesystem, Slack, Firestore).

## Installation

```bash
npm install @lytics/playwright-adapters
# or
pnpm add @lytics/playwright-adapters
# or
yarn add @lytics/playwright-adapters
```

## Adapters

### FilesystemAdapter

Writes test results to JSON files on the local filesystem. Useful for local development, debugging, and CI artifact collection.

**Features:**
- Creates organized directory structure (`test-results/` and `test-runs/`)
- Pretty-printed JSON by default (configurable)
- Automatic directory creation
- Writes `latest.json` for easy access to most recent run
- Non-blocking error handling (allows other adapters to continue)

**Example:**

```typescript
import { CoreReporter } from '@lytics/playwright-reporter';
import { FilesystemAdapter } from '@lytics/playwright-adapters/filesystem';

export default {
  reporter: [
    ['list'],
    [
      new CoreReporter({
        adapters: [
          new FilesystemAdapter({
            outputDir: './test-results',
            pretty: true, // default: true
          }),
        ],
      }),
    ],
  ],
};
```

**Configuration:**

```typescript
interface FilesystemAdapterConfig {
  /** Directory to write test results to (required) */
  outputDir: string;
  /** Whether to pretty-print JSON (default: true) */
  pretty?: boolean;
}
```

**Output Structure:**

```
test-results/
├── test-results/
│   ├── TEST-001-2024-01-01T00-00-00.000Z.json
│   ├── TEST-002-2024-01-01T00-01-00.000Z.json
│   └── ...
└── test-runs/
    ├── test-run-run-123-2024-01-01T00-00-00.000Z.json
    ├── test-run-run-456-2024-01-01T01-00-00.000Z.json
    └── latest.json
```

### SlackAdapter

Sends test results to Slack channels using `@lytics/playwright-slack`. Automatically formats test summaries with pass/fail statistics, failed test details, and flaky test tracking.

**Features:**
- Rich Slack formatting via `@lytics/playwright-slack`
- Production-only mode (configurable)
- Skip pull request notifications (configurable)
- Automatic flaky test detection
- Failed test details with error messages
- Non-blocking error handling

**Example:**

```typescript
import { CoreReporter } from '@lytics/playwright-reporter';
import { FilesystemAdapter } from '@lytics/playwright-adapters/filesystem';
import { SlackAdapter } from '@lytics/playwright-adapters/slack';

export default {
  reporter: [
    ['list'],
    [
      new CoreReporter({
        adapters: [
          new FilesystemAdapter({ outputDir: './test-results' }),
          new SlackAdapter({
            webhookUrl: process.env.SLACK_WEBHOOK_URL,
            environment: 'Production',
            productionOnly: true, // default: true
            skipPullRequests: true, // default: true
            dashboardUrl: 'https://dashboard.example.com',
            ciJobUrl: process.env.CI_JOB_URL,
            artifactBaseUrl: process.env.ARTIFACT_BASE_URL,
            triggerType: process.env.TRIGGER_TYPE,
          }),
        ],
      }),
    ],
  ],
};
```

**Configuration:**

```typescript
interface SlackAdapterConfig {
  /** Slack webhook URL (can also be set via SLACK_WEBHOOK_URL env var) */
  webhookUrl?: string;
  /** Environment label (defaults to TEST_ENV or 'Production') */
  environment?: string;
  /** Only send notifications in production (default: true) */
  productionOnly?: boolean;
  /** Skip notifications for pull requests (default: true) */
  skipPullRequests?: boolean;
  /** Dashboard URL for test reports */
  dashboardUrl?: string;
  /** CI job URL (can also be set via CI_JOB_URL env var) */
  ciJobUrl?: string;
  /** Artifact base URL (can also be set via ARTIFACT_BASE_URL env var) */
  artifactBaseUrl?: string;
  /** Trigger type (can also be set via TRIGGER_TYPE env var) */
  triggerType?: string;
}
```

**Environment Variables:**

The adapter automatically reads from environment variables if not provided in config:
- `SLACK_WEBHOOK_URL` - Slack webhook URL (required)
- `TEST_ENV` - Environment name (e.g., 'Production', 'Staging')
- `TRIGGER_TYPE` - What triggered the test run (e.g., 'schedule', 'pull_request')
- `CI_JOB_URL` - URL to CI job for action links
- `ARTIFACT_BASE_URL` - Base URL for test artifacts

**Note:** This adapter requires `@lytics/playwright-slack` and `@lytics/slack-client` to be installed as dependencies.

### FirestoreAdapter

Writes test results to Google Cloud Firestore. Supports automatic retry with exponential backoff for transient failures.

**Features:**
- Writes to three configurable Firestore collections (you define the collection names)
- Automatic retry with exponential backoff for transient failures
- GCP authentication via Application Default Credentials (ADC) or Service Account JSON
- Optional skip conditions (e.g., skip PR runs)
- Non-blocking error handling (allows other adapters to continue)
- Schema-agnostic (you configure your own collection names and structure)

**Example:**

```typescript
import { CoreReporter } from '@lytics/playwright-reporter';
import { FirestoreAdapter } from '@lytics/playwright-adapters/firestore';

export default {
  reporter: [
    ['list'],
    [
      new CoreReporter({
        adapters: [
          new FirestoreAdapter({
            projectId: 'my-gcp-project',
            credentials: process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON,
            // Configure your own collection names to match your Firestore schema
            collections: {
              testRuns: 'your_test_runs_collection',
              testCases: 'your_test_cases_collection',
              latestTestCases: 'your_latest_test_cases_collection',
            },
            skipConditions: {
              skipPullRequests: true,
            },
          }),
        ],
      }),
    ],
  ],
};
```

**Configuration:**

```typescript
interface FirestoreAdapterConfig {
  /** GCP project ID (required) */
  projectId: string;
  /** Service account credentials (JSON string or object). If not provided, uses Application Default Credentials */
  credentials?: string | Record<string, unknown>;
  /** Collection names for different data types (required - configure your own schema) */
  collections: {
    /** Collection for test run summaries */
    testRuns: string;
    /** Collection for individual test executions */
    testCases: string;
    /** Collection for latest test case status */
    latestTestCases: string;
  };
  /** Optional conditions to skip writes */
  skipConditions?: {
    /** Skip writes for pull requests (default: false) */
    skipPullRequests?: boolean;
  };
  /** Retry configuration */
  retry?: {
    /** Maximum number of retries (default: 3) */
    maxRetries?: number;
    /** Initial delay in milliseconds (default: 1000) */
    initialDelayMs?: number;
    /** Maximum delay in milliseconds (default: 10000) */
    maxDelayMs?: number;
  };
}
```

**Authentication:**

The FirestoreAdapter supports two authentication methods:

1. **Application Default Credentials (ADC)** - Recommended: When `credentials` is not provided, the adapter uses Application Default Credentials.

```bash
# Set the GOOGLE_APPLICATION_CREDENTIALS environment variable
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account-key.json

# Or use gcloud CLI to authenticate
gcloud auth application-default login
```

2. **Service Account JSON**: Provide service account credentials directly as a JSON string or object.

```typescript
// From environment variable (JSON string)
new FirestoreAdapter({
  projectId: 'my-gcp-project',
  credentials: process.env.GOOGLE_APPLICATION_CREDENTIALS_JSON,
});
```

**Retry Logic:**

The adapter automatically retries failed operations with exponential backoff. Retries are only attempted for transient errors (network issues, rate limits, etc.). Non-retryable errors (authentication, invalid data) fail immediately.

**Environment Variables:**

- `TRIGGER_TYPE`: Used by `skipPullRequests` condition. Set to `'pull_request'` to skip writes.

**Note:** This adapter requires `@google-cloud/firestore` to be installed as a dependency.

## Creating Custom Adapters

Adapters implement the `ResultAdapter` interface:

```typescript
import type { ResultAdapter, CoreTestResult, CoreTestRun } from '@lytics/playwright-reporter';

export class MyCustomAdapter implements ResultAdapter {
  async initialize(): Promise<void> {
    // Setup connection, create resources, 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 resources, close connections, etc.
  }
}
```

## License

MIT