chore: use original test ids in html report (#30486)

Fixes https://github.com/microsoft/playwright/issues/30430
This commit is contained in:
Pavel Feldman 2024-04-23 14:28:27 -07:00 committed by GitHub
parent 67c430435a
commit 4514b7e3ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 45 additions and 14 deletions

View File

@ -78,11 +78,21 @@ const TestCaseViewLoader: React.FC<{
const testId = searchParams.get('testId');
const anchor = (searchParams.get('anchor') || '') as 'video' | 'diff' | '';
const run = +(searchParams.get('run') || '0');
const testIdToFileIdMap = React.useMemo(() => {
const map = new Map<string, string>();
for (const file of report.json().files) {
for (const test of file.tests)
map.set(test.testId, file.fileId);
}
return map;
}, [report]);
React.useEffect(() => {
(async () => {
if (!testId || testId === test?.testId)
return;
const fileId = testId.split('-')[0];
const fileId = testIdToFileIdMap.get(testId);
if (!fileId)
return;
const file = await report.entry(`${fileId}.json`) as TestFile;
@ -93,7 +103,7 @@ const TestCaseViewLoader: React.FC<{
}
}
})();
}, [test, report, testId]);
}, [test, report, testId, testIdToFileIdMap]);
return <TestCaseView projectNames={report.json().projectNames} test={test} anchor={anchor} run={run}></TestCaseView>;
};

View File

@ -246,7 +246,7 @@ class HtmlBuilder {
}
const { testFile, testFileSummary } = fileEntry;
const testEntries: TestEntry[] = [];
this._processSuite(fileSuite, fileId, projectSuite.project()!.name, [], testEntries);
this._processSuite(fileSuite, projectSuite.project()!.name, [], testEntries);
for (const test of testEntries) {
testFile.tests.push(test.testCase);
testFileSummary.tests.push(test.testCaseSummary);
@ -346,30 +346,25 @@ class HtmlBuilder {
this._dataZipFile.addBuffer(Buffer.from(JSON.stringify(data)), fileName);
}
private _processSuite(suite: Suite, fileId: string, projectName: string, path: string[], outTests: TestEntry[]) {
private _processSuite(suite: Suite, projectName: string, path: string[], outTests: TestEntry[]) {
const newPath = [...path, suite.title];
suite.entries().forEach(e => {
if (e.type === 'test')
outTests.push(this._createTestEntry(fileId, e, projectName, newPath));
outTests.push(this._createTestEntry(e, projectName, newPath));
else
this._processSuite(e, fileId, projectName, newPath, outTests);
this._processSuite(e, projectName, newPath, outTests);
});
}
private _createTestEntry(fileId: string, test: TestCasePublic, projectName: string, path: string[]): TestEntry {
private _createTestEntry(test: TestCasePublic, projectName: string, path: string[]): TestEntry {
const duration = test.results.reduce((a, r) => a + r.duration, 0);
const location = this._relativeLocation(test.location)!;
path = path.slice(1);
const [file, ...titles] = test.titlePath();
const testIdExpression = `[project=${this._projectId(test.parent)}]${toPosixPath(file)}\x1e${titles.join('\x1e')} (repeat:${test.repeatEachIndex})`;
const testId = fileId + '-' + calculateSha1(testIdExpression).slice(0, 20);
const results = test.results.map(r => this._createTestResult(test, r));
return {
testCase: {
testId,
testId: test.id,
title: test.title,
projectName,
location,
@ -383,7 +378,7 @@ class HtmlBuilder {
ok: test.outcome() === 'expected' || test.outcome() === 'flaky',
},
testCaseSummary: {
testId,
testId: test.id,
title: test.title,
projectName,
location,

View File

@ -86,6 +86,32 @@ for (const useIntermediateMergeReport of [false, true] as const) {
await expect(page.locator('.metadata-view')).not.toBeVisible();
});
test('should allow navigating to testId=test.id', async ({ runInlineTest, page, showReport }) => {
const result = await runInlineTest({
'a.test.js': `
import { test, expect } from '@playwright/test';
test('passes', async ({ page }) => {
console.log('TESTID=' + test.info().testId);
await expect(1).toBe(1);
});
`,
}, { reporter: 'dot,html' }, { PW_TEST_HTML_REPORT_OPEN: 'never' });
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(1);
await showReport();
await page.click('text=passes');
await page.locator('text=stdout').click();
await expect(page.locator('.attachment-body')).toHaveText(/TESTID=.*/);
const idString = await page.locator('.attachment-body').textContent();
const testId = idString.match(/TESTID=(.*)/)[1];
expect(page.url()).toContain('testId=' + testId);
// Expect test to be opened.
await page.reload();
await page.locator('text=stdout').click();
await expect(page.locator('.attachment-body')).toHaveText(/TESTID=.*/);
});
test('should not throw when PW_TEST_HTML_REPORT_OPEN value is invalid', async ({ runInlineTest, page, showReport }, testInfo) => {
const invalidOption = 'invalid-option';