@serenity-js/playwright-test 3.31.17 → 3.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +6 -5
- package/lib/api/PlaywrightTestConfig.d.ts +7 -6
- package/lib/api/PlaywrightTestConfig.d.ts.map +1 -1
- package/lib/api/WorkerEventStreamReader.d.ts +13 -0
- package/lib/api/WorkerEventStreamReader.d.ts.map +1 -0
- package/lib/api/WorkerEventStreamReader.js +58 -0
- package/lib/api/WorkerEventStreamReader.js.map +1 -0
- package/lib/api/WorkerEventStreamWriter.d.ts +24 -0
- package/lib/api/WorkerEventStreamWriter.d.ts.map +1 -0
- package/lib/api/WorkerEventStreamWriter.js +86 -0
- package/lib/api/WorkerEventStreamWriter.js.map +1 -0
- package/lib/api/index.d.ts +1 -2
- package/lib/api/index.d.ts.map +1 -1
- package/lib/api/index.js +1 -2
- package/lib/api/index.js.map +1 -1
- package/lib/api/serenity-fixtures.d.ts +377 -0
- package/lib/api/serenity-fixtures.d.ts.map +1 -0
- package/lib/api/{SerenityOptions.js → serenity-fixtures.js} +1 -1
- package/lib/api/serenity-fixtures.js.map +1 -0
- package/lib/api/test-api.d.ts +27 -15
- package/lib/api/test-api.d.ts.map +1 -1
- package/lib/api/test-api.js +126 -104
- package/lib/api/test-api.js.map +1 -1
- package/lib/events/EventFactory.d.ts +16 -0
- package/lib/events/EventFactory.d.ts.map +1 -0
- package/lib/events/EventFactory.js +94 -0
- package/lib/events/EventFactory.js.map +1 -0
- package/lib/events/PlaywrightSceneId.d.ts +7 -0
- package/lib/events/PlaywrightSceneId.d.ts.map +1 -0
- package/lib/events/PlaywrightSceneId.js +19 -0
- package/lib/events/PlaywrightSceneId.js.map +1 -0
- package/lib/events/index.d.ts +3 -0
- package/lib/events/index.d.ts.map +1 -0
- package/lib/events/index.js +19 -0
- package/lib/events/index.js.map +1 -0
- package/lib/reporter/PlaywrightErrorParser.d.ts +7 -0
- package/lib/reporter/PlaywrightErrorParser.d.ts.map +1 -0
- package/lib/reporter/PlaywrightErrorParser.js +28 -0
- package/lib/reporter/PlaywrightErrorParser.js.map +1 -0
- package/lib/reporter/PlaywrightEventBuffer.d.ts +25 -0
- package/lib/reporter/PlaywrightEventBuffer.d.ts.map +1 -0
- package/lib/reporter/PlaywrightEventBuffer.js +147 -0
- package/lib/reporter/PlaywrightEventBuffer.js.map +1 -0
- package/lib/reporter/PlaywrightTestSceneIdFactory.d.ts +8 -0
- package/lib/reporter/PlaywrightTestSceneIdFactory.d.ts.map +1 -0
- package/lib/reporter/PlaywrightTestSceneIdFactory.js +15 -0
- package/lib/reporter/PlaywrightTestSceneIdFactory.js.map +1 -0
- package/lib/reporter/SerenityReporterForPlaywrightTest.d.ts +15 -22
- package/lib/reporter/SerenityReporterForPlaywrightTest.d.ts.map +1 -1
- package/lib/reporter/SerenityReporterForPlaywrightTest.js +62 -163
- package/lib/reporter/SerenityReporterForPlaywrightTest.js.map +1 -1
- package/lib/reporter/index.d.ts +0 -2
- package/lib/reporter/index.d.ts.map +1 -1
- package/lib/reporter/index.js +0 -2
- package/lib/reporter/index.js.map +1 -1
- package/package.json +9 -9
- package/src/api/PlaywrightTestConfig.ts +7 -6
- package/src/api/WorkerEventStreamReader.ts +27 -0
- package/src/api/WorkerEventStreamWriter.ts +117 -0
- package/src/api/index.ts +1 -2
- package/src/api/serenity-fixtures.ts +392 -0
- package/src/api/test-api.ts +187 -99
- package/src/events/EventFactory.ts +204 -0
- package/src/events/PlaywrightSceneId.ts +20 -0
- package/src/events/index.ts +2 -0
- package/src/reporter/PlaywrightErrorParser.ts +35 -0
- package/src/reporter/PlaywrightEventBuffer.ts +251 -0
- package/src/reporter/PlaywrightTestSceneIdFactory.ts +14 -0
- package/src/reporter/SerenityReporterForPlaywrightTest.ts +89 -250
- package/src/reporter/index.ts +0 -2
- package/lib/api/SerenityFixtures.d.ts +0 -130
- package/lib/api/SerenityFixtures.d.ts.map +0 -1
- package/lib/api/SerenityFixtures.js +0 -3
- package/lib/api/SerenityFixtures.js.map +0 -1
- package/lib/api/SerenityOptions.d.ts +0 -271
- package/lib/api/SerenityOptions.d.ts.map +0 -1
- package/lib/api/SerenityOptions.js.map +0 -1
- package/lib/reporter/DomainEventBuffer.d.ts +0 -11
- package/lib/reporter/DomainEventBuffer.d.ts.map +0 -1
- package/lib/reporter/DomainEventBuffer.js +0 -24
- package/lib/reporter/DomainEventBuffer.js.map +0 -1
- package/lib/reporter/PlaywrightAttachments.d.ts +0 -2
- package/lib/reporter/PlaywrightAttachments.d.ts.map +0 -1
- package/lib/reporter/PlaywrightAttachments.js +0 -5
- package/lib/reporter/PlaywrightAttachments.js.map +0 -1
- package/src/api/SerenityFixtures.ts +0 -132
- package/src/api/SerenityOptions.ts +0 -277
- package/src/reporter/DomainEventBuffer.ts +0 -28
- package/src/reporter/PlaywrightAttachments.ts +0 -1
|
@@ -1,49 +1,23 @@
|
|
|
1
1
|
import type { FullConfig } from '@playwright/test';
|
|
2
|
-
import type { Reporter, Suite, TestCase, TestError, TestResult, } from '@playwright/test/reporter';
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
Serenity,
|
|
6
|
-
StageCrewMember,
|
|
7
|
-
StageCrewMemberBuilder,
|
|
8
|
-
Timestamp,
|
|
9
|
-
} from '@serenity-js/core';
|
|
10
|
-
import { LogicError, serenity as reporterSerenityInstance, } from '@serenity-js/core';
|
|
2
|
+
import type { FullResult, Reporter, Suite, TestCase, TestError, TestResult, } from '@playwright/test/reporter';
|
|
3
|
+
import type { ClassDescription, StageCrewMember, StageCrewMemberBuilder } from '@serenity-js/core';
|
|
4
|
+
import { Clock, Duration, Serenity, Timestamp } from '@serenity-js/core';
|
|
11
5
|
import type { OutputStream } from '@serenity-js/core/lib/adapter';
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
TestRunFinished,
|
|
21
|
-
TestRunFinishes,
|
|
22
|
-
TestRunnerDetected,
|
|
23
|
-
TestRunStarts
|
|
24
|
-
} from '@serenity-js/core/lib/events';
|
|
25
|
-
import { FileSystem, FileSystemLocation, Path, RequirementsHierarchy, } from '@serenity-js/core/lib/io';
|
|
26
|
-
import type { CorrelationId, Outcome, Tag } from '@serenity-js/core/lib/model';
|
|
27
|
-
import {
|
|
28
|
-
ArbitraryTag,
|
|
29
|
-
Category,
|
|
30
|
-
ExecutionFailedWithAssertionError,
|
|
31
|
-
ExecutionFailedWithError,
|
|
32
|
-
ExecutionIgnored,
|
|
33
|
-
ExecutionRetriedTag,
|
|
34
|
-
ExecutionSkipped,
|
|
35
|
-
ExecutionSuccessful,
|
|
36
|
-
Name,
|
|
37
|
-
ScenarioDetails,
|
|
38
|
-
Tags,
|
|
39
|
-
} from '@serenity-js/core/lib/model';
|
|
40
|
-
|
|
41
|
-
import { SERENITY_JS_DOMAIN_EVENTS_ATTACHMENT_CONTENT_TYPE } from './PlaywrightAttachments';
|
|
6
|
+
import { TestRunFinished, TestRunFinishes, TestRunStarts } from '@serenity-js/core/lib/events';
|
|
7
|
+
import { ExecutionFailedWithError, ExecutionSuccessful, } from '@serenity-js/core/lib/model';
|
|
8
|
+
|
|
9
|
+
import { PlaywrightErrorParser } from './PlaywrightErrorParser';
|
|
10
|
+
import { PlaywrightEventBuffer } from './PlaywrightEventBuffer';
|
|
11
|
+
import { PlaywrightTestSceneIdFactory } from './PlaywrightTestSceneIdFactory';
|
|
12
|
+
|
|
13
|
+
type HookType = 'beforeAll' | 'afterAll' | 'beforeEach' | 'afterEach';
|
|
42
14
|
|
|
43
15
|
/**
|
|
44
16
|
* Configuration object accepted by `@serenity-js/playwright-test` reporter.
|
|
45
17
|
*
|
|
46
|
-
*
|
|
18
|
+
* For usage examples, see:
|
|
19
|
+
* - [`SerenityFixtures`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/)
|
|
20
|
+
* - [`SerenityWorkerFixtures`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/)
|
|
47
21
|
*/
|
|
48
22
|
export interface SerenityReporterForPlaywrightTestConfig {
|
|
49
23
|
/**
|
|
@@ -52,7 +26,7 @@ export interface SerenityReporterForPlaywrightTestConfig {
|
|
|
52
26
|
* Note that the `crew` can also be configured using [class descriptions](https://serenity-js.org/api/core/#ClassDescription).
|
|
53
27
|
*
|
|
54
28
|
* #### Learn more
|
|
55
|
-
* - [`
|
|
29
|
+
* - [`SerenityFixtures`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/)
|
|
56
30
|
* - [`SerenityConfig.crew`](https://serenity-js.org/api/core/class/SerenityConfig/#crew)
|
|
57
31
|
*/
|
|
58
32
|
crew?: Array<StageCrewMember | StageCrewMemberBuilder | ClassDescription>;
|
|
@@ -74,113 +48,101 @@ export interface SerenityReporterForPlaywrightTestConfig {
|
|
|
74
48
|
* Serenity/JS [stage crew members](https://serenity-js.org/api/core/interface/StageCrewMember/).
|
|
75
49
|
*/
|
|
76
50
|
export class SerenityReporterForPlaywrightTest implements Reporter {
|
|
77
|
-
private errorParser = new PlaywrightErrorParser();
|
|
78
|
-
|
|
51
|
+
private readonly errorParser = new PlaywrightErrorParser();
|
|
52
|
+
|
|
53
|
+
private readonly sceneIdFactory: PlaywrightTestSceneIdFactory;
|
|
54
|
+
private readonly serenity: Serenity;
|
|
79
55
|
private unhandledError?: Error;
|
|
80
56
|
|
|
57
|
+
private readonly eventBuffer: PlaywrightEventBuffer = new PlaywrightEventBuffer();
|
|
58
|
+
private readonly suiteTestCounts = new Map<Suite, number>();
|
|
59
|
+
|
|
81
60
|
/**
|
|
82
61
|
* @param config
|
|
83
|
-
* @param serenity
|
|
84
|
-
* Instance of [`Serenity`](https://serenity-js.org/api/core/class/Serenity/), specific to the Node process running this Serenity reporter.
|
|
85
|
-
* Note that Playwright runs test workers and reporters in separate processes.
|
|
86
|
-
* @param requirementsHierarchy
|
|
87
|
-
* Root directory of the requirements hierarchy, used to determine capabilities and themes.
|
|
88
62
|
*/
|
|
89
|
-
constructor(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
new
|
|
94
|
-
|
|
95
|
-
|
|
63
|
+
constructor(config: SerenityReporterForPlaywrightTestConfig) {
|
|
64
|
+
this.sceneIdFactory = new PlaywrightTestSceneIdFactory();
|
|
65
|
+
|
|
66
|
+
this.serenity = new Serenity(
|
|
67
|
+
new Clock(),
|
|
68
|
+
process.cwd(),
|
|
69
|
+
this.sceneIdFactory,
|
|
70
|
+
)
|
|
96
71
|
this.serenity.configure(config);
|
|
97
72
|
}
|
|
98
73
|
|
|
99
74
|
onBegin(config: FullConfig, suite: Suite): void {
|
|
100
|
-
this.
|
|
101
|
-
|
|
102
|
-
);
|
|
75
|
+
this.eventBuffer.configure(config);
|
|
76
|
+
this.serenity.announce(new TestRunStarts(this.serenity.currentTime()));
|
|
103
77
|
|
|
104
|
-
this.
|
|
78
|
+
this.countTestsPerSuite(suite);
|
|
105
79
|
}
|
|
106
80
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const tags: Tag[] = [
|
|
115
|
-
... scenarioTags,
|
|
116
|
-
... test.tags.flatMap(tag => Tags.from(tag)),
|
|
117
|
-
];
|
|
118
|
-
|
|
119
|
-
this.emit(
|
|
120
|
-
new SceneStarts(currentSceneId, scenarioDetails, this.serenity.currentTime()),
|
|
81
|
+
private countTestsPerSuite(suite: Suite): void {
|
|
82
|
+
suite.allTests().forEach(test => {
|
|
83
|
+
let currentSuite: Suite | undefined = test.parent;
|
|
84
|
+
while (currentSuite) {
|
|
85
|
+
const count = this.suiteTestCounts.get(currentSuite) ?? 0;
|
|
86
|
+
this.suiteTestCounts.set(currentSuite, count + 1);
|
|
121
87
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
new TestRunnerDetected(
|
|
127
|
-
currentSceneId,
|
|
128
|
-
new Name('Playwright'),
|
|
129
|
-
this.serenity.currentTime(),
|
|
130
|
-
),
|
|
88
|
+
currentSuite = currentSuite.parent;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
131
92
|
|
|
132
|
-
|
|
133
|
-
);
|
|
93
|
+
onTestBegin(test: TestCase, result: TestResult): void {
|
|
94
|
+
this.eventBuffer.appendTestStart(test, result);
|
|
134
95
|
}
|
|
135
96
|
|
|
136
97
|
// TODO might be nice to support that by emitting TestStepStarted / Finished
|
|
137
98
|
// onStepBegin(test: TestCase, _result: TestResult, step: TestStep): void {
|
|
138
99
|
// // console.log('>> onStepBegin');
|
|
139
100
|
// }
|
|
101
|
+
// todo: add stdout -> Log https://github.com/microsoft/playwright/blob/main/packages/playwright/src/reporters/list.ts#L67
|
|
140
102
|
|
|
141
103
|
// onStepEnd(test: TestCase, _result: TestResult, step: TestStep): void {
|
|
142
104
|
// // console.log('>> onStepEnd');
|
|
143
105
|
// }
|
|
144
106
|
|
|
145
107
|
onTestEnd(test: TestCase, result: TestResult): void {
|
|
146
|
-
this.announceRetryIfNeeded(test, result);
|
|
147
108
|
|
|
148
|
-
const
|
|
109
|
+
const pendingAfterAllHooks = this.countPendingAfterAllHooks(test);
|
|
149
110
|
|
|
150
|
-
|
|
111
|
+
if (test.retries > 0) {
|
|
112
|
+
this.eventBuffer.appendRetryableSceneEvents(test, result);
|
|
113
|
+
}
|
|
151
114
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
115
|
+
this.eventBuffer.appendCrashedWorkerEvents(test, result);
|
|
116
|
+
this.eventBuffer.appendSceneEvents(test, result);
|
|
156
117
|
|
|
157
|
-
|
|
118
|
+
if (pendingAfterAllHooks === 0) {
|
|
119
|
+
this.eventBuffer.appendSceneFinishedEvent(test, result)
|
|
158
120
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
121
|
+
const events = this.eventBuffer.flush(test, result);
|
|
122
|
+
|
|
123
|
+
this.serenity.announce(...events);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
this.eventBuffer.deferAppendingSceneFinishedEvent(test, result);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
163
129
|
|
|
164
|
-
|
|
130
|
+
private countPendingAfterAllHooks(test: TestCase): number {
|
|
131
|
+
let currentSuite: Suite | undefined = test.parent;
|
|
132
|
+
const pendingAfterAllHooks: Suite[] = [];
|
|
165
133
|
|
|
166
|
-
|
|
134
|
+
while (currentSuite) {
|
|
135
|
+
const remainingSuites = (this.suiteTestCounts.get(currentSuite) || 0) - 1;
|
|
136
|
+
this.suiteTestCounts.set(currentSuite, remainingSuites);
|
|
167
137
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
138
|
+
if (remainingSuites === 0 && currentSuite['_hooks'].some((hook: { type: HookType }) => hook.type === 'afterAll')) {
|
|
139
|
+
pendingAfterAllHooks.push(currentSuite);
|
|
171
140
|
}
|
|
172
|
-
}
|
|
173
141
|
|
|
174
|
-
|
|
142
|
+
currentSuite = currentSuite.parent;
|
|
143
|
+
}
|
|
175
144
|
|
|
176
|
-
|
|
177
|
-
new SceneFinished(
|
|
178
|
-
currentSceneId,
|
|
179
|
-
this.scenarioDetailsFrom(test).scenarioDetails,
|
|
180
|
-
this.determineScenarioOutcome(worstInteractionOutcome, scenarioOutcome),
|
|
181
|
-
this.now(),
|
|
182
|
-
),
|
|
183
|
-
);
|
|
145
|
+
return pendingAfterAllHooks.length;
|
|
184
146
|
}
|
|
185
147
|
|
|
186
148
|
onError(error: TestError): void {
|
|
@@ -189,173 +151,50 @@ export class SerenityReporterForPlaywrightTest implements Reporter {
|
|
|
189
151
|
}
|
|
190
152
|
}
|
|
191
153
|
|
|
192
|
-
|
|
193
|
-
worstInteractionOutcome: Outcome,
|
|
194
|
-
scenarioOutcome: Outcome,
|
|
195
|
-
): Outcome {
|
|
196
|
-
if (worstInteractionOutcome instanceof ExecutionFailedWithAssertionError) {
|
|
197
|
-
return worstInteractionOutcome;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return worstInteractionOutcome.isWorseThan(scenarioOutcome)
|
|
201
|
-
? worstInteractionOutcome
|
|
202
|
-
: scenarioOutcome;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
private outcomeFrom(test: TestCase, result: TestResult): Outcome {
|
|
206
|
-
const outcome = test.outcome();
|
|
207
|
-
|
|
208
|
-
if (outcome === 'skipped') {
|
|
209
|
-
return new ExecutionSkipped();
|
|
210
|
-
}
|
|
154
|
+
async onEnd(fullResult: FullResult): Promise<void> {
|
|
211
155
|
|
|
212
|
-
|
|
213
|
-
return new ExecutionFailedWithError(
|
|
214
|
-
new LogicError(`Scenario expected to fail, but ${ result.status }`),
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if ([ 'failed', 'interrupted', 'timedOut' ].includes(result.status)) {
|
|
219
|
-
if (test.retries > result.retry) {
|
|
220
|
-
return new ExecutionIgnored(this.errorParser.errorFrom(result.error));
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
return new ExecutionFailedWithError(
|
|
224
|
-
this.errorParser.errorFrom(result.error),
|
|
225
|
-
);
|
|
226
|
-
}
|
|
156
|
+
const deferredEvents = this.eventBuffer.flushAllDeferred();
|
|
227
157
|
|
|
228
|
-
|
|
229
|
-
|
|
158
|
+
this.serenity.announce(
|
|
159
|
+
...deferredEvents,
|
|
160
|
+
);
|
|
230
161
|
|
|
231
|
-
|
|
232
|
-
const
|
|
233
|
-
root_,
|
|
234
|
-
browserName_,
|
|
235
|
-
fileName,
|
|
236
|
-
describeOrItBlockTitle,
|
|
237
|
-
...nestedTitles
|
|
238
|
-
] = test.titlePath();
|
|
239
|
-
|
|
240
|
-
const path = new Path(test.location.file);
|
|
241
|
-
const scenarioName = nestedTitles.join(' ').trim();
|
|
242
|
-
|
|
243
|
-
const name = scenarioName || describeOrItBlockTitle;
|
|
244
|
-
const featureName = scenarioName ? describeOrItBlockTitle : fileName;
|
|
245
|
-
|
|
246
|
-
return {
|
|
247
|
-
scenarioDetails: new ScenarioDetails(
|
|
248
|
-
new Name(Tags.stripFrom(name)),
|
|
249
|
-
new Category(Tags.stripFrom(featureName)),
|
|
250
|
-
new FileSystemLocation(path, test.location.line, test.location.column),
|
|
251
|
-
),
|
|
252
|
-
scenarioTags: Tags.from(`${ featureName } ${ name }`),
|
|
253
|
-
};
|
|
254
|
-
}
|
|
162
|
+
const fullDuration = Duration.ofMilliseconds(Math.round(fullResult.duration));
|
|
163
|
+
const endTime = new Timestamp(fullResult.startTime).plus(fullDuration);
|
|
255
164
|
|
|
256
|
-
|
|
257
|
-
this.serenity.announce(new TestRunFinishes(this.serenity.currentTime()));
|
|
165
|
+
this.serenity.announce(new TestRunFinishes(endTime));
|
|
258
166
|
|
|
259
167
|
try {
|
|
260
168
|
await this.serenity.waitForNextCue();
|
|
261
169
|
|
|
262
|
-
const outcome = this.unhandledError
|
|
263
|
-
new ExecutionFailedWithError(this.unhandledError)
|
|
170
|
+
const outcome = this.unhandledError
|
|
171
|
+
? new ExecutionFailedWithError(this.unhandledError)
|
|
264
172
|
: new ExecutionSuccessful();
|
|
265
173
|
|
|
266
174
|
this.serenity.announce(
|
|
267
175
|
new TestRunFinished(
|
|
268
176
|
outcome,
|
|
269
|
-
|
|
177
|
+
endTime,
|
|
270
178
|
),
|
|
271
179
|
);
|
|
272
|
-
}
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
273
182
|
this.serenity.announce(
|
|
274
183
|
new TestRunFinished(
|
|
275
184
|
new ExecutionFailedWithError(error),
|
|
276
|
-
|
|
185
|
+
endTime,
|
|
277
186
|
),
|
|
278
187
|
);
|
|
188
|
+
|
|
279
189
|
throw error;
|
|
280
190
|
}
|
|
281
191
|
}
|
|
282
192
|
|
|
283
|
-
// TODO emit a text artifact with stdout
|
|
193
|
+
// TODO emit a text artifact with stdout
|
|
284
194
|
// reporter.onStdErr(chunk, test, result)
|
|
285
195
|
// reporter.onStdOut(chunk, test, result)
|
|
286
196
|
|
|
287
|
-
private emit(...events: DomainEvent[]): void {
|
|
288
|
-
events.forEach((event) => {
|
|
289
|
-
this.serenity.announce(event);
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
private announceRetryIfNeeded(test: TestCase, result: TestResult): void {
|
|
294
|
-
if (test.retries === 0) {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
const currentSceneId = this.sceneIds.get(test.id);
|
|
299
|
-
|
|
300
|
-
this.emit(
|
|
301
|
-
new RetryableSceneDetected(currentSceneId, this.now()),
|
|
302
|
-
new SceneTagged(
|
|
303
|
-
currentSceneId,
|
|
304
|
-
new ArbitraryTag('retried'), // todo: replace with a dedicated tag
|
|
305
|
-
this.now(),
|
|
306
|
-
),
|
|
307
|
-
);
|
|
308
|
-
|
|
309
|
-
if (result.retry > 0) {
|
|
310
|
-
this.emit(
|
|
311
|
-
new SceneTagged(
|
|
312
|
-
currentSceneId,
|
|
313
|
-
new ExecutionRetriedTag(result.retry),
|
|
314
|
-
this.serenity.currentTime(),
|
|
315
|
-
),
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
private now(): Timestamp {
|
|
321
|
-
return this.serenity.currentTime();
|
|
322
|
-
}
|
|
323
|
-
|
|
324
197
|
printsToStdio(): boolean {
|
|
325
198
|
return true;
|
|
326
199
|
}
|
|
327
200
|
}
|
|
328
|
-
|
|
329
|
-
class PlaywrightErrorParser {
|
|
330
|
-
private static ascii = new RegExp(
|
|
331
|
-
'[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))', // eslint-disable-line no-control-regex
|
|
332
|
-
'g',
|
|
333
|
-
);
|
|
334
|
-
|
|
335
|
-
public errorFrom(testError: TestError): Error {
|
|
336
|
-
const message = testError.message && PlaywrightErrorParser.stripAsciiFrom(testError.message);
|
|
337
|
-
|
|
338
|
-
let stack = testError.stack && PlaywrightErrorParser.stripAsciiFrom(testError.stack);
|
|
339
|
-
|
|
340
|
-
// TODO: Do I need to process it?
|
|
341
|
-
// const value = testError.value;
|
|
342
|
-
|
|
343
|
-
const prologue = `Error: ${ message }`;
|
|
344
|
-
if (stack && message && stack.startsWith(prologue)) {
|
|
345
|
-
stack = stack.slice(prologue.length);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
if (testError.cause) {
|
|
349
|
-
stack += `\nCaused by: ${ this.errorFrom(testError.cause).stack }`;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const error = new Error(message);
|
|
353
|
-
error.stack = stack;
|
|
354
|
-
|
|
355
|
-
return error;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
private static stripAsciiFrom(text: string): string {
|
|
359
|
-
return text.replace(this.ascii, '');
|
|
360
|
-
}
|
|
361
|
-
}
|
package/src/reporter/index.ts
CHANGED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import type { Actor, Cast, Serenity } from '@serenity-js/core';
|
|
2
|
-
/**
|
|
3
|
-
* Serenity/JS-specific [Playwright Test fixtures](https://playwright.dev/docs/test-fixtures)
|
|
4
|
-
* injected into your [test scenarios](https://serenity-js.org/api/playwright-test/function/it/).
|
|
5
|
-
*
|
|
6
|
-
* ## Example test scenario
|
|
7
|
-
*
|
|
8
|
-
* ```typescript
|
|
9
|
-
* import { Ensure, equals } from '@serenity-js/assertions'
|
|
10
|
-
* import { describe, it, test } from '@serenity-js/playwright-test'
|
|
11
|
-
* import { Photographer, TakePhotosOfFailures } from '@serenity-js/web'
|
|
12
|
-
*
|
|
13
|
-
* describe(`Recording items`, () => {
|
|
14
|
-
*
|
|
15
|
-
* test.use({
|
|
16
|
-
* defaultActorName: 'Serena',
|
|
17
|
-
* crew: [
|
|
18
|
-
* Photographer.whoWill(TakePhotosOfFailures),
|
|
19
|
-
* ],
|
|
20
|
-
* })
|
|
21
|
-
*
|
|
22
|
-
* describe(`Todo List App`, () => {
|
|
23
|
-
*
|
|
24
|
-
* it(`should allow me to add a todo item`, async ({ actor }) => {
|
|
25
|
-
* await actor.attemptsTo(
|
|
26
|
-
* startWithAnEmptyList(),
|
|
27
|
-
*
|
|
28
|
-
* recordItem('Buy some milk'),
|
|
29
|
-
*
|
|
30
|
-
* Ensure.that(itemNames(), equals([
|
|
31
|
-
* 'Buy some milk',
|
|
32
|
-
* ])),
|
|
33
|
-
* )
|
|
34
|
-
* })
|
|
35
|
-
* })
|
|
36
|
-
* })
|
|
37
|
-
* ```
|
|
38
|
-
*
|
|
39
|
-
* ## Learn more
|
|
40
|
-
* - Declaring a Serenity/JS [test scenario](https://serenity-js.org/api/playwright-test/function/it/)
|
|
41
|
-
* - [Grouping test scenarios](https://serenity-js.org/api/playwright-test/function/describe/)
|
|
42
|
-
* - [Serenity/JS + Playwright Test project template](https://github.com/serenity-js/serenity-js-playwright-test-template/)
|
|
43
|
-
*/
|
|
44
|
-
export interface SerenityFixtures {
|
|
45
|
-
/**
|
|
46
|
-
* Retrieves the root object of the Serenity/JS framework.
|
|
47
|
-
*/
|
|
48
|
-
serenity: Serenity;
|
|
49
|
-
/**
|
|
50
|
-
* Name and version of the operating system that Playwright Test worker process runs on.
|
|
51
|
-
*/
|
|
52
|
-
platform: {
|
|
53
|
-
name: string;
|
|
54
|
-
version: string;
|
|
55
|
-
};
|
|
56
|
-
/**
|
|
57
|
-
* A cast of Serenity/JS actors to be used instead of the default cast
|
|
58
|
-
* when instantiating [`actor`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#actor)
|
|
59
|
-
* and invoking [`actorCalled`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#actorCalled).
|
|
60
|
-
*
|
|
61
|
-
* #### Overriding the default cast of Serenity/JS actors
|
|
62
|
-
*
|
|
63
|
-
* ```typescript
|
|
64
|
-
* import { Cast, TakeNotes } from '@serenity-js/core'
|
|
65
|
-
* import { Ensure, equals } from '@serenity-js/assertions'
|
|
66
|
-
* import { BrowseTheWebWithPlaywright } from '@serenity-js/playwright'
|
|
67
|
-
* import { describe, it, test } from '@serenity-js/playwright-test'
|
|
68
|
-
*
|
|
69
|
-
* describe(`Recording items`, () => {
|
|
70
|
-
*
|
|
71
|
-
* test.use({
|
|
72
|
-
* defaultActorName: 'Serena',
|
|
73
|
-
* actors: ({ browser, contextOptions }, use) => {
|
|
74
|
-
* const cast = Cast.where(actor =>
|
|
75
|
-
* actor.whoCan(
|
|
76
|
-
* BrowseTheWebWithPlaywright.using(browser, contextOptions),
|
|
77
|
-
* TakeNotes.usingAnEmptyNotepad(),
|
|
78
|
-
* )
|
|
79
|
-
* )
|
|
80
|
-
*
|
|
81
|
-
* // Make sure to pass your custom cast to Playwright `use` callback
|
|
82
|
-
* use(cast)
|
|
83
|
-
* },
|
|
84
|
-
* })
|
|
85
|
-
*
|
|
86
|
-
* describe(`Todo List App`, () => {
|
|
87
|
-
*
|
|
88
|
-
* it(`should allow me to add a todo item`, async ({ actor }) => {
|
|
89
|
-
* await actor.attemptsTo(
|
|
90
|
-
* startWithAnEmptyList(),
|
|
91
|
-
*
|
|
92
|
-
* recordItem('Buy some milk'),
|
|
93
|
-
*
|
|
94
|
-
* Ensure.that(itemNames(), equals([
|
|
95
|
-
* 'Buy some milk',
|
|
96
|
-
* ])),
|
|
97
|
-
* )
|
|
98
|
-
* })
|
|
99
|
-
* })
|
|
100
|
-
* })
|
|
101
|
-
* ```
|
|
102
|
-
*/
|
|
103
|
-
actors: Cast;
|
|
104
|
-
/**
|
|
105
|
-
* Uses the provided [cast](https://serenity-js.org/api/core/class/Cast/) of [`actors`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#actors) to instantiate an [`Actor`](https://serenity-js.org/api/core/class/Actor/) called `name`
|
|
106
|
-
* and inject it into a [test scenario](https://serenity-js.org/api/playwright-test/function/it/).
|
|
107
|
-
*
|
|
108
|
-
* Retrieves an existing actor if one has already been instantiated.
|
|
109
|
-
*
|
|
110
|
-
* #### Learn more
|
|
111
|
-
* - Declaring a Serenity/JS [test scenario](https://serenity-js.org/api/playwright-test/function/it/)
|
|
112
|
-
* - [`SerenityOptions.actors`](https://serenity-js.org/api/playwright-test/interface/SerenityOptions/#actors)
|
|
113
|
-
* - [`SerenityFixtures.actors`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#actors)
|
|
114
|
-
*
|
|
115
|
-
* @param name
|
|
116
|
-
*/
|
|
117
|
-
actorCalled: (name: string) => Actor;
|
|
118
|
-
/**
|
|
119
|
-
* Default [`actor`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#actor) injected into a [test scenario](https://serenity-js.org/api/playwright-test/function/it/).
|
|
120
|
-
*
|
|
121
|
-
* Using `actor` fixture is equivalent to invoking [`actorCalled`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#actorCalled) with [`defaultActorName`](https://serenity-js.org/api/playwright-test/interface/SerenityOptions/#defaultActorName).
|
|
122
|
-
*
|
|
123
|
-
* #### Learn more
|
|
124
|
-
* - [`actorCalled`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#actorCalled)
|
|
125
|
-
* - [`SerenityOptions.defaultActorName`](https://serenity-js.org/api/playwright-test/interface/SerenityOptions/#defaultActorName)
|
|
126
|
-
* - Declaring a Serenity/JS [test scenario](https://serenity-js.org/api/playwright-test/function/it/)
|
|
127
|
-
*/
|
|
128
|
-
actor: Actor;
|
|
129
|
-
}
|
|
130
|
-
//# sourceMappingURL=SerenityFixtures.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SerenityFixtures.d.ts","sourceRoot":"","sources":["../../src/api/SerenityFixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,MAAM,WAAW,gBAAgB;IAE7B;;OAEG;IACH,QAAQ,EAAE,QAAQ,CAAC;IAEnB;;OAEG;IACH,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8CG;IACH,MAAM,EAAE,IAAI,CAAC;IAEb;;;;;;;;;;;;OAYG;IACH,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;IAErC;;;;;;;;;OASG;IACH,KAAK,EAAE,KAAK,CAAC;CAChB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SerenityFixtures.js","sourceRoot":"","sources":["../../src/api/SerenityFixtures.ts"],"names":[],"mappings":""}
|