Skip to content

feat: add auto-fixture for Istanbul E2E coverage collection#95

Merged
subhashkhileri merged 5 commits into
redhat-developer:mainfrom
gustavolira:feat/coverage-auto-fixture
Jun 4, 2026
Merged

feat: add auto-fixture for Istanbul E2E coverage collection#95
subhashkhileri merged 5 commits into
redhat-developer:mainfrom
gustavolira:feat/coverage-auto-fixture

Conversation

@gustavolira

Copy link
Copy Markdown
Member

Summary

  • Adds a _coverageCollector auto-fixture to the shared test object that automatically collects window.__coverage__ from the browser after each test
  • Guarded by E2E_COLLECT_COVERAGE=1 — zero overhead when disabled (no page.evaluate, no fs operations)
  • Writes Istanbul coverage JSON files to coverage/istanbul/ (configurable via COVERAGE_OUTPUT_DIR)

Why

The rhdh-plugin-export-overlays repo builds Istanbul-instrumented dynamic plugins and runs E2E tests against them. The instrumented plugins populate window.__coverage__ in the browser, but nothing collects it today.

Since all 18 workspace test files import test from @red-hat-developer-hub/e2e-test-utils/test, adding an auto-fixture here gives every test automatic coverage collection without modifying any test file.

How it works

1. Instrumented plugin loaded in browser → window.__coverage__ populated
2. Test runs and exercises plugin UI
3. _coverageCollector auto-fixture teardown fires (after test, before page closes)
4. page.evaluate() reads __coverage__ from browser
5. JSON written to coverage/istanbul/<testId>-<timestamp>.json
6. Overlay repo's coverage-reporter merges all JSONs → lcov.info
7. upload-coverage.sh sends lcov to Codecov with --slug --sha --flag

Design decisions

  • auto: true — runs for every test without test file changes
  • scope: "test" — collects per-test, not per-worker
  • await use() first — teardown runs AFTER the test but BEFORE page closes (Playwright tears down in reverse dependency order)
  • try/catch with empty catch — best-effort; if the page crashed or plugin wasn't instrumented, silently skip
  • _ prefix — Playwright convention for internal auto-fixtures
  • No new dependencies — uses only node:fs and existing path import

Related PRs

Test plan

  • yarn build succeeds
  • yarn typecheck passes
  • With E2E_COLLECT_COVERAGE=1 and an instrumented plugin: JSON files appear in coverage/istanbul/
  • Without E2E_COLLECT_COVERAGE: no JSON files, no performance impact
  • When page crashes mid-test: no error thrown, test result unaffected

🤖 Generated with Claude Code

@subhashkhileri subhashkhileri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review:

Comment thread src/playwright/fixtures/test.ts
Comment thread src/playwright/fixtures/test.ts Outdated
@subhashkhileri

Copy link
Copy Markdown
Member

@gustavolira


Hey, here's what needs to change in rhdh-e2e-test-utils to support the __coverage tag swap for PR checks.

Everything is in src/utils/plugin-metadata.ts — three small changes:

1. Add backstage.role to the types (so we know which plugins are frontend)

PackageCRD interface (line 19) needs backstage.role:

interface PackageCRD {
  spec?: {
    packageName?: string;
    dynamicArtifact?: string;
    backstage?: {
      role?: string;
    };
    appConfigExamples?: Array<{ ... }>;
  };
}

PluginMetadata interface (line 12) needs role:

export interface PluginMetadata {
  packagePath: string;
  pluginConfig: Record<string, unknown>;
  packageName: string;
  sourceFile: string;
  role?: string;
}

2. Parse the role in parseMetadataFile (line 212)

Just read it from the parsed YAML and include in the return:

const role = parsed?.spec?.backstage?.role;
// ... in the return:
return { packagePath, pluginConfig: pluginConfig || {}, packageName, sourceFile: filePath, role };

3. The actual swap — in resolvePluginPackages (line 472-479)

This is the existing PR branch that already only runs when GIT_PR_NUMBER is set:

if (prOciUrls) {
  const prUrl = prOciUrls.get(displayName);
  if (prUrl) {
    const usesCoverage =
      process.env.E2E_COLLECT_COVERAGE === "1" &&
      metadata.role === "frontend-plugin";
    const resolved = usesCoverage
      ? prUrl.replace(/(:[^!]+)/, "$1__coverage")
      : prUrl;
    console.log(`[PluginMetadata] PR: ${pkg}${resolved}`);
    return { ...plugin, package: resolved };
  }
}

That regex appends __coverage to the tag while keeping the !alias intact:
plugin:pr_1845__1.5.0!pluginplugin:pr_1845__1.5.0__coverage!plugin

That's it — only affects PR checks, only when E2E_COLLECT_COVERAGE=1, only for frontend plugins. Nightly, {{inherit}}, and local dev paths are untouched.


