chore: show steps for fixtures (#22860)

Fixes https://github.com/microsoft/playwright/issues/22565
This commit is contained in:
Pavel Feldman 2023-05-06 10:25:32 -07:00 committed by GitHub
parent 21ffa0b6ad
commit 9771b1ee74
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 257 additions and 37 deletions

View file

@ -16,7 +16,7 @@
import { formatLocation, debugTest } from '../util';
import { ManualPromise, zones } from 'playwright-core/lib/utils';
import type { TestInfoImpl } from './testInfo';
import type { TestInfoImpl, TestStepInternal } from './testInfo';
import type { FixtureDescription, TimeoutManager } from './timeoutManager';
import { fixtureParameterNames, type FixturePool, type FixtureRegistration, type FixtureScope } from '../common/fixtures';
import type { WorkerInfo } from '../../types/test';
@ -74,6 +74,12 @@ class Fixture {
}
}
// Break the regustration function into before/after steps. Create these before/after stacks
// w/o scopes, and create single mutable step that will be converted into the after step.
const shouldGenerateStep = !this.registration.name.startsWith('_') && !this.registration.option && this.registration.scope === 'test';
let mutableStepOnStack: TestStepInternal | undefined;
let afterStep: TestStepInternal | undefined;
let called = false;
const useFuncStarted = new ManualPromise<void>();
debugTest(`setup ${this.registration.name}`);
@ -85,7 +91,17 @@ class Fixture {
this._useFuncFinished = new ManualPromise<void>();
useFuncStarted.resolve();
await this._useFuncFinished;
if (shouldGenerateStep) {
afterStep = testInfo._addStep({
wallTime: Date.now(),
title: `fixture: ${this.registration.name}`,
category: 'fixture',
}, testInfo._afterHooksStep);
mutableStepOnStack!.stepId = afterStep.stepId;
}
};
const workerInfo: WorkerInfo = { config: testInfo.config, parallelIndex: testInfo.parallelIndex, workerIndex: testInfo.workerIndex, project: testInfo.project };
const info = this.registration.scope === 'worker' ? workerInfo : testInfo;
testInfo._timeoutManager.setCurrentFixture(this._runnableDescription);
@ -99,7 +115,16 @@ class Fixture {
};
try {
const result = zones.preserve(async () => {
return await this.registration.fn(params, useFunc, info);
if (!shouldGenerateStep)
return await this.registration.fn(params, useFunc, info);
await testInfo._runAsStep({
title: `fixture: ${this.registration.name}`,
category: 'fixture',
}, async step => {
mutableStepOnStack = step;
return await this.registration.fn(params, useFunc, info);
});
});
if (result instanceof Promise)
@ -110,6 +135,12 @@ class Fixture {
handleError(e);
}
await useFuncStarted;
if (shouldGenerateStep) {
mutableStepOnStack?.complete({});
this._selfTeardownComplete?.finally(() => {
afterStep?.complete({});
});
}
testInfo._timeoutManager.setCurrentFixture(undefined);
}

View file

