Skip to content

Commit

Permalink
improve hooks: run worker hooks via beforeAll/afterAll and use custom…
Browse files Browse the repository at this point in the history
… test instances from hooks
  • Loading branch information
vitalets committed Oct 25, 2024
1 parent 9fa70cf commit 6ad48f4
Show file tree
Hide file tree
Showing 20 changed files with 266 additions and 151 deletions.
22 changes: 12 additions & 10 deletions src/gen/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { DescribeConfigureOptions } from '../playwright/types';
import { toPosixPath } from '../utils/paths';
import { BDDConfig } from '../config/types';
import { ScenarioHookType } from '../hooks/scenario';
import { WorkerHookType } from '../hooks/worker';

const supportsTags = playwrightVersion >= '1.42.0';

Expand Down Expand Up @@ -68,7 +69,17 @@ export class Formatter {
const allFixturesStr = [runScenarioHooksFixture, ...fixturesNames].join(', ');
const method = type === 'before' ? 'beforeEach' : 'afterEach';
return [
`test.${method}(({ ${allFixturesStr} }) => $runScenarioHooks(${this.quoted(type)}, { ${fixturesStr} }));`,
// eslint-disable-next-line max-len
`test.${method}(({ ${allFixturesStr} }) => ${runScenarioHooksFixture}(${this.quoted(type)}, { ${fixturesStr} }));`,
];
}

workerHooksCall(type: WorkerHookType, fixturesNames: string[]) {
const runWorkerHooksFixture = '$runWorkerHooks';
const fixturesStr = fixturesNames.join(', ');
const allFixturesStr = [runWorkerHooksFixture, ...fixturesNames].join(', ');
return [
`test.${type}(({ ${allFixturesStr} }) => ${runWorkerHooksFixture}(${this.quoted(type)}, { ${fixturesStr} }));`,
];
}

Expand Down Expand Up @@ -127,15 +138,6 @@ export class Formatter {
];
}

workerHookFixtures(fixtureNames: string[]) {
if (!fixtureNames.length) return [];
const fixtures = fixtureNames.join(', ');
const scope = this.quoted('worker');
return [
`$workerHookFixtures: [({ ${fixtures} }, use) => use({ ${fixtures} }), { scope: ${scope} }],`,
];
}

worldFixture(worldFixtureName: string) {
return [`$world: ({ ${worldFixtureName} }, use) => use(${worldFixtureName}),`];
}
Expand Down
65 changes: 0 additions & 65 deletions src/gen/hooks.ts

This file was deleted.

9 changes: 4 additions & 5 deletions src/gen/testFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { KeywordsMap, getKeywordsMap } from './i18n';
import { stringifyLocation, throwIf } from '../utils';
import parseTagsExpression from '@cucumber/tag-expressions';
import { TestNode } from './testNode';
import { getWorkerHooksFixtures } from '../hooks/worker';
import { LANG_EN, isEnglish } from '../config/lang';
import { BddMetaBuilder } from './bddMetaBuilder';
import { GherkinDocumentWithPickles } from '../features/types';
Expand All @@ -39,7 +38,7 @@ import { getStepTextWithKeyword } from '../features/helpers';
import { formatDuplicateStepsMessage, StepFinder } from '../steps/finder';
import { exit } from '../utils/exit';
import { StepDefinition } from '../steps/stepDefinition';
import { Hooks } from './hooks';
import { TestFileHooks } from './testFileHooks';

