Skip to content

Commit b3aaac5

Browse files
Rework hooks (#23)
* reworked hooks via playwright hooks * display proper location in sources
1 parent d41abde commit b3aaac5

File tree

5 files changed

+118
-66
lines changed

5 files changed

+118
-66
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
1010
:pencil: - chore
1111
:microscope: - experimental
1212

13+
## [1.2.0]
14+
- :rocket: reworked hooks via playwright hooks
15+
- :rocket: display proper location in sources
16+
1317
## [1.1.1]
1418
- :beetle: fixed issue with After hooks execution in case of failed test
1519

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@qavajs/playwright-runner-adapter",
3-
"version": "1.1.1",
3+
"version": "1.2.0",
44
"description": "adapter for playwright test runner",
55
"scripts": {
66
"build": "tsc",

src/cucumber.spec.ts

Lines changed: 109 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,23 @@ function log(data: any) {
99
function attach(this: { test: any }, body: any, details: any) {
1010
const fileName = details.fileName ?? 'attachment';
1111
const contentType = details.mediaType ?? 'text/plain';
12-
this.test.info().attach(fileName, {body, contentType});
12+
this.test.info().attach(fileName, { body, contentType });
1313
}
1414

1515
const fixture = new supportCodeLibrary.World({});
1616
const test = fixture.test;
1717

18-
const stepHandler = test.expect.extend({
19-
async execute(fn: () => Promise<any>) {
20-
try {
21-
await fn();
22-
return {
23-
pass: true,
24-
message: () => ''
25-
}
26-
} catch (e: any) {
27-
return {
28-
pass: false,
29-
message: () => e.message,
30-
}
31-
}
18+
test.beforeAll(async () => {
19+
for (const beforeAllHook of supportCodeLibrary.beforeTestRunHookDefinitions) {
20+
const location = { location: { column: 1, file: beforeAllHook.uri, line: beforeAllHook.line }}
21+
await test.step(
22+
'Before All',
23+
() => beforeAllHook.code.apply({}),
24+
location
25+
)
3226
}
3327
});
3428

35-
for (const beforeAllHook of supportCodeLibrary.beforeTestRunHookDefinitions) {
36-
test.beforeAll(() => beforeAllHook.code.apply({}));
37-
}
38-
3929
for (const feature of features) {
4030
const tests = feature.tests;
4131
test.describe(feature.feature as string, async () => {
@@ -45,73 +35,130 @@ for (const feature of features) {
4535
supportCodeLibrary
4636
});
4737

48-
test.beforeEach(world.init);
38+
test.beforeEach('Fixtures', world.init);
39+
40+
test.beforeEach('Before Hooks', async () => {
41+
const testId = test
42+
.info()
43+
.annotations
44+
.find((annotation: { type: string }) => annotation.type === 'testId')
45+
.description;
46+
const testCase = tests.find(test => test.id === testId);
47+
for (const beforeHook of supportCodeLibrary.beforeTestCaseHookDefinitions) {
48+
if (beforeHook.appliesToTestCase(testCase)) {
49+
const hookName = beforeHook.name ?? 'Before';
50+
const location = { location: { column: 1, file: beforeHook.uri, line: beforeHook.line }}
51+
await test.step(
52+
hookName,
53+
() => beforeHook.code.apply(world, [{
54+
pickle: testCase
55+
}]),
56+
location
57+
);
58+
}
59+
}
60+
});
4961

5062
for (const testCase of tests) {
5163
const tag = testCase.tags.map((tag: { name: string }) => tag.name);
52-
test(testCase.name, {tag}, async () => {
64+
const annotation = [
65+
{ type: 'name', description: testCase.name },
66+
{ type: 'testId', description: testCase.id },
67+
{ type: 'tags', description: JSON.stringify(testCase.tags) }
68+
];
69+
test(testCase.name, { tag, annotation: annotation }, async () => {
5370
const testInfo = test.info();
54-
const result: { status: string, error?: any } = { status: 'passed' };
55-
for (const beforeHook of supportCodeLibrary.beforeTestCaseHookDefinitions) {
56-
if (beforeHook.appliesToTestCase(testCase)) {
57-
const hookName = beforeHook.name ?? 'Before';
58-
await test.step(hookName, () => beforeHook.code.apply(world, [{
59-
pickle: testCase
60-
}]));
61-
}
62-
}
71+
testInfo.result = { status: 'passed' };
6372
for (const pickleStep of testCase.steps) {
6473
if (testInfo.error) {
6574
break;
6675
}
76+
const steps = supportCodeLibrary.stepDefinitions
77+
.filter(stepDefinition => stepDefinition.matchesStepName(pickleStep.text));
78+
if (steps.length === 0) throw new Error(`Step '${pickleStep.text}' is not defined`);
79+
if (steps.length > 1) throw new Error(`'${pickleStep.text}' matches multiple step definitions`);
80+
const [ step ] = steps;
81+
const location = { location: { column: 1, file: step.uri, line: step.line }}
6782
await test.step(pickleStep.text, async () => {
6883
for (const beforeStep of supportCodeLibrary.beforeTestStepHookDefinitions) {
6984
if (beforeStep.appliesToTestCase(testCase)) {
70-
await test.step('Before Step', () => beforeStep.code.apply(world, [{
71-
pickle: testCase,
72-
pickleStep
73-
}]));
85+
const location = { location: { column: 1, file: beforeStep.uri, line: beforeStep.line }}
86+
await test.step(
87+
'Before Step',
88+
() => beforeStep.code.apply(world, [{
89+
pickle: testCase,
90+
pickleStep
91+
}]),
92+
location
93+
);
7494
}
7595
}
76-
const steps = supportCodeLibrary.stepDefinitions
77-
.filter(stepDefinition => stepDefinition.matchesStepName(pickleStep.text));
78-
if (steps.length === 0) throw new Error(`Step '${pickleStep.text}' is not defined`);
79-
if (steps.length > 1) throw new Error(`'${pickleStep.text}' matches multiple step definitions`);
80-
const [step] = steps;
81-
const {parameters} = await step.getInvocationParameters({
96+
const { parameters } = await step.getInvocationParameters({
8297
step: {
8398
text: pickleStep.text,
8499
argument: pickleStep.argument
85100
},
86101
world
87102
} as any);
88-
await stepHandler
89-
.soft(() => step.code.apply(world, parameters), 'Step')
90-
.execute();
91-
for (const afterStep of supportCodeLibrary.afterTestStepHookDefinitions) {
92-
if (afterStep.appliesToTestCase(testCase)) {
93-
await test.step('After Step', () => afterStep.code.apply(world, [{
94-
pickle: testCase,
95-
pickleStep,
96-
result
97-
}]));
103+
try {
104+
await step.code.apply(world, parameters);
105+
} catch (err: any) {
106+
testInfo.result.error = err;
107+
throw err;
108+
} finally {
109+
for (const afterStep of supportCodeLibrary.afterTestStepHookDefinitions) {
110+
if (afterStep.appliesToTestCase(testCase)) {
111+
const location = { location: { column: 1, file: afterStep.uri, line: afterStep.line }}
112+
await test.step(
113+
'After Step',
114+
() => afterStep.code.apply(world, [{
115+
pickle: testCase,
116+
pickleStep,
117+
result: testInfo.result
118+
}]),
119+
location
120+
);
121+
}
98122
}
99123
}
100-
});
101-
}
102-
for (const afterHook of supportCodeLibrary.afterTestCaseHookDefinitions) {
103-
if (afterHook.appliesToTestCase(testCase)) {
104-
const hookName = afterHook.name ?? 'After';
105-
await test.step(hookName, () => afterHook.code.apply(world, [{
106-
pickle: testCase, result
107-
}]));
108-
}
124+
}, location);
109125
}
110126
})
111127
}
128+
129+
test.afterEach('After Hooks', async () => {
130+
const testInfo = test.info();
131+
const testId = testInfo
132+
.annotations
133+
.find((annotation: { type: string }) => annotation.type === 'testId')
134+
.description;
135+
const testCase = tests.find(test => test.id === testId);
136+
for (const afterHook of supportCodeLibrary.afterTestCaseHookDefinitions) {
137+
if (afterHook.appliesToTestCase(testCase)) {
138+
const hookName = afterHook.name ?? 'After';
139+
const location = { location: { column: 1, file: afterHook.uri, line: afterHook.line }}
140+
await test.step(
141+
hookName,
142+
() => afterHook.code.apply(world, [{
143+
pickle: testCase,
144+
result: testInfo.result
145+
}]),
146+
location
147+
);
148+
}
149+
}
150+
});
151+
112152
});
113153
}
114154

115-
for (const afterAllHook of supportCodeLibrary.afterTestRunHookDefinitions) {
116-
test.afterAll(() => afterAllHook.code.apply({}));
117-
}
155+
test.afterAll(async () => {
156+
for (const afterAllHook of supportCodeLibrary.afterTestRunHookDefinitions) {
157+
const location = { location: { column: 1, file: afterAllHook.uri, line: afterAllHook.line }}
158+
await test.step(
159+
'After All',
160+
() => afterAllHook.code.apply({}),
161+
location
162+
)
163+
}
164+
});

test/features/feature.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Feature: test feature
66
Scenario: simple scenario
77
Given open 'https://google.com' url
88

9+
@tag
910
Scenario Outline: simple scenario <example>
1011
Given open '<example>' url
1112

test/step_definitions/steps.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ Given('open {string} url', async function (this: ExtendedPlaywrightWorld, url) {
5454
});
5555

5656
When(/^simple step$/, async function () {
57-
console.log('pass')
57+
console.log('pass');
5858
});
5959

6060
When('data table step', async function (dataTable: DataTable) {
61-
this.expect(dataTable.raw()).toEqual([['1'], ['2']])
61+
this.expect(dataTable.raw()).toEqual([['1'], ['2']]);
6262
});
6363

6464
When('multiline step', async function (multiline: string) {
65-
this.expect(multiline).toEqual('first\nsecond')
65+
this.expect(multiline).toEqual('first\nsecond');
6666
});
6767

6868
When('log', async function () {

0 commit comments

Comments
 (0)