@ -26,7 +26,7 @@ import type { Location } from '../../types/testReporter';
import { getContainedPath, normalizeAndSaveAttachment, sanitizeForFilePath, serializeError, trimLongString } from '../util';
import type * as trace from '@trace/trace';
interface TestStepInternal {
export interface TestStepInternal {
complete(result: { error?: Error | TestInfoError }): void;
stepId: string;
title: string;
@ -56,6 +56,8 @@ export class TestInfoImpl implements TestInfo {
readonly _projectInternal: FullProjectInternal;
readonly _configInternal: FullConfigInternal;
readonly _steps: TestStepInternal[] = [];
_beforeHooksStep: TestStepInternal | undefined;
_afterHooksStep: TestStepInternal | undefined;
// ------------ TestInfo fields ------------
readonly testId: string;
@ -212,9 +214,10 @@ export class TestInfoImpl implements TestInfo {
}
}
_addStep(data: Omit<TestStepInternal, 'complete' | 'stepId' | 'steps'>): TestStepInternal {
_addStep(data: Omit<TestStepInternal, 'complete' | 'stepId' | 'steps'>, parentStep?: TestStepInternal): TestStepInternal {
const stepId = `${data.category}@${data.title}@${++this._lastStepId}`;
let parentStep = zones.zoneData<TestStepInternal>('stepZone', captureRawStack());
if (!parentStep)
parentStep = zones.zoneData<TestStepInternal>('stepZone', captureRawStack()) || undefined;
// For out-of-stack calls, locate the enclosing step.
let isLaxParent = false;

View file

@ -322,6 +322,7 @@ export class WorkerMain extends ProcessRunner {
let testFunctionParams: object | null = null;
await testInfo._runAsStep({ category: 'hook', title: 'Before Hooks' }, async step => {
testInfo._beforeHooksStep = step;
// Note: wrap all preparation steps together, because failure/skip in any of them
// prevents further setup and/or test from running.
const beforeHooksError = await testInfo._runAndFailOnError(async () => {
@ -392,6 +393,7 @@ export class WorkerMain extends ProcessRunner {
testInfo._timeoutManager.setCurrentRunnable({ type: 'afterEach', slot: afterHooksSlot });
}
await testInfo._runAsStep({ category: 'hook', title: 'After Hooks' }, async step => {
testInfo._afterHooksStep = step;
let firstAfterHooksError: TestInfoError | undefined;
await testInfo._runWithTimeout(async () => {
// Note: do not wrap all teardown steps together, because failure in any of them

View file

@ -84,7 +84,7 @@ function indexModel(context: ContextEntry) {
}
function mergeActions(contexts: ContextEntry[]) {
const map = new Map<number, ActionTraceEvent>();
const map = new Map<string, ActionTraceEvent>();
// Protocol call aka isPrimary contexts have startTime/endTime as server-side times.
// Step aka non-isPrimary contexts have startTime/endTime are client-side times.
@ -95,7 +95,7 @@ function mergeActions(contexts: ContextEntry[]) {
for (const context of primaryContexts) {
for (const action of context.actions)
map.set(action.wallTime, action);
map.set(`${action.apiName}@${action.wallTime}`, action);
if (!offset && context.actions.length)
offset = context.actions[0].startTime - context.actions[0].wallTime;
}
@ -110,7 +110,8 @@ function mergeActions(contexts: ContextEntry[]) {
action.endTime = action.startTime + duration;
}
const existing = map.get(action.wallTime);
const key = `${action.apiName}@${action.wallTime}`;
const existing = map.get(key);
if (existing && existing.apiName === action.apiName) {
if (action.error)
existing.error = action.error;
@ -118,7 +119,7 @@ function mergeActions(contexts: ContextEntry[]) {
existing.attachments = action.attachments;
continue;
}
map.set(action.wallTime, action);
map.set(key, action);
}
}

View file

@ -147,10 +147,14 @@ test('should reuse context with trace if mode=when-possible', async ({ runInline
expect(trace1.apiNames).toEqual([
'Before Hooks',
'browserType.launch',
'fixture: context',
'fixture: page',
'browserContext.newPage',
'page.setContent',
'page.click',
'After Hooks',
'fixture: page',
'fixture: context',
'tracing.stopChunk',
]);
expect(trace1.traceModel.storage().snapshotsForTest().length).toBeGreaterThan(0);
@ -159,11 +163,15 @@ test('should reuse context with trace if mode=when-possible', async ({ runInline
const trace2 = await parseTrace(testInfo.outputPath('test-results', 'reuse-two', 'trace.zip'));
expect(trace2.apiNames).toEqual([
'Before Hooks',
'fixture: context',
'fixture: page',
'expect.toBe',
'page.setContent',
'page.fill',
'locator.click',
'After Hooks',
'fixture: page',
'fixture: context',
'tracing.stopChunk',
]);
expect(trace2.traceModel.storage().snapshotsForTest().length).toBeGreaterThan(0);

View file

@ -89,16 +89,22 @@ test('should record api trace', async ({ runInlineTest, server }, testInfo) => {
const trace1 = await parseTrace(testInfo.outputPath('test-results', 'a-pass', 'trace.zip'));
expect(trace1.apiNames).toEqual([
'Before Hooks',
'fixture: request',
'apiRequest.newContext',
'tracing.start',
'browserType.launch',
'fixture: context',
'browser.newContext',
'tracing.start',
'fixture: page',
'browserContext.newPage',
'page.goto',
'apiRequestContext.get',
'After Hooks',
'fixture: page',
'fixture: context',
'browserContext.close',
'fixture: request',
'tracing.stopChunk',
'apiRequestContext.dispose',
]);
@ -115,16 +121,22 @@ test('should record api trace', async ({ runInlineTest, server }, testInfo) => {
expect(trace3.apiNames).toEqual([
'Before Hooks',
'tracing.startChunk',
'fixture: request',
'apiRequest.newContext',
'tracing.start',
'fixture: context',
'browser.newContext',
'tracing.start',
'fixture: page',
'browserContext.newPage',
'page.goto',
'apiRequestContext.get',
'expect.toBe',
'After Hooks',
'fixture: page',
'fixture: context',
'browserContext.close',
'fixture: request',
'tracing.stopChunk',
'apiRequestContext.dispose',
'browser.close',
@ -317,16 +329,22 @@ test('should not override trace file in afterAll', async ({ runInlineTest, serve
expect(trace1.apiNames).toEqual([
'Before Hooks',
'browserType.launch',
'fixture: context',
'browser.newContext',
'tracing.start',
'fixture: page',
'browserContext.newPage',
'page.goto',
'After Hooks',
'fixture: page',
'fixture: context',
'browserContext.close',
'afterAll hook',
'fixture: request',
'apiRequest.newContext',
'tracing.start',
'apiRequestContext.get',
'fixture: request',
'tracing.stopChunk',
'apiRequestContext.dispose',
'browser.close',

View file

@ -280,17 +280,25 @@ test('should report expect steps', async ({ runInlineTest }) => {
`begin {\"title\":\"Before Hooks\",\"category\":\"hook\"}`,
`begin {\"title\":\"browserType.launch\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browserType.launch\",\"category\":\"pw:api\"}`,
`begin {\"title\":\"fixture: context\",\"category\":\"fixture\"}`,
`begin {\"title\":\"browser.newContext\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browser.newContext\",\"category\":\"pw:api\"}`,
`end {\"title\":\"fixture: context\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browser.newContext\",\"category\":\"pw:api\"}]}`,
`begin {\"title\":\"fixture: page\",\"category\":\"fixture\"}`,
`begin {\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}`,
`end {\"title\":\"Before Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browserType.launch\",\"category\":\"pw:api\"},{\"title\":\"browser.newContext\",\"category\":\"pw:api\"},{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]}`,
`end {\"title\":\"fixture: page\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]}`,
`end {\"title\":\"Before Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browserType.launch\",\"category\":\"pw:api\"},{\"title\":\"fixture: context\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browser.newContext\",\"category\":\"pw:api\"}]},{\"title\":\"fixture: page\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]}]}`,
`begin {\"title\":\"expect.not.toHaveTitle\",\"category\":\"expect\"}`,
`end {\"title\":\"expect.not.toHaveTitle\",\"category\":\"expect\"}`,
`begin {\"title\":\"After Hooks\",\"category\":\"hook\"}`,
`begin {\"title\":\"fixture: page\",\"category\":\"fixture\"}`,
`end {\"title\":\"fixture: page\",\"category\":\"fixture\"}`,
`begin {\"title\":\"fixture: context\",\"category\":\"fixture\"}`,
`end {\"title\":\"fixture: context\",\"category\":\"fixture\"}`,
`begin {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`,
`end {\"title\":\"After Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browserContext.close\",\"category\":\"pw:api\"}]}`,
`end {\"title\":\"After Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"fixture: page\",\"category\":\"fixture\"},{\"title\":\"fixture: context\",\"category\":\"fixture\"},{\"title\":\"browserContext.close\",\"category\":\"pw:api\"}]}`,
]);
});
@ -341,13 +349,19 @@ test('should report api steps', async ({ runInlineTest }) => {
`begin {\"title\":\"Before Hooks\",\"category\":\"hook\"}`,
`begin {\"title\":\"browserType.launch\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browserType.launch\",\"category\":\"pw:api\"}`,
`begin {\"title\":\"fixture: context\",\"category\":\"fixture\"}`,
`begin {\"title\":\"browser.newContext\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browser.newContext\",\"category\":\"pw:api\"}`,
`end {\"title\":\"fixture: context\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browser.newContext\",\"category\":\"pw:api\"}]}`,
`begin {\"title\":\"fixture: page\",\"category\":\"fixture\"}`,
`begin {\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}`,
`end {\"title\":\"fixture: page\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]}`,
`begin {\"title\":\"fixture: request\",\"category\":\"fixture\"}`,
`begin {\"title\":\"apiRequest.newContext\",\"category\":\"pw:api\"}`,
`end {\"title\":\"apiRequest.newContext\",\"category\":\"pw:api\"}`,
`end {\"title\":\"Before Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browserType.launch\",\"category\":\"pw:api\"},{\"title\":\"browser.newContext\",\"category\":\"pw:api\"},{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"},{\"title\":\"apiRequest.newContext\",\"category\":\"pw:api\"}]}`,
`end {\"title\":\"fixture: request\",\"category\":\"fixture\",\"steps\":[{\"title\":\"apiRequest.newContext\",\"category\":\"pw:api\"}]}`,
`end {\"title\":\"Before Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browserType.launch\",\"category\":\"pw:api\"},{\"title\":\"fixture: context\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browser.newContext\",\"category\":\"pw:api\"}]},{\"title\":\"fixture: page\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]},{\"title\":\"fixture: request\",\"category\":\"fixture\",\"steps\":[{\"title\":\"apiRequest.newContext\",\"category\":\"pw:api\"}]}]}`,
`begin {\"title\":\"page.waitForNavigation\",\"category\":\"pw:api\"}`,
`begin {\"title\":\"page.goto(data:text/html,<button></button>)\",\"category\":\"pw:api\"}`,
`end {\"title\":\"page.waitForNavigation\",\"category\":\"pw:api\",\"steps\":[{\"title\":\"page.goto(data:text/html,<button></button>)\",\"category\":\"pw:api\"}]}`,
@ -361,11 +375,17 @@ test('should report api steps', async ({ runInlineTest }) => {
`begin {"title":"apiRequestContext.get(http://localhost2)","category":"pw:api"}`,
`end {"title":"apiRequestContext.get(http://localhost2)","category":"pw:api","error":{"message":"<message>","stack":"<stack>","location":"<location>","snippet":"<snippet>"}}`,
`begin {\"title\":\"After Hooks\",\"category\":\"hook\"}`,
`begin {\"title\":\"fixture: request\",\"category\":\"fixture\"}`,
`begin {\"title\":\"apiRequestContext.dispose\",\"category\":\"pw:api\"}`,
`end {\"title\":\"apiRequestContext.dispose\",\"category\":\"pw:api\"}`,
`end {\"title\":\"fixture: request\",\"category\":\"fixture\",\"steps\":[{\"title\":\"apiRequestContext.dispose\",\"category\":\"pw:api\"}]}`,
`begin {\"title\":\"fixture: page\",\"category\":\"fixture\"}`,
`end {\"title\":\"fixture: page\",\"category\":\"fixture\"}`,
`begin {\"title\":\"fixture: context\",\"category\":\"fixture\"}`,
`end {\"title\":\"fixture: context\",\"category\":\"fixture\"}`,
`begin {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`,
`end {\"title\":\"After Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"apiRequestContext.dispose\",\"category\":\"pw:api\"},{\"title\":\"browserContext.close\",\"category\":\"pw:api\"}]}`,
`end {\"title\":\"After Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"fixture: request\",\"category\":\"fixture\",\"steps\":[{\"title\":\"apiRequestContext.dispose\",\"category\":\"pw:api\"}]},{\"title\":\"fixture: page\",\"category\":\"fixture\"},{\"title\":\"fixture: context\",\"category\":\"fixture\"},{\"title\":\"browserContext.close\",\"category\":\"pw:api\"}]}`,
`begin {\"title\":\"Before Hooks\",\"category\":\"hook\"}`,
`begin {\"title\":\"beforeAll hook\",\"category\":\"hook\"}`,
`begin {\"title\":\"browser.newPage\",\"category\":\"pw:api\"}`,
@ -414,21 +434,29 @@ test('should report api step failure', async ({ runInlineTest }) => {
`begin {\"title\":\"Before Hooks\",\"category\":\"hook\"}`,
`begin {\"title\":\"browserType.launch\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browserType.launch\",\"category\":\"pw:api\"}`,
`begin {\"title\":\"fixture: context\",\"category\":\"fixture\"}`,
`begin {\"title\":\"browser.newContext\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browser.newContext\",\"category\":\"pw:api\"}`,
`end {\"title\":\"fixture: context\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browser.newContext\",\"category\":\"pw:api\"}]}`,
`begin {\"title\":\"fixture: page\",\"category\":\"fixture\"}`,
`begin {\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}`,
`end {\"title\":\"Before Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browserType.launch\",\"category\":\"pw:api\"},{\"title\":\"browser.newContext\",\"category\":\"pw:api\"},{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]}`,
`end {\"title\":\"fixture: page\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]}`,
`end {\"title\":\"Before Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browserType.launch\",\"category\":\"pw:api\"},{\"title\":\"fixture: context\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browser.newContext\",\"category\":\"pw:api\"}]},{\"title\":\"fixture: page\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]}]}`,
`begin {\"title\":\"page.setContent\",\"category\":\"pw:api\"}`,
`end {\"title\":\"page.setContent\",\"category\":\"pw:api\"}`,
`begin {\"title\":\"page.click(input)\",\"category\":\"pw:api\"}`,
`end {\"title\":\"page.click(input)\",\"category\":\"pw:api\",\"error\":{\"message\":\"page.click: Timeout 1ms exceeded.\\n=========================== logs ===========================\\nwaiting for locator('input')\\n============================================================\",\"stack\":\"<stack>\",\"location\":\"<location>\",\"snippet\":\"<snippet>\"}}`,
`begin {\"title\":\"After Hooks\",\"category\":\"hook\"}`,
`begin {\"title\":\"fixture: page\",\"category\":\"fixture\"}`,
`end {\"title\":\"fixture: page\",\"category\":\"fixture\"}`,
`begin {\"title\":\"fixture: context\",\"category\":\"fixture\"}`,
`end {\"title\":\"fixture: context\",\"category\":\"fixture\"}`,
`begin {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`,
`begin {\"title\":\"browser.close\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browser.close\",\"category\":\"pw:api\"}`,
`end {\"title\":\"After Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browserContext.close\",\"category\":\"pw:api\"},{\"title\":\"browser.close\",\"category\":\"pw:api\"}]}`,
`end {\"title\":\"After Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"fixture: page\",\"category\":\"fixture\"},{\"title\":\"fixture: context\",\"category\":\"fixture\"},{\"title\":\"browserContext.close\",\"category\":\"pw:api\"},{\"title\":\"browser.close\",\"category\":\"pw:api\"}]}`,
]);
});
@ -480,19 +508,27 @@ test('should show nice stacks for locators', async ({ runInlineTest }) => {
`begin {"title":"Before Hooks","category":"hook"}`,
`begin {\"title\":\"browserType.launch\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browserType.launch\",\"category\":\"pw:api\"}`,
`begin {\"title\":\"fixture: context\",\"category\":\"fixture\"}`,
`begin {\"title\":\"browser.newContext\",\"category\":\"pw:api\"}`,
`end {\"title\":\"browser.newContext\",\"category\":\"pw:api\"}`,
`end {\"title\":\"fixture: context\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browser.newContext\",\"category\":\"pw:api\"}]}`,
`begin {\"title\":\"fixture: page\",\"category\":\"fixture\"}`,
`begin {"title":"browserContext.newPage","category":"pw:api"}`,
`end {"title":"browserContext.newPage","category":"pw:api"}`,
`end {\"title\":\"Before Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browserType.launch\",\"category\":\"pw:api\"},{\"title\":\"browser.newContext\",\"category\":\"pw:api\"},{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]}`,
`end {\"title\":\"fixture: page\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]}`,
`end {\"title\":\"Before Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browserType.launch\",\"category\":\"pw:api\"},{\"title\":\"fixture: context\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browser.newContext\",\"category\":\"pw:api\"}]},{\"title\":\"fixture: page\",\"category\":\"fixture\",\"steps\":[{\"title\":\"browserContext.newPage\",\"category\":\"pw:api\"}]}]}`,
`begin {"title":"page.setContent","category":"pw:api"}`,
`end {"title":"page.setContent","category":"pw:api"}`,
`begin {"title":"locator.evaluate(button)","category":"pw:api"}`,
`end {"title":"locator.evaluate(button)","category":"pw:api"}`,
`begin {"title":"After Hooks","category":"hook"}`,
`begin {\"title\":\"fixture: page\",\"category\":\"fixture\"}`,
`end {\"title\":\"fixture: page\",\"category\":\"fixture\"}`,
`begin {\"title\":\"fixture: context\",\"category\":\"fixture\"}`,
`end {\"title\":\"fixture: context\",\"category\":\"fixture\"}`,
`begin {"title":"browserContext.close","category":"pw:api"}`,
`end {"title":"browserContext.close","category":"pw:api"}`,
`end {"title":"After Hooks","category":"hook","steps":[{"title":"browserContext.close","category":"pw:api"}]}`,
`end {\"title\":\"After Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"fixture: page\",\"category\":\"fixture\"},{\"title\":\"fixture: context\",\"category\":\"fixture\"},{\"title\":\"browserContext.close\",\"category\":\"pw:api\"}]}`,
]);
});

View file

@ -100,12 +100,24 @@ test('should report api step hierarchy', async ({ runInlineTest }) => {
title: 'browserType.launch',
},
{
category: 'pw:api',
title: 'browser.newContext',
category: 'fixture',
title: 'fixture: context',
steps: [
{
category: 'pw:api',
title: 'browser.newContext',
},
]
},
{
category: 'pw:api',
title: 'browserContext.newPage',
category: 'fixture',
title: 'fixture: page',
steps: [
{
category: 'pw:api',
title: 'browserContext.newPage',
},
]
},
],
},
@ -171,6 +183,14 @@ test('should report api step hierarchy', async ({ runInlineTest }) => {
category: 'hook',
title: 'After Hooks',
steps: [
{
category: 'fixture',
title: 'fixture: page',
},
{
category: 'fixture',
title: 'fixture: context',
},
{
category: 'pw:api',
title: 'browserContext.close',
@ -255,12 +275,24 @@ test('should not report nested after hooks', async ({ runInlineTest }) => {
title: 'browserType.launch',
},
{
category: 'pw:api',
title: 'browser.newContext',
category: 'fixture',
title: 'fixture: context',
steps: [
{
category: 'pw:api',
title: 'browser.newContext',
},
]
},
{
category: 'pw:api',
title: 'browserContext.newPage',
category: 'fixture',
title: 'fixture: page',
steps: [
{
category: 'pw:api',
title: 'browserContext.newPage',
},
]
},
],
},
@ -277,6 +309,14 @@ test('should not report nested after hooks', async ({ runInlineTest }) => {
category: 'hook',
title: 'After Hooks',
steps: [
{
category: 'fixture',
title: 'fixture: page',
},
{
category: 'fixture',
title: 'fixture: context',
},
{
category: 'pw:api',
title: 'browserContext.close',
@ -332,16 +372,20 @@ test('should report test.step from fixtures', async ({ runInlineTest }) => {
expect(result.exitCode).toBe(0);
expect(result.outputLines).toEqual([
`begin Before Hooks`,
`begin fixture: foo`,
`begin setup foo`,
`end setup foo`,
`end fixture: foo`,
`end Before Hooks`,
`begin test step`,
`begin inside foo`,
`end inside foo`,
`end test step`,
`begin After Hooks`,
`begin fixture: foo`,
`begin teardown foo`,
`end teardown foo`,
`end fixture: foo`,
`end After Hooks`,
]);
});
@ -374,12 +418,24 @@ test('should report expect step locations', async ({ runInlineTest }) => {
title: 'browserType.launch',
},
{
category: 'pw:api',
title: 'browser.newContext',
category: 'fixture',
title: 'fixture: context',
steps: [
{
category: 'pw:api',
title: 'browser.newContext',
},
]
},
{
category: 'pw:api',
title: 'browserContext.newPage',
category: 'fixture',
title: 'fixture: page',
steps: [
{
category: 'pw:api',
title: 'browserContext.newPage',
},
]
},
],
},
@ -396,6 +452,14 @@ test('should report expect step locations', async ({ runInlineTest }) => {
category: 'hook',
title: 'After Hooks',
steps: [
{
category: 'fixture',
title: 'fixture: page',
},
{
category: 'fixture',
title: 'fixture: context',
},
{
category: 'pw:api',
title: 'browserContext.close',
@ -622,13 +686,25 @@ test('should nest steps based on zones', async ({ runInlineTest }) => {
category: 'pw:api'
},
{
category: 'pw:api',
title: 'browser.newContext',
category: 'fixture',
title: 'fixture: context',
steps: [
{
category: 'pw:api',
title: 'browser.newContext',
},
]
},
{
title: 'browserContext.newPage',
category: 'pw:api'
}
category: 'fixture',
title: 'fixture: page',
steps: [
{
category: 'pw:api',
title: 'browserContext.newPage',
},
]
},
]
},
{
@ -700,6 +776,14 @@ test('should nest steps based on zones', async ({ runInlineTest }) => {
],
location: { file: 'a.test.ts', line: 'number', column: 'number' }
},
{
category: 'fixture',
title: 'fixture: page',
},
{
category: 'fixture',
title: 'fixture: context',
},
{
title: 'browserContext.close',
category: 'pw:api'
@ -856,8 +940,26 @@ test('should nest page.continue insize page.goto steps', async ({ runInlineTest
category: 'hook',
steps: [
{ title: 'browserType.launch', category: 'pw:api' },
{ title: 'browser.newContext', category: 'pw:api' },
{ title: 'browserContext.newPage', category: 'pw:api' },
{
category: 'fixture',
title: 'fixture: context',
steps: [
{
category: 'pw:api',
title: 'browser.newContext',
},
]
},
{
category: 'fixture',
title: 'fixture: page',
steps: [
{
category: 'pw:api',
title: 'browserContext.newPage',
},
]
},
],
},
{
@ -881,6 +983,14 @@ test('should nest page.continue insize page.goto steps', async ({ runInlineTest
title: 'After Hooks',
category: 'hook',
steps: [
{
category: 'fixture',
title: 'fixture: page',
},
{
category: 'fixture',
title: 'fixture: context',
},
{ title: 'browserContext.close', category: 'pw:api' },
],
},

View file

@ -208,10 +208,14 @@ test('should report toHaveScreenshot step with expectation name in title', async
expect(result.outputLines).toEqual([
`end browserType.launch`,
`end browser.newContext`,
`end fixture: context`,
`end browserContext.newPage`,
`end fixture: page`,
`end Before Hooks`,
`end expect.toHaveScreenshot(foo.png)`,
`end expect.toHaveScreenshot(is-a-test-1.png)`,
`end fixture: page`,
`end fixture: context`,
`end browserContext.close`,
`end After Hooks`,
]);

View file

@ -108,6 +108,8 @@ test('should update trace live', async ({ runUITest, server }) => {
/page.gotohttp:\/\/localhost:\d+\/one.html/,
/page.gotohttp:\/\/localhost:\d+\/two.html/,
/After Hooks[\d.]+m?s/,
/fixture: page[\d.]+m?s/,
/fixture: context[\d.]+m?s/,
/browserContext.close[\d.]+m?s/,
]);
});

View file

@ -45,8 +45,9 @@ test('should merge trace events', async ({ runUITest, server }) => {
/locator.clickgetByRole\('button'\)[\d.]+m?s/,
/expect.toBe[\d.]+m?s/,
/After Hooks[\d.]+m?s/,
/fixture: page[\d.]+m?s/,
/fixture: context[\d.]+m?s/,
/browserContext.close[\d.]+m?s/,
]);
});
@ -73,6 +74,8 @@ test('should merge web assertion events', async ({ runUITest }, testInfo) => {
/page.setContent[\d.]+m?s/,
/expect.toBeVisiblelocator\('button'\)[\d.]+m?s/,
/After Hooks[\d.]+m?s/,
/fixture: page[\d.]+m?s/,
/fixture: context[\d.]+m?s/,
/browserContext.close[\d.]+m?s/,
]);
});
@ -148,6 +151,8 @@ test('should show snapshots for sync assertions', async ({ runUITest, server })
/locator\.clickgetByRole\('button'\)[\d.]+m?s/,
/expect\.toBe[\d.]+m?s/,
/After Hooks[\d.]+m?s/,
/fixture: page[\d.]+m?s/,
/fixture: context[\d.]+m?s/,
/browserContext.close[\d.]+m?s/,
]);