feat(hooks): add a step per hook (#12867)
It is now possible to see which hooks were run in the html report.
This commit is contained in:
parent
c7d6f96328
commit
3a009531b1
|
|
@ -214,6 +214,18 @@ export class TestInfoImpl implements TestInfo {
|
||||||
this.errors.push(error);
|
this.errors.push(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _runAsStep<T>(cb: () => Promise<T>, stepInfo: Omit<TestStepInternal, 'complete'>): Promise<T> {
|
||||||
|
const step = this._addStep(stepInfo);
|
||||||
|
try {
|
||||||
|
const result = await cb();
|
||||||
|
step.complete();
|
||||||
|
return result;
|
||||||
|
} catch (e) {
|
||||||
|
step.complete(e instanceof SkipError ? undefined : serializeError(e));
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------ TestInfo methods ------------
|
// ------------ TestInfo methods ------------
|
||||||
|
|
||||||
async attach(name: string, options: { path?: string, body?: string | Buffer, contentType?: string } = {}) {
|
async attach(name: string, options: { path?: string, body?: string | Buffer, contentType?: string } = {}) {
|
||||||
|
|
|
||||||
|
|
@ -418,7 +418,13 @@ export class WorkerRunner extends EventEmitter {
|
||||||
if (actualScope !== scope)
|
if (actualScope !== scope)
|
||||||
continue;
|
continue;
|
||||||
testInfo._timeoutManager.setCurrentRunnable({ type: modifier.type, location: modifier.location, slot: timeSlot });
|
testInfo._timeoutManager.setCurrentRunnable({ type: modifier.type, location: modifier.location, slot: timeSlot });
|
||||||
const result = await this._fixtureRunner.resolveParametersAndRunFunction(modifier.fn, testInfo);
|
const result = await testInfo._runAsStep(() => this._fixtureRunner.resolveParametersAndRunFunction(modifier.fn, testInfo), {
|
||||||
|
category: 'hook',
|
||||||
|
title: `${modifier.type} modifier`,
|
||||||
|
canHaveChildren: true,
|
||||||
|
forceNoParent: false,
|
||||||
|
location: modifier.location,
|
||||||
|
});
|
||||||
if (result && extraAnnotations)
|
if (result && extraAnnotations)
|
||||||
extraAnnotations.push({ type: modifier.type, description: modifier.description });
|
extraAnnotations.push({ type: modifier.type, description: modifier.description });
|
||||||
testInfo[modifier.type](!!result, modifier.description);
|
testInfo[modifier.type](!!result, modifier.description);
|
||||||
|
|
@ -437,7 +443,13 @@ export class WorkerRunner extends EventEmitter {
|
||||||
// Separate time slot for each "beforeAll" hook.
|
// Separate time slot for each "beforeAll" hook.
|
||||||
const timeSlot = { timeout: this._project.config.timeout, elapsed: 0 };
|
const timeSlot = { timeout: this._project.config.timeout, elapsed: 0 };
|
||||||
testInfo._timeoutManager.setCurrentRunnable({ type: 'beforeAll', location: hook.location, slot: timeSlot });
|
testInfo._timeoutManager.setCurrentRunnable({ type: 'beforeAll', location: hook.location, slot: timeSlot });
|
||||||
await this._fixtureRunner.resolveParametersAndRunFunction(hook.fn, testInfo);
|
await testInfo._runAsStep(() => this._fixtureRunner.resolveParametersAndRunFunction(hook.fn, testInfo), {
|
||||||
|
category: 'hook',
|
||||||
|
title: `${hook.type} hook`,
|
||||||
|
canHaveChildren: true,
|
||||||
|
forceNoParent: false,
|
||||||
|
location: hook.location,
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Always run all the hooks, and capture the first error.
|
// Always run all the hooks, and capture the first error.
|
||||||
beforeAllError = beforeAllError || e;
|
beforeAllError = beforeAllError || e;
|
||||||
|
|
@ -459,7 +471,13 @@ export class WorkerRunner extends EventEmitter {
|
||||||
// Separate time slot for each "afterAll" hook.
|
// Separate time slot for each "afterAll" hook.
|
||||||
const timeSlot = { timeout: this._project.config.timeout, elapsed: 0 };
|
const timeSlot = { timeout: this._project.config.timeout, elapsed: 0 };
|
||||||
testInfo._timeoutManager.setCurrentRunnable({ type: 'afterAll', location: hook.location, slot: timeSlot });
|
testInfo._timeoutManager.setCurrentRunnable({ type: 'afterAll', location: hook.location, slot: timeSlot });
|
||||||
await this._fixtureRunner.resolveParametersAndRunFunction(hook.fn, testInfo);
|
await testInfo._runAsStep(() => this._fixtureRunner.resolveParametersAndRunFunction(hook.fn, testInfo), {
|
||||||
|
category: 'hook',
|
||||||
|
title: `${hook.type} hook`,
|
||||||
|
canHaveChildren: true,
|
||||||
|
forceNoParent: false,
|
||||||
|
location: hook.location,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
firstError = firstError || afterAllError;
|
firstError = firstError || afterAllError;
|
||||||
}
|
}
|
||||||
|
|
@ -472,7 +490,13 @@ export class WorkerRunner extends EventEmitter {
|
||||||
for (const hook of hooks) {
|
for (const hook of hooks) {
|
||||||
try {
|
try {
|
||||||
testInfo._timeoutManager.setCurrentRunnable({ type, location: hook.location, slot: timeSlot });
|
testInfo._timeoutManager.setCurrentRunnable({ type, location: hook.location, slot: timeSlot });
|
||||||
await this._fixtureRunner.resolveParametersAndRunFunction(hook.fn, testInfo);
|
await testInfo._runAsStep(() => this._fixtureRunner.resolveParametersAndRunFunction(hook.fn, testInfo), {
|
||||||
|
category: 'hook',
|
||||||
|
title: `${hook.type} hook`,
|
||||||
|
canHaveChildren: true,
|
||||||
|
forceNoParent: false,
|
||||||
|
location: hook.location,
|
||||||
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Always run all the hooks, and capture the first error.
|
// Always run all the hooks, and capture the first error.
|
||||||
error = error || e;
|
error = error || e;
|
||||||
|
|
|
||||||
|
|
@ -392,13 +392,31 @@ test('should show multi trace source', async ({ runInlineTest, page, server, sho
|
||||||
await expect(page.locator('.source-line-running')).toContainText('request.get');
|
await expect(page.locator('.source-line-running')).toContainText('request.get');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should show timed out steps', async ({ runInlineTest, page, showReport }) => {
|
test('should show timed out steps and hooks', async ({ runInlineTest, page, showReport }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'playwright.config.js': `
|
'playwright.config.js': `
|
||||||
module.exports = { timeout: 3000 };
|
module.exports = { timeout: 3000 };
|
||||||
`,
|
`,
|
||||||
'a.test.js': `
|
'a.test.js': `
|
||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
|
test.beforeAll(() => {
|
||||||
|
console.log('beforeAll 1');
|
||||||
|
});
|
||||||
|
test.beforeAll(() => {
|
||||||
|
console.log('beforeAll 2');
|
||||||
|
});
|
||||||
|
test.beforeEach(() => {
|
||||||
|
console.log('beforeEach 1');
|
||||||
|
});
|
||||||
|
test.beforeEach(() => {
|
||||||
|
console.log('beforeEach 2');
|
||||||
|
});
|
||||||
|
test.afterEach(() => {
|
||||||
|
console.log('afterEach 1');
|
||||||
|
});
|
||||||
|
test.afterAll(() => {
|
||||||
|
console.log('afterAll 1');
|
||||||
|
});
|
||||||
test('fails', async ({ page }) => {
|
test('fails', async ({ page }) => {
|
||||||
await test.step('outer step', async () => {
|
await test.step('outer step', async () => {
|
||||||
await test.step('inner step', async () => {
|
await test.step('inner step', async () => {
|
||||||
|
|
@ -416,6 +434,20 @@ test('should show timed out steps', async ({ runInlineTest, page, showReport })
|
||||||
await page.click('text=outer step');
|
await page.click('text=outer step');
|
||||||
await expect(page.locator('.tree-item:has-text("outer step") svg.color-text-danger')).toHaveCount(2);
|
await expect(page.locator('.tree-item:has-text("outer step") svg.color-text-danger')).toHaveCount(2);
|
||||||
await expect(page.locator('.tree-item:has-text("inner step") svg.color-text-danger')).toHaveCount(2);
|
await expect(page.locator('.tree-item:has-text("inner step") svg.color-text-danger')).toHaveCount(2);
|
||||||
|
await page.click('text=Before Hooks');
|
||||||
|
await expect(page.locator('.tree-item:has-text("Before Hooks") .tree-item')).toContainText([
|
||||||
|
/beforeAll hook/,
|
||||||
|
/beforeAll hook/,
|
||||||
|
/beforeEach hook/,
|
||||||
|
/beforeEach hook/,
|
||||||
|
]);
|
||||||
|
await page.locator('text=beforeAll hook').nth(1).click();
|
||||||
|
await expect(page.locator('text=console.log(\'beforeAll 2\');')).toBeVisible();
|
||||||
|
await page.click('text=After Hooks');
|
||||||
|
await expect(page.locator('.tree-item:has-text("After Hooks") .tree-item')).toContainText([
|
||||||
|
/afterEach hook/,
|
||||||
|
/afterAll hook/,
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should render annotations', async ({ runInlineTest, page, showReport }) => {
|
test('should render annotations', async ({ runInlineTest, page, showReport }) => {
|
||||||
|
|
|
||||||
|
|
@ -343,11 +343,13 @@ test('should report api steps', async ({ runInlineTest }) => {
|
||||||
`%% end {\"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\":\"apiRequestContext.dispose\",\"category\":\"pw:api\"},{\"title\":\"browserContext.close\",\"category\":\"pw:api\"}]}`,
|
||||||
`%% begin {\"title\":\"Before Hooks\",\"category\":\"hook\"}`,
|
`%% begin {\"title\":\"Before Hooks\",\"category\":\"hook\"}`,
|
||||||
|
`%% begin {\"title\":\"beforeAll hook\",\"category\":\"hook\"}`,
|
||||||
`%% begin {\"title\":\"browser.newPage\",\"category\":\"pw:api\"}`,
|
`%% begin {\"title\":\"browser.newPage\",\"category\":\"pw:api\"}`,
|
||||||
`%% end {\"title\":\"browser.newPage\",\"category\":\"pw:api\"}`,
|
`%% end {\"title\":\"browser.newPage\",\"category\":\"pw:api\"}`,
|
||||||
`%% begin {\"title\":\"page.setContent\",\"category\":\"pw:api\"}`,
|
`%% begin {\"title\":\"page.setContent\",\"category\":\"pw:api\"}`,
|
||||||
`%% end {\"title\":\"page.setContent\",\"category\":\"pw:api\"}`,
|
`%% end {\"title\":\"page.setContent\",\"category\":\"pw:api\"}`,
|
||||||
`%% end {\"title\":\"Before Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"browser.newPage\",\"category\":\"pw:api\"},{\"title\":\"page.setContent\",\"category\":\"pw:api\"}]}`,
|
`%% end {\"title\":\"beforeAll hook\",\"category\":\"hook\",\"steps\":[{\"title\":\"browser.newPage\",\"category\":\"pw:api\"},{\"title\":\"page.setContent\",\"category\":\"pw:api\"}]}`,
|
||||||
|
`%% end {\"title\":\"Before Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"beforeAll hook\",\"category\":\"hook\",\"steps\":[{\"title\":\"browser.newPage\",\"category\":\"pw:api\"},{\"title\":\"page.setContent\",\"category\":\"pw:api\"}]}]}`,
|
||||||
`%% begin {\"title\":\"page.click(button)\",\"category\":\"pw:api\"}`,
|
`%% begin {\"title\":\"page.click(button)\",\"category\":\"pw:api\"}`,
|
||||||
`%% end {\"title\":\"page.click(button)\",\"category\":\"pw:api\"}`,
|
`%% end {\"title\":\"page.click(button)\",\"category\":\"pw:api\"}`,
|
||||||
`%% begin {\"title\":\"After Hooks\",\"category\":\"hook\"}`,
|
`%% begin {\"title\":\"After Hooks\",\"category\":\"hook\"}`,
|
||||||
|
|
@ -357,9 +359,11 @@ test('should report api steps', async ({ runInlineTest }) => {
|
||||||
`%% begin {\"title\":\"page.click(button)\",\"category\":\"pw:api\"}`,
|
`%% begin {\"title\":\"page.click(button)\",\"category\":\"pw:api\"}`,
|
||||||
`%% end {\"title\":\"page.click(button)\",\"category\":\"pw:api\"}`,
|
`%% end {\"title\":\"page.click(button)\",\"category\":\"pw:api\"}`,
|
||||||
`%% begin {\"title\":\"After Hooks\",\"category\":\"hook\"}`,
|
`%% begin {\"title\":\"After Hooks\",\"category\":\"hook\"}`,
|
||||||
|
`%% begin {\"title\":\"afterAll hook\",\"category\":\"hook\"}`,
|
||||||
`%% begin {\"title\":\"page.close\",\"category\":\"pw:api\"}`,
|
`%% begin {\"title\":\"page.close\",\"category\":\"pw:api\"}`,
|
||||||
`%% end {\"title\":\"page.close\",\"category\":\"pw:api\"}`,
|
`%% end {\"title\":\"page.close\",\"category\":\"pw:api\"}`,
|
||||||
`%% end {\"title\":\"After Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"page.close\",\"category\":\"pw:api\"}]}`,
|
`%% end {\"title\":\"afterAll hook\",\"category\":\"hook\",\"steps\":[{\"title\":\"page.close\",\"category\":\"pw:api\"}]}`,
|
||||||
|
`%% end {\"title\":\"After Hooks\",\"category\":\"hook\",\"steps\":[{\"title\":\"afterAll hook\",\"category\":\"hook\",\"steps\":[{\"title\":\"page.close\",\"category\":\"pw:api\"}]}]}`,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue