import { URL } from 'node:url'; import { Reporter, FullConfig, Suite, TestCase, TestResult, TestStep, TestError, FullResult } from '@playwright/test/reporter'; import { Timeseries } from 'prometheus-remote-write'; import * as _playwright_test from '@playwright/test'; import { TestType, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions } from '@playwright/test'; declare abstract class Metric = Record> { /** **NOTE:** Must be initialized in constructor */ protected series: Timeseries; constructor(metadata: Record<"name", MetricName> & Labels); /** Internal method */ _getSeries(): Timeseries; /** Append extra labels */ labels(labels: Record): this; /** Send metrics to prometheus */ collect(): this; /** revert metric to initial state */ abstract reset(): this; [Symbol.dispose](): void; } /** * Counters go up, and reset when the process restarts. * * Initial value is 0 */ declare class Counter = Record> extends Metric { protected readonly metadata: Record<"name", MetricName> & Labels; protected initialValue: number; protected counter: number; constructor(metadata: Record<"name", MetricName> & Labels, initialValue?: number); /** Increase counter by selected value */ inc(value?: number): this; reset(): this; } declare class Gauge = Record> extends Counter { /** Decrement gauge value */ dec(value?: number): this; /** set gauge value */ set(value?: number): this; /** set gauge to zero */ zero(): this; reset(): this; } interface PromRWFixture { /** * Creates a Counter metric with the specified name and optional labels. * @param name - The name of the counter metric. * @param labels - Optional key-value pairs for metric labeling. * @returns A Counter instance that can be used to track incremental values. * @example * ```ts * test('track API request count', async ({ useCounterMetric, page }) => { * // Create a counter metric for API requests * const apiRequestCounter = useCounterMetric( * 'api_requests', { * endpoint: '/users' // endpoint is a custom label * }); * * // Increment counter when API is called * await page.goto('/users'); * apiRequestCounter.inc(); * * // Increment by specific amount * await page.click('.load-more-users'); * apiRequestCounter.inc(5); * * // Add additional labels and collect metrics * apiRequestCounter.labels({ status: 'success' }).collect(); * }); * ``` */ useCounterMetric: = Record>(name: Name, labels?: Labels) => Counter; /** * Creates a Gauge metric with the specified name and optional labels. * @param name - The name of the gauge metric. * @param labels - Optional key-value pairs for metric labeling. * @returns A Gauge instance that can be used to track values that can go up and down. * @example * ```ts * test('track active users', async ({ useGaugeMetric, page }) => { * // Create a gauge metric for active users * const activeUsersGauge = useGaugeMetric('active_users', { region: 'us-east' }); * * // Set gauge to initial value * activeUsersGauge.set(10); * * // Increment gauge when users log in * await page.goto('/login'); * await page.fill('#username', 'testuser'); * await page.fill('#password', 'password'); * await page.click('#login-button'); * activeUsersGauge.inc(); * * // Decrement gauge when users log out * await page.click('#logout-button'); * activeUsersGauge.dec(); * * // Reset to zero and collect metrics * activeUsersGauge.zero().collect(); * }); * ``` */ useGaugeMetric: (name: string, labels?: Record) => Gauge; } declare const test: TestType; declare const expect: _playwright_test.Expect<{}>; type PrometheusOptions = { /** * URL of the Prometheus remote write implementation's endpoint. * @throws "TypeError" if not defined in options */ serverUrl: string | URL; /** * Additional headers to include in the HTTP requests. * @example * { header1: 'key1' } */ headers?: Record; auth?: { /** Basic auth. Username */ username?: string; /** Basic auth. Password */ password?: string; }; /** @default 'pw_' */ prefix?: string; /** * Additional labels to apply to each timeseries. * @example * { instance: "hostname" } */ labels?: Record; /** * env variables to send. Default is empty object due to security reasons. * @default `{}` empty object * @see {@link https://nodejs.org/docs/latest/api/process.html#processenv node.js - process.env} * @example * // setup all env variables, unsafe ❌ * export default defineConfig({ * // ... * reporter: [ * ['playwright-prometheus-remote-write-reporter', { * serverUrl: 'http://localhost:9090/api/v1/write', * env: process.env // setup all env variables. Use it own risk * }] * ], * // ... * }); * @example * // collect system info only - good ✅ * import os from 'node:os' * export default defineConfig({ * // ... * reporter: [ * ['playwright-prometheus-remote-write-reporter', { * serverUrl: 'http://localhost:9090/api/v1/write', * env: { * user: os.userInfo().username, * platform: os.platform(), * type: os.type(), * version: os.version(), * productVersion: process.env.MY_PRODUCT_VERSION, // e.g. 2.4.8 * }, * }] * ], * // ... * }); */ env?: Record; }; declare class PrometheusReporter implements Reporter { private readonly options; private readonly prefix; private readonly env; private pw_projects; private readonly test_step_total_count; private readonly test_step_total_duration; private readonly test_annotation_count; private test_step_duration; private test_step_error_count; private test_step_total_error; private test_step; private readonly pw_stderr; private readonly pw_stdout; private readonly pw_config; private test_attachment_count; private test_attachment_size; private tests_total_attachment_size; private errors_count; private test_errors; private tests_total_attachment; private test_duration; private test; private test_retry_count; private total_duration; private readonly test_total_count; private readonly skipped_tests_count; private readonly timed_out_tests_count; private readonly passed_count; private readonly failed_count; private readonly node_memory_heap_total; private readonly node_memory_rss; private readonly node_memory_heap_used; private readonly node_memory_external; private readonly node_memory_free; private readonly node_memory_array_buffers; private readonly node_cpu_user; private readonly node_cpu_system; private readonly node_argv; private readonly node_os; private readonly node_env; private readonly node_versions; /** timeseries from user tests */ private readonly timeseries; constructor(options?: PrometheusOptions); private memoryDelta; private cpuDelta; private updateNodejsStats; private sendNodejsStats; private send; onBegin(config: FullConfig, suite: Suite): void; private updateResults; onStepEnd(test: TestCase, result: TestResult, step: TestStep): Promise; onTestEnd(test: TestCase, result: TestResult): Promise; onError(error: TestError): void; private mapTimeseries; onStdOut(chunk: string | Buffer, test: void | TestCase, result: void | TestResult): Promise; onStdErr(chunk: string | Buffer, test: void | TestCase): void; onEnd(result: FullResult): void; onStepBegin(test: TestCase, result: TestResult, step: TestStep): void; onTestBegin(test: TestCase, result: TestResult): void; onExit(): Promise; private location; printsToStdio(): boolean; } export { Counter, Gauge, type PromRWFixture, type PrometheusOptions, PrometheusReporter as default, expect, test };