feat(merge): prepend bot name to global errors (#29055)

This way one can figure out where does the error come from.

An example merged report that exhibits the issue:
https://mspwblobreport.z1.web.core.windows.net/run-7563628632-1-2328b83af75801ab76bb06c214fee483cf5bc07c/index.html#?q=s%3Afailed%20s%3Aflaky
This commit is contained in:
Dmitry Gozman 2024-01-18 15:11:32 -08:00 committed by GitHub
parent c76f5294ce
commit b7d22b64e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 26 additions and 2 deletions

View File

@ -26,12 +26,14 @@ import { Multiplexer } from './multiplexer';
import { ZipFile, calculateSha1 } from 'playwright-core/lib/utils';
import { currentBlobReportVersion, type BlobReportMetadata } from './blob';
import { relativeFilePath } from '../util';
import type { TestError } from '../../types/testReporter';
type StatusCallback = (message: string) => void;
type ReportData = {
eventPatchers: JsonEventPatchers;
reportFile: string;
metadata: BlobReportMetadata;
};
export async function createMergedReport(config: FullConfigInternal, dir: string, reporterDescriptions: ReporterDescription[], rootDirOverride: string | undefined) {
@ -65,11 +67,13 @@ export async function createMergedReport(config: FullConfigInternal, dir: string
};
await dispatchEvents(eventData.prologue);
for (const { reportFile, eventPatchers } of eventData.reports) {
for (const { reportFile, eventPatchers, metadata } of eventData.reports) {
const reportJsonl = await fs.promises.readFile(reportFile);
const events = parseTestEvents(reportJsonl);
new JsonStringInternalizer(stringPool).traverse(events);
eventPatchers.patchers.push(new AttachmentPathPatcher(dir));
if (metadata.name)
eventPatchers.patchers.push(new GlobalErrorPatcher(metadata.name));
eventPatchers.patchEvents(events);
await dispatchEvents(events);
}
@ -213,6 +217,7 @@ async function mergeEvents(dir: string, shardReportFiles: string[], stringPool:
reports.push({
eventPatchers,
reportFile: localPath,
metadata,
});
}
@ -465,6 +470,24 @@ class PathSeparatorPatcher {
}
}
class GlobalErrorPatcher {
private _prefix: string;
constructor(botName: string) {
this._prefix = `(${botName}) `;
}
patchEvent(event: JsonEvent) {
if (event.method !== 'onError')
return;
const error = event.params.error as TestError;
if (error.message !== undefined)
error.message = this._prefix + error.message;
if (error.stack !== undefined)
error.stack = this._prefix + error.stack;
}
}
interface JsonEventPatcher {
patchEvent(event: JsonEvent): void;
}

View File

@ -904,7 +904,7 @@ test('onError in the report', async ({ runInlineTest, mergeReports, showReport,
test.skip('skipped 3', async ({}) => {});
`
};
const result = await runInlineTest(files, { shard: `1/3` });
const result = await runInlineTest(files, { shard: `1/3` }, { PWTEST_BOT_NAME: 'macos-node16-ttest' });
expect(result.exitCode).toBe(1);
const { exitCode } = await mergeReports(reportDir, { 'PW_TEST_HTML_REPORT_OPEN': 'never' }, { additionalArgs: ['--reporter', 'html'] });
@ -917,6 +917,7 @@ test('onError in the report', async ({ runInlineTest, mergeReports, showReport,
await expect(page.locator('.subnav-item:has-text("Failed") .counter')).toHaveText('0');
await expect(page.locator('.subnav-item:has-text("Flaky") .counter')).toHaveText('0');
await expect(page.locator('.subnav-item:has-text("Skipped") .counter')).toHaveText('1');
await expect(page.getByTestId('report-errors')).toContainText('(macos-node16-ttest) Error: Error in teardown');
});
test('preserve config fields', async ({ runInlineTest, mergeReports }) => {