type TestFileOptions = {
gherkinDocument: GherkinDocumentWithPickles;
Expand All @@ -56,7 +55,7 @@ export class TestFile {
private gherkinDocumentQuery: GherkinDocumentQuery;
private bddMetaBuilder: BddMetaBuilder;
private stepFinder: StepFinder;
private hooks: Hooks;
private hooks: TestFileHooks;

public missingSteps: MissingStep[] = [];
public featureUri: string;
Expand All @@ -68,7 +67,7 @@ export class TestFile {
this.bddMetaBuilder = new BddMetaBuilder(this.gherkinDocumentQuery);
this.featureUri = this.getFeatureUri();
this.stepFinder = new StepFinder(options.config);
this.hooks = new Hooks(this.formatter);
this.hooks = new TestFileHooks(this.formatter);
}

get gherkinDocument() {
Expand Down Expand Up @@ -162,7 +161,7 @@ export class TestFile {
...this.formatter.testFixture(),
...this.formatter.uriFixture(this.featureUri),
...this.bddMetaBuilder.getFixture(),
...this.formatter.workerHookFixtures(getWorkerHooksFixtures()),
// ...this.formatter.workerHookFixtures(getWorkerHooksFixtures()),
...(worldFixtureName ? this.formatter.worldFixture(worldFixtureName) : []),
]);

Expand Down
103 changes: 103 additions & 0 deletions src/gen/testFileHooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/**
* Collect hooks for test file.
*/

import {
GeneralScenarioHook,
getScenarioHooksFixtureNames,
getScenarioHooksToRun,
ScenarioHookType,
} from '../hooks/scenario';
import {
getWorkerHooksFixtureNames,
getWorkerHooksToRun,
WorkerHook,
WorkerHookType,
} from '../hooks/worker';
import { toBoolean } from '../utils';
import { Formatter } from './formatter';
import { TestNode } from './testNode';

export class TestFileHooks {
private beforeAll = new TestFileWorkerHooks('beforeAll', this.formatter);
private afterAll = new TestFileWorkerHooks('afterAll', this.formatter);
private before = new TestFileScenarioHooks('before', this.formatter);
private after = new TestFileScenarioHooks('after', this.formatter);

constructor(private formatter: Formatter) {}

registerHooksForTest(node: TestNode) {
if (node.isSkipped()) return;
this.beforeAll.registerHooksForTest(node);
this.afterAll.registerHooksForTest(node);
this.before.registerHooksForTest(node);
this.after.registerHooksForTest(node);
}

getCustomTests() {
return new Set([
...this.beforeAll.getCustomTests(), // prettier-ignore
...this.afterAll.getCustomTests(),
...this.before.getCustomTests(),
...this.after.getCustomTests(),
]);
}

getLines() {
const lines = [
...this.beforeAll.getLines(), // prettier-ignore
...this.afterAll.getLines(),
...this.before.getLines(),
...this.after.getLines(),
];
if (lines.length) lines.push('');
return lines;
}
}

class TestFileScenarioHooks<T extends ScenarioHookType> {
hooks = new Set<GeneralScenarioHook>();

constructor(
private type: T,
private formatter: Formatter,
) {}

registerHooksForTest(node: TestNode) {
getScenarioHooksToRun(this.type, node.tags).forEach((hook) => this.hooks.add(hook));
}

getCustomTests() {
return new Set([...this.hooks].map((hook) => hook.customTest).filter(toBoolean));
}

getLines() {
if (!this.hooks.size) return [];
const fixtureNames = getScenarioHooksFixtureNames([...this.hooks]);
return this.formatter.scenarioHooksCall(this.type, fixtureNames);
}
}

class TestFileWorkerHooks<T extends WorkerHookType> {
hooks = new Set<WorkerHook>();

constructor(
private type: T,
private formatter: Formatter,
) {}

// todo: node is not used until we add tags to worker hooks
registerHooksForTest(_node: TestNode) {
getWorkerHooksToRun(this.type).forEach((hook) => this.hooks.add(hook));
}

getCustomTests() {
return new Set([...this.hooks].map((hook) => hook.customTest).filter(toBoolean));
}

getLines() {
if (!this.hooks.size) return [];
const fixtureNames = getWorkerHooksFixtureNames([...this.hooks]);
return this.formatter.workerHooksCall(this.type, fixtureNames);
}
}
6 changes: 3 additions & 3 deletions src/hooks/scenario.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ export function scenarioHookFactory<

// eslint-disable-next-line visual/complexity
export async function runScenarioHooks(type: ScenarioHookType, fixtures: ScenarioHookFixtures) {
const scenarioHooksToRun = getScenarioHooksToRun(type, fixtures.$bddContext.tags);
const hooksToRun = getScenarioHooksToRun(type, fixtures.$bddContext.tags);

let error;
for (const hook of scenarioHooksToRun) {
for (const hook of hooksToRun) {
try {
await runScenarioHook(hook, fixtures);
} catch (e) {
Expand Down Expand Up @@ -122,7 +122,7 @@ export function getScenarioHooksToRun(type: ScenarioHookType, tags: string[] = [
}

/**
* Wraps hook fn with timeout and waiting Cucumber attachments to fulfill.
* Wraps hook fn with timeout.
*/
function wrapHookFn(hook: GeneralScenarioHook, fixtures: ScenarioHookFixtures) {
const { timeout } = hook.options;
Expand Down
Loading

0 comments on commit 6ad48f4

Please sign in to comment.