Fix Playwright coverage collection and merge
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import type { TestInfo } from '@playwright/test';
|
||||
import { expect, test as base, Page } from '@bgotink/playwright-coverage';
|
||||
|
||||
const coverageDir = path.join(process.cwd(), 'coverage-reports', 'e2e', '.nyc_output');
|
||||
|
||||
async function writeCoverageFile(page: Page, testInfo: TestInfo) {
|
||||
try {
|
||||
const coverage = await page.evaluate(() => (globalThis as any).__coverage__ ?? null);
|
||||
if (!coverage || Object.keys(coverage).length === 0) return;
|
||||
|
||||
await fs.mkdir(coverageDir, { recursive: true });
|
||||
|
||||
const titleParts =
|
||||
typeof testInfo.titlePath === 'function'
|
||||
? testInfo.titlePath()
|
||||
: Array.isArray((testInfo as any).titlePath)
|
||||
? (testInfo as any).titlePath
|
||||
: [testInfo.title];
|
||||
const safeTitle = titleParts
|
||||
.filter(Boolean)
|
||||
.map((part) => part.replace(/[^a-zA-Z0-9-_]+/g, '_'))
|
||||
.join('--')
|
||||
.slice(0, 200);
|
||||
const worker = typeof testInfo.workerIndex === 'number' ? `w${testInfo.workerIndex}` : 'w';
|
||||
const filename = path.join(coverageDir, `coverage-${worker}-${Date.now()}-${safeTitle || 'test'}.json`);
|
||||
|
||||
await fs.writeFile(filename, JSON.stringify(coverage));
|
||||
console.log('Wrote coverage file:', path.relative(process.cwd(), filename));
|
||||
} catch (error) {
|
||||
const msg = error instanceof Error ? error.message : String(error);
|
||||
console.warn('Failed to collect coverage from page:', msg);
|
||||
}
|
||||
}
|
||||
|
||||
export const test = base.extend({
|
||||
page: async ({ page }, use, testInfo) => {
|
||||
await use(page);
|
||||
await writeCoverageFile(page, testInfo);
|
||||
},
|
||||
});
|
||||
|
||||
export { expect };
|
||||
export type { Page };
|
||||
@@ -1,5 +1,4 @@
|
||||
import { expect, test } from '@bgotink/playwright-coverage';
|
||||
import type { Page } from '@playwright/test';
|
||||
import { expect, test, Page } from './fixtures';
|
||||
|
||||
import {
|
||||
areaName,
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
// e2e/playwright-collect-coverage.spec.ts
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { test } from '@playwright/test';
|
||||
|
||||
const EVAL_TIMEOUT_MS = 5000;
|
||||
const WRITE_TIMEOUT_MS = 15000;
|
||||
|
||||
function withTimeout<T>(p: Promise<T>, ms: number, onTimeout?: () => void) {
|
||||
let timer: NodeJS.Timeout | undefined;
|
||||
const timeout = new Promise<T>((res) => {
|
||||
timer = setTimeout(() => {
|
||||
onTimeout?.();
|
||||
// @ts-ignore resolve null on timeout
|
||||
res(null);
|
||||
}, ms);
|
||||
});
|
||||
return Promise.race([p, timeout]).then((r) => {
|
||||
if (timer) clearTimeout(timer);
|
||||
return r;
|
||||
});
|
||||
}
|
||||
|
||||
test.afterEach(async ({ page }, testInfo) => {
|
||||
try {
|
||||
console.log(`Collecting coverage for: ${testInfo.title}`);
|
||||
|
||||
// Evaluate coverage in page, but don't hang forever
|
||||
const evalPromise = page.evaluate(() => (globalThis as any).__coverage__ || null);
|
||||
const coverage = await withTimeout(evalPromise, EVAL_TIMEOUT_MS, () => {
|
||||
console.warn('page.evaluate for coverage timed out');
|
||||
});
|
||||
|
||||
if (!coverage || Object.keys(coverage).length === 0) {
|
||||
console.log('No coverage collected (empty or timed out).');
|
||||
return;
|
||||
}
|
||||
|
||||
const dir = path.join(process.cwd(), '.nyc_output');
|
||||
await fs.promises.mkdir(dir, { recursive: true });
|
||||
|
||||
const safeTitle = (testInfo.title || 'test').replace(/[^a-zA-Z0-9-_]/g, '_').slice(0, 120);
|
||||
const worker = typeof testInfo.workerIndex === 'number' ? testInfo.workerIndex : process.pid;
|
||||
const filename = path.join(dir, `coverage-e2e-w${worker}-${Date.now()}-${safeTitle}.json`);
|
||||
|
||||
// write asynchronously, bounded by timeout
|
||||
const writePromise = fs.promises.writeFile(filename, JSON.stringify(coverage));
|
||||
await withTimeout(writePromise, WRITE_TIMEOUT_MS, () => {
|
||||
console.warn('Writing coverage file timed out');
|
||||
});
|
||||
|
||||
console.log('Wrote coverage:', filename);
|
||||
} catch (error: unknown) {
|
||||
const msg = error instanceof Error ? error.message : String(error);
|
||||
console.warn('Failed to collect coverage from page:', msg);
|
||||
}
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect, test } from '@bgotink/playwright-coverage';
|
||||
import { expect, test } from './fixtures';
|
||||
import {
|
||||
ensureProductsExist,
|
||||
areaName,
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
// e2e/test-helpers.ts
|
||||
import { expect, Page } from '@playwright/test';
|
||||
import { expect } from './fixtures';
|
||||
import type { Page } from '@playwright/test';
|
||||
|
||||
/* -----------------------
|
||||
Shared constants
|
||||
|
||||
Reference in New Issue
Block a user