diff --git a/docs/changelog.md b/docs/changelog.md index 451ee01..742af29 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,7 +2,13 @@ All notable changes to this project will be documented in this file. -## [1.1.38] - Current +## [1.1.39] - Current + +### Added + +- **E2E coverage collection auto-fixture**: New `_coverageCollector` automatic fixture collects Istanbul coverage (`window.__coverage__`) from the browser after each test and writes per-test JSON files to `/coverage/`. Enabled via `E2E_COLLECT_COVERAGE=1`. Zero overhead when disabled — no `page.evaluate` call or fs operations. Designed for use with instrumented dynamic plugin builds (nyc instrument). + +## [1.1.38] ### Added diff --git a/package.json b/package.json index f5d563b..0fccf5f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@red-hat-developer-hub/e2e-test-utils", - "version": "1.1.38", + "version": "1.1.39", "description": "Test utilities for RHDH E2E tests", "license": "Apache-2.0", "repository": { diff --git a/src/playwright/fixtures/test.ts b/src/playwright/fixtures/test.ts index 4456227..9bbf362 100644 --- a/src/playwright/fixtures/test.ts +++ b/src/playwright/fixtures/test.ts @@ -4,6 +4,7 @@ import { LoginHelper, UIhelper } from "../helpers/index.js"; import { runOnce } from "../run-once.js"; import { $ } from "../../utils/bash.js"; import { WorkspacePaths } from "../../utils/workspace-paths.js"; +import fs from "node:fs"; import path from "path"; type RHDHDeploymentTestFixtures = { @@ -11,6 +12,8 @@ type RHDHDeploymentTestFixtures = { uiHelper: UIhelper; loginHelper: LoginHelper; autoAnnotations: void; + // eslint-disable-next-line @typescript-eslint/naming-convention + _coverageCollector: void; }; type RHDHDeploymentWorkerFixtures = { @@ -77,6 +80,34 @@ const baseTest = base.extend< }, { auto: true, scope: "test" }, ], + // eslint-disable-next-line @typescript-eslint/naming-convention + _coverageCollector: [ + async ({ page }, use, testInfo) => { + await use(); + if (process.env.E2E_COLLECT_COVERAGE !== "1") return; + try { + const coverage = await page.evaluate( + () => + ( + globalThis as unknown as { + // eslint-disable-next-line @typescript-eslint/naming-convention + __coverage__?: Record; + } + ).__coverage__, + ); + if (!coverage) return; + const dir = path.join(testInfo.project.outputDir, "coverage"); + fs.mkdirSync(dir, { recursive: true }); + fs.writeFileSync( + path.join(dir, `${testInfo.testId}-${Date.now()}.json`), + JSON.stringify(coverage), + ); + } catch { + // Best-effort: page may have crashed or been closed + } + }, + { auto: true, scope: "test" }, + ], }); export const test = Object.assign(baseTest, {