@gustavolira gustavolira force-pushed the feat/coverage-auto-fixture branch from fad896f to 7f4e86c Compare June 3, 2026 20:59
gustavolira added a commit to gustavolira/rhdh-e2e-test-utils that referenced this pull request Jun 3, 2026
Implements automatic image tag swap from 'pr_XXX__version' to
'pr_XXX__version__coverage' when E2E_COLLECT_COVERAGE=1 is set
and the plugin is a frontend-plugin.

Changes:
1. Add 'role' field to PluginMetadata and PackageCRD types
2. Parse spec.backstage.role in parseMetadataFile()
3. Swap to __coverage tag in resolvePluginPackages() when:
   - GIT_PR_NUMBER is set (PR mode)
   - E2E_COLLECT_COVERAGE=1
   - Plugin role is 'frontend-plugin'

The regex preserves OCI alias: plugin:tag!alias → plugin:tag__coverage!alias

Only affects PR checks. Nightly mode, {{inherit}}, and local dev
paths are unchanged. Backend plugins skip the swap (no browser coverage).

Implements: redhat-developer#95 (comment)
Comment thread package.json Outdated
Comment thread docs/changelog.md Outdated
Comment thread src/playwright/fixtures/test.ts Outdated
_coverageCollector: [
async ({ page }, use, testInfo) => {
await use();
if (process.env.E2E_COLLECT_COVERAGE !== "1") return;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly a consistency nit, but other boolean value environment variables in the codebase seem to prefer "true" rather than 1 (like here), though then there's also this check against either. I'm sure this isn't something that will be toggled a lot.

- Adds _coverageCollector automatic fixture to test object
- Collects window.__coverage__ from browser after each test
- Writes per-test JSON files to <outputDir>/coverage/
- Enabled via E2E_COLLECT_COVERAGE=1
- Zero overhead when disabled (no page.evaluate or fs operations)
- Designed for use with instrumented dynamic plugin builds

This enables automatic E2E coverage collection for all workspaces
in rhdh-plugin-export-overlays without modifying any test files.
Implements automatic image tag swap from 'pr_XXX__version' to
'pr_XXX__version__coverage' when E2E_COLLECT_COVERAGE=1 is set
and the plugin is a frontend-plugin.

Changes:
1. Add 'role' field to PluginMetadata and PackageCRD types
2. Parse spec.backstage.role in parseMetadataFile()
3. Swap to __coverage tag in resolvePluginPackages() when:
   - GIT_PR_NUMBER is set (PR mode)
   - E2E_COLLECT_COVERAGE=1
   - Plugin role is 'frontend-plugin'

The regex preserves OCI alias: plugin:tag!alias → plugin:tag__coverage!alias

Only affects PR checks. Nightly mode, {{inherit}}, and local dev
paths are unchanged. Backend plugins skip the swap (no browser coverage).

Implements: redhat-developer#95 (comment)
For consistency with other boolean env vars in the codebase (like
E2E_NIGHTLY_MODE, USE_NEW_FRONTEND_SYSTEM), change from checking
"1" to checking "true".

Updated in:
- src/playwright/fixtures/test.ts (_coverageCollector fixture)
- src/utils/plugin-metadata.ts (coverage image swap)
- docs/changelog.md (documentation)

Addresses: redhat-developer#95 (comment)
@gustavolira gustavolira force-pushed the feat/coverage-auto-fixture branch from b3a6710 to 65e599a Compare June 4, 2026 13:52
Main branch was updated to 1.1.45, so this PR needs to bump to 1.1.46.
Comment thread package.json Outdated
Comment thread docs/changelog.md Outdated
Co-authored-by: Subhash Khileri <subhashkhileri2@gmail.com>
@subhashkhileri subhashkhileri merged commit 4434981 into redhat-developer:main Jun 4, 2026
3 checks passed
gustavolira added a commit to gustavolira/rhdh-plugin-export-overlays that referenced this pull request Jun 4, 2026
Version 2.1.0 includes the automatic __coverage image swap logic
from PR redhat-developer/rhdh-e2e-test-utils#95 (merged 2026-06-04).

Changes:
- Auto-fixture _coverageCollector that collects window.__coverage__
- Automatic swap to __coverage images when E2E_COLLECT_COVERAGE=true
  and plugin role is frontend-plugin

This enables E2E coverage collection to work end-to-end.
gustavolira added a commit to gustavolira/rhdh-plugin-export-overlays that referenced this pull request Jun 4, 2026
Version 2.1.0 includes the automatic __coverage image swap logic
from PR redhat-developer/rhdh-e2e-test-utils#95 (merged 2026-06-04).

Changes:
- Auto-fixture _coverageCollector that collects window.__coverage__
- Automatic swap to __coverage images when E2E_COLLECT_COVERAGE=true
  and plugin role is frontend-plugin

This enables E2E coverage collection to work end-to-end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants