mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix: preserve steps in merged report (#23120)
This commit is contained in:
parent
acdb71878e
commit
a1fc8ff07d
@ -28,7 +28,7 @@ export type JsonConfig = Pick<FullConfig, 'configFile' | 'globalTimeout' | 'maxF
|
|||||||
listOnly: boolean;
|
listOnly: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type MergeReporterConfig = Pick<FullConfig, 'configFile' | 'reportSlowTests' | 'quiet' >;
|
export type MergeReporterConfig = Pick<FullConfig, 'configFile' | 'quiet' | 'reportSlowTests' | 'rootDir' >;
|
||||||
|
|
||||||
export type JsonPattern = {
|
export type JsonPattern = {
|
||||||
s?: string;
|
s?: string;
|
||||||
@ -171,7 +171,7 @@ export class TeleReporterReceiver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _onBegin(config: JsonConfig, projects: JsonProject[]) {
|
private _onBegin(config: JsonConfig, projects: JsonProject[]) {
|
||||||
this._rootDir = config.rootDir;
|
this._rootDir = this._reportConfig?.rootDir || config.rootDir;
|
||||||
for (const project of projects) {
|
for (const project of projects) {
|
||||||
let projectSuite = this._rootSuite.suites.find(suite => suite.project()!.id === project.id);
|
let projectSuite = this._rootSuite.suites.find(suite => suite.project()!.id === project.id);
|
||||||
if (!projectSuite) {
|
if (!projectSuite) {
|
||||||
@ -247,6 +247,8 @@ export class TeleReporterReceiver {
|
|||||||
};
|
};
|
||||||
if (parentStep)
|
if (parentStep)
|
||||||
parentStep.steps.push(step);
|
parentStep.steps.push(step);
|
||||||
|
else
|
||||||
|
result.steps.push(step);
|
||||||
result.stepMap.set(payload.id, step);
|
result.stepMap.set(payload.id, step);
|
||||||
this._reporter.onStepBegin?.(test, result, step);
|
this._reporter.onStepBegin?.(test, result, step);
|
||||||
}
|
}
|
||||||
@ -286,6 +288,7 @@ export class TeleReporterReceiver {
|
|||||||
const result = { ...baseFullConfig, ...config };
|
const result = { ...baseFullConfig, ...config };
|
||||||
if (this._reportConfig) {
|
if (this._reportConfig) {
|
||||||
result.configFile = this._reportConfig.configFile;
|
result.configFile = this._reportConfig.configFile;
|
||||||
|
result.rootDir = this._reportConfig.rootDir;
|
||||||
result.reportSlowTests = this._reportConfig.reportSlowTests;
|
result.reportSlowTests = this._reportConfig.reportSlowTests;
|
||||||
result.quiet = this._reportConfig.quiet;
|
result.quiet = this._reportConfig.quiet;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import type { FullConfig, ReporterDescription } from '../../types/test';
|
import type { ReporterDescription } from '../../types/test';
|
||||||
import type { FullResult } from '../../types/testReporter';
|
import type { FullResult } from '../../types/testReporter';
|
||||||
import type { FullConfigInternal } from '../common/config';
|
import type { FullConfigInternal } from '../common/config';
|
||||||
import { TeleReporterReceiver, type JsonEvent, type JsonProject, type JsonSuite, type JsonTestResultEnd, type JsonConfig } from '../isomorphic/teleReceiver';
|
import { TeleReporterReceiver, type JsonEvent, type JsonProject, type JsonSuite, type JsonTestResultEnd, type JsonConfig } from '../isomorphic/teleReceiver';
|
||||||
@ -25,7 +25,7 @@ import { Multiplexer } from './multiplexer';
|
|||||||
|
|
||||||
export async function createMergedReport(config: FullConfigInternal, dir: string, reporterDescriptions: ReporterDescription[], resolvePaths: boolean) {
|
export async function createMergedReport(config: FullConfigInternal, dir: string, reporterDescriptions: ReporterDescription[], resolvePaths: boolean) {
|
||||||
const shardFiles = await sortedShardFiles(dir);
|
const shardFiles = await sortedShardFiles(dir);
|
||||||
const events = await mergeEvents(dir, shardFiles, config.config);
|
const events = await mergeEvents(dir, shardFiles);
|
||||||
if (resolvePaths)
|
if (resolvePaths)
|
||||||
patchAttachmentPaths(events, dir);
|
patchAttachmentPaths(events, dir);
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ function parseEvents(reportJsonl: string): JsonEvent[] {
|
|||||||
return reportJsonl.toString().split('\n').filter(line => line.length).map(line => JSON.parse(line)) as JsonEvent[];
|
return reportJsonl.toString().split('\n').filter(line => line.length).map(line => JSON.parse(line)) as JsonEvent[];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function mergeEvents(dir: string, shardReportFiles: string[], reportConfig: FullConfig) {
|
async function mergeEvents(dir: string, shardReportFiles: string[]) {
|
||||||
const events: JsonEvent[] = [];
|
const events: JsonEvent[] = [];
|
||||||
const beginEvents: JsonEvent[] = [];
|
const beginEvents: JsonEvent[] = [];
|
||||||
const endEvents: JsonEvent[] = [];
|
const endEvents: JsonEvent[] = [];
|
||||||
@ -69,10 +69,10 @@ async function mergeEvents(dir: string, shardReportFiles: string[], reportConfig
|
|||||||
events.push(event);
|
events.push(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [mergeBeginEvents(beginEvents, reportConfig), ...events, mergeEndEvents(endEvents), { method: 'onExit', params: undefined }];
|
return [mergeBeginEvents(beginEvents), ...events, mergeEndEvents(endEvents), { method: 'onExit', params: undefined }];
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeBeginEvents(beginEvents: JsonEvent[], reportConfig: FullConfig): JsonEvent {
|
function mergeBeginEvents(beginEvents: JsonEvent[]): JsonEvent {
|
||||||
if (!beginEvents.length)
|
if (!beginEvents.length)
|
||||||
throw new Error('No begin events found');
|
throw new Error('No begin events found');
|
||||||
const projects: JsonProject[] = [];
|
const projects: JsonProject[] = [];
|
||||||
|
@ -47,10 +47,11 @@ const test = baseTest.extend<{
|
|||||||
if (options.additionalArgs)
|
if (options.additionalArgs)
|
||||||
command.push(...options.additionalArgs);
|
command.push(...options.additionalArgs);
|
||||||
|
|
||||||
|
const cwd = options.cwd ? path.resolve(test.info().outputDir, options.cwd) : test.info().outputDir;
|
||||||
const testProcess = childProcess({
|
const testProcess = childProcess({
|
||||||
command,
|
command,
|
||||||
env: cleanEnv(env),
|
env: cleanEnv(env),
|
||||||
cwd: test.info().outputDir,
|
cwd,
|
||||||
});
|
});
|
||||||
const { exitCode } = await testProcess.exited;
|
const { exitCode } = await testProcess.exited;
|
||||||
return { exitCode, output: testProcess.output.toString() };
|
return { exitCode, output: testProcess.output.toString() };
|
||||||
@ -409,14 +410,12 @@ test('preserve attachments', async ({ runInlineTest, mergeReports, showReport, p
|
|||||||
|
|
||||||
await showReport();
|
await showReport();
|
||||||
|
|
||||||
// Check file attachment.
|
|
||||||
await page.getByText('first').click();
|
await page.getByText('first').click();
|
||||||
await expect(page.getByText('file-attachment')).toBeVisible();
|
|
||||||
|
|
||||||
// Check file attachment content.
|
|
||||||
const popupPromise = page.waitForEvent('popup');
|
const popupPromise = page.waitForEvent('popup');
|
||||||
await page.getByText('file-attachment').click();
|
// Check file attachment.
|
||||||
|
await page.getByRole('link', { name: 'file-attachment' }).click();
|
||||||
const popup = await popupPromise;
|
const popup = await popupPromise;
|
||||||
|
// Check file attachment content.
|
||||||
await expect(popup.locator('body')).toHaveText('hello!');
|
await expect(popup.locator('body')).toHaveText('hello!');
|
||||||
await popup.close();
|
await popup.close();
|
||||||
await page.goBack();
|
await page.goBack();
|
||||||
@ -484,15 +483,14 @@ test('generate html with attachment urls', async ({ runInlineTest, mergeReports,
|
|||||||
return oldSeveFile.call(server, req, res, filePath);
|
return oldSeveFile.call(server, req, res, filePath);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check file attachment.
|
|
||||||
await page.goto(`${server.PREFIX}/index.html`);
|
await page.goto(`${server.PREFIX}/index.html`);
|
||||||
await page.getByText('first').click();
|
await page.getByText('first').click();
|
||||||
await expect(page.getByText('file-attachment')).toBeVisible();
|
|
||||||
|
|
||||||
// Check file attachment content.
|
|
||||||
const popupPromise = page.waitForEvent('popup');
|
const popupPromise = page.waitForEvent('popup');
|
||||||
await page.getByText('file-attachment').click();
|
// Check file attachment.
|
||||||
|
await page.getByRole('link', { name: 'file-attachment' }).click();
|
||||||
const popup = await popupPromise;
|
const popup = await popupPromise;
|
||||||
|
// Check file attachment content.
|
||||||
await expect(popup.locator('body')).toHaveText('hello!');
|
await expect(popup.locator('body')).toHaveText('hello!');
|
||||||
await popup.close();
|
await popup.close();
|
||||||
await page.goBack();
|
await page.goBack();
|
||||||
@ -847,3 +845,57 @@ test('preserve config fields', async ({ runInlineTest, mergeReports }) => {
|
|||||||
expect(json.configFile).toEqual(test.info().outputPath('merge.config.ts'));
|
expect(json.configFile).toEqual(test.info().outputPath('merge.config.ts'));
|
||||||
expect(json.quiet).toEqual(mergeConfig.quiet);
|
expect(json.quiet).toEqual(mergeConfig.quiet);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('preserve steps in html report', async ({ runInlineTest, mergeReports, showReport, page }) => {
|
||||||
|
test.slow();
|
||||||
|
const reportDir = test.info().outputPath('blob-report');
|
||||||
|
const files = {
|
||||||
|
'playwright.config.ts': `
|
||||||
|
module.exports = {
|
||||||
|
reporter: [['blob']]
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
'tests/a.test.js': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
test.beforeAll(() => {
|
||||||
|
expect(1).toBe(1);
|
||||||
|
})
|
||||||
|
test('test 1', async ({}) => {
|
||||||
|
await test.step('my step', async () => {
|
||||||
|
expect(2).toBe(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
await runInlineTest(files);
|
||||||
|
const reportFiles = await fs.promises.readdir(reportDir);
|
||||||
|
reportFiles.sort();
|
||||||
|
expect(reportFiles).toEqual([expect.stringMatching(/report-.*.jsonl/), 'resources']);
|
||||||
|
// Run merger in a different directory to make sure relative paths will not be resolved
|
||||||
|
// relative to the current directory.
|
||||||
|
const mergeCwd = test.info().outputPath('foo');
|
||||||
|
await fs.promises.mkdir(mergeCwd, { recursive: true });
|
||||||
|
const { exitCode, output } = await mergeReports(reportDir, { 'PW_TEST_HTML_REPORT_OPEN': 'never' }, { additionalArgs: ['--reporter', 'html'], cwd: mergeCwd });
|
||||||
|
expect(exitCode).toBe(0);
|
||||||
|
|
||||||
|
expect(output).toContain('To open last HTML report run:');
|
||||||
|
|
||||||
|
await showReport();
|
||||||
|
|
||||||
|
await expect(page.locator('.subnav-item:has-text("All") .counter')).toHaveText('1');
|
||||||
|
await expect(page.locator('.subnav-item:has-text("Passed") .counter')).toHaveText('1');
|
||||||
|
|
||||||
|
await page.getByRole('link', { name: 'test 1' }).click();
|
||||||
|
|
||||||
|
await page.getByText('Before Hooks').click();
|
||||||
|
await page.getByText('beforeAll hook').click();
|
||||||
|
await expect(page.getByText('expect.toBe')).toBeVisible();
|
||||||
|
// Collapse hooks.
|
||||||
|
await page.getByText('Before Hooks').click();
|
||||||
|
await expect(page.getByText('expect.toBe')).not.toBeVisible();
|
||||||
|
|
||||||
|
// Check that 'my step' location is relative.
|
||||||
|
await expect(page.getByText('— tests/a.test.js:7')).toBeVisible();
|
||||||
|
await page.getByText('my step').click();
|
||||||
|
await expect(page.getByText('expect.toBe')).toBeVisible();
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user