Skip to content

Commit

Permalink
add name option to BeforeAll / AfterAll hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
vitalets committed Oct 28, 2024
1 parent 95e3701 commit 5ff63c6
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* support scoped step definitions ([#205](https://github.com/vitalets/playwright-bdd/issues/205))
* new config option `missingSteps` to setup different behavior when step definitions are missing ([#158](https://github.com/vitalets/playwright-bdd/issues/158))
* new config option `matchKeywords` to enable keyword matching when searching for step definitions ([#221](https://github.com/vitalets/playwright-bdd/issues/221))
* add `name` option to `BeforeAll / AfterAll` hooks
* make config option `quote` default to `"single"` to have less escapes in the generated files
* config option `featuresRoot` serves as a default directory for both `features` and `steps`, if these options are not explicitly defined
* feature: provide full localized step titles to Playwright HTML reporter ([#229](https://github.com/vitalets/playwright-bdd/issues/229), [#122](https://github.com/vitalets/playwright-bdd/issues/122))
Expand Down
2 changes: 1 addition & 1 deletion src/gen/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class Formatter {
const title = type === 'beforeAll' ? 'BeforeAll Hooks' : 'AfterAll Hooks';
return [
// eslint-disable-next-line max-len
`test.${type}(${this.quoted(title)}, ({ ${allFixturesStr} }) => ${runWorkerHooksFixture}(${this.quoted(type)}, { ${fixturesStr} }));`,
`test.${type}(${this.quoted(title)}, ({ ${allFixturesStr} }) => ${runWorkerHooksFixture}(test, ${this.quoted(type)}, { ${fixturesStr} }));`,
];
}

Expand Down
6 changes: 3 additions & 3 deletions src/hooks/scenario.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ export async function runScenarioHooks(type: ScenarioHookType, fixtures: Scenari
}

async function runScenarioHook(hook: GeneralScenarioHook, fixtures: ScenarioHookFixtures) {
const hookFn = wrapHookFn(hook, fixtures);
const fn = wrapHookFnWithTimeout(hook, fixtures);
const stepTitle = getHookStepTitle(hook);
await runStepWithLocation(fixtures.$bddContext.test, stepTitle, hook.location, hookFn);
await runStepWithLocation(fixtures.$bddContext.test, stepTitle, hook.location, fn);
}

export function getScenarioHooksFixtureNames(hooks: GeneralScenarioHook[]) {
Expand All @@ -120,7 +120,7 @@ export function getScenarioHooksToRun(type: ScenarioHookType, tags: string[] = [
/**
* Wraps hook fn with timeout.
*/
function wrapHookFn(hook: GeneralScenarioHook, fixtures: ScenarioHookFixtures) {
function wrapHookFnWithTimeout(hook: GeneralScenarioHook, fixtures: ScenarioHookFixtures) {
const { timeout } = hook.options;
const { $bddContext } = fixtures;
const fixturesArg = {
Expand Down
47 changes: 39 additions & 8 deletions src/hooks/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@

import { WorkerInfo } from '@playwright/test';
import { fixtureParameterNames } from '../playwright/fixtureParameterNames';
import { KeyValue, TestTypeCommon } from '../playwright/types';
import { KeyValue, PlaywrightLocation, TestTypeCommon } from '../playwright/types';
import { callWithTimeout } from '../utils';
import { getLocationByOffset } from '../playwright/getLocationInFile';
import { runStepWithLocation } from '../playwright/runStepWithLocation';

export type WorkerHookType = 'beforeAll' | 'afterAll';

type WorkerHookOptions = {
name?: string;
timeout?: number;
};

Expand All @@ -26,10 +29,11 @@ export type WorkerHook<Fixtures = object> = {
type: WorkerHookType;
options: WorkerHookOptions;
fn: WorkerHookFn<Fixtures>;
location: PlaywrightLocation;
customTest?: TestTypeCommon;
// Since playwright-bdd v8 we run worker hooks via test.beforeAll / test.afterAll in each test file,
// so we need to know if hook was executed to avoid double execution every test file.
// so we need to know if hook was executed to avoid double execution in every test file.
executed?: boolean;
customTest?: TestTypeCommon;
};

/**
Expand Down Expand Up @@ -58,18 +62,24 @@ export function createBeforeAllAfterAll<Fixtures extends KeyValue>(
type,
options: getOptionsFromArgs(args) as WorkerHookOptions,
fn: getFnFromArgs(args) as WorkerHook['fn'],
// offset = 3 b/c this call is 3 steps below the user's code
location: getLocationByOffset(3),
customTest,
});
};
}

// eslint-disable-next-line visual/complexity
export async function runWorkerHooks(type: WorkerHookType, fixtures: WorkerHookFixtures) {
export async function runWorkerHooks(
test: TestTypeCommon,
type: WorkerHookType,
fixtures: WorkerHookFixtures,
) {
const hooksToRun = getWorkerHooksToRun(type);
let error;
for (const hook of hooksToRun) {
try {
await runWorkerHook(hook, fixtures);
await runWorkerHook(test, hook, fixtures);
} catch (e) {
if (type === 'beforeAll') throw e;
if (!error) error = e;
Expand All @@ -78,11 +88,12 @@ export async function runWorkerHooks(type: WorkerHookType, fixtures: WorkerHookF
if (error) throw error;
}

async function runWorkerHook(hook: WorkerHook, fixtures: WorkerHookFixtures) {
async function runWorkerHook(test: TestTypeCommon, hook: WorkerHook, fixtures: WorkerHookFixtures) {
if (!hook.executed) {
hook.executed = true;
const { timeout } = hook.options;
await callWithTimeout(() => hook.fn(fixtures), timeout, getTimeoutMessage(hook));
const hookFn = wrapHookFnWithTimeout(hook, fixtures);
const stepTitle = getHookStepTitle(hook);
await runStepWithLocation(test, stepTitle, hook.location, hookFn);
}
}

Expand All @@ -102,6 +113,22 @@ export function getWorkerHooksFixtureNames(hooks: WorkerHook[]) {
return [...fixtureNames];
}

/**
* Wraps hook fn with timeout.
*/
function wrapHookFnWithTimeout(hook: WorkerHook, fixtures: WorkerHookFixtures) {
const { timeout } = hook.options;

return async () => {
await callWithTimeout(
// call with null to avoid using 'this' inside worker hook
() => hook.fn.call(null, fixtures),
timeout,
getTimeoutMessage(hook),
);
};
}

function getOptionsFromArgs(args: unknown[]) {
if (typeof args[0] === 'object') return args[0];
return {};
Expand All @@ -124,3 +151,7 @@ function getTimeoutMessage(hook: WorkerHook) {
const { timeout } = hook.options;
return `${hook.type} hook timeout (${timeout} ms)`;
}

function getHookStepTitle(hook: WorkerHook) {
return hook.options.name || (hook.type === 'beforeAll' ? 'BeforeAll hook' : 'AfterAll hook');
}
4 changes: 3 additions & 1 deletion test/reporter-data/features/steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { createBdd } from 'playwright-bdd';
import { test } from './fixtures';

const { Given, When, Before, BeforeAll } = createBdd(test);
const { Given, When, Before, BeforeAll, AfterAll } = createBdd(test);

Given('background step', async () => {});
Given('I am on home page', async ({ myPage }) => {
Expand All @@ -12,3 +12,5 @@ When('Action {int}', () => {});
Before({ name: 'hook 1' }, async () => {});
Before(async () => {});
BeforeAll(async () => {});
BeforeAll({ name: 'named BeforeAll hook' }, async () => {});
AfterAll({ name: 'named AfterAll hook' }, async () => {});
5 changes: 4 additions & 1 deletion test/reporter-data/test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ function checkStepLocations(output) {
);

expect(output).toContain(`Before Hooks :0:0`);
// todo: add named beforeAll hook
expect(output).toContain(`BeforeAll Hooks`);
expect(output).toContain(`BeforeAll hook ${normalize('features/steps.ts')}:14:1`);
expect(output).toContain(`named BeforeAll hook ${normalize('features/steps.ts')}:15:1`);
expect(output).toContain(`named AfterAll hook ${normalize('features/steps.ts')}:16:1`);

expect(output).toContain(`BeforeEach Hooks`);
expect(output).toContain(`hook 1 ${normalize('features/steps.ts')}:12:1`);
expect(output).toContain(`BeforeEach hook ${normalize('features/steps.ts')}:13:1`);
Expand Down

0 comments on commit 5ff63c6

Please sign in to comment.