@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.
Files changed (90) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +6 -5
  3. package/lib/api/PlaywrightTestConfig.d.ts +7 -6
  4. package/lib/api/PlaywrightTestConfig.d.ts.map +1 -1
  5. package/lib/api/WorkerEventStreamReader.d.ts +13 -0
  6. package/lib/api/WorkerEventStreamReader.d.ts.map +1 -0
  7. package/lib/api/WorkerEventStreamReader.js +58 -0
  8. package/lib/api/WorkerEventStreamReader.js.map +1 -0
  9. package/lib/api/WorkerEventStreamWriter.d.ts +24 -0
  10. package/lib/api/WorkerEventStreamWriter.d.ts.map +1 -0
  11. package/lib/api/WorkerEventStreamWriter.js +86 -0
  12. package/lib/api/WorkerEventStreamWriter.js.map +1 -0
  13. package/lib/api/index.d.ts +1 -2
  14. package/lib/api/index.d.ts.map +1 -1
  15. package/lib/api/index.js +1 -2
  16. package/lib/api/index.js.map +1 -1
  17. package/lib/api/serenity-fixtures.d.ts +377 -0
  18. package/lib/api/serenity-fixtures.d.ts.map +1 -0
  19. package/lib/api/{SerenityOptions.js → serenity-fixtures.js} +1 -1
  20. package/lib/api/serenity-fixtures.js.map +1 -0
  21. package/lib/api/test-api.d.ts +27 -15
  22. package/lib/api/test-api.d.ts.map +1 -1
  23. package/lib/api/test-api.js +126 -104
  24. package/lib/api/test-api.js.map +1 -1
  25. package/lib/events/EventFactory.d.ts +16 -0
  26. package/lib/events/EventFactory.d.ts.map +1 -0
  27. package/lib/events/EventFactory.js +94 -0
  28. package/lib/events/EventFactory.js.map +1 -0
  29. package/lib/events/PlaywrightSceneId.d.ts +7 -0
  30. package/lib/events/PlaywrightSceneId.d.ts.map +1 -0
  31. package/lib/events/PlaywrightSceneId.js +19 -0
  32. package/lib/events/PlaywrightSceneId.js.map +1 -0
  33. package/lib/events/index.d.ts +3 -0
  34. package/lib/events/index.d.ts.map +1 -0
  35. package/lib/events/index.js +19 -0
  36. package/lib/events/index.js.map +1 -0
  37. package/lib/reporter/PlaywrightErrorParser.d.ts +7 -0
  38. package/lib/reporter/PlaywrightErrorParser.d.ts.map +1 -0
  39. package/lib/reporter/PlaywrightErrorParser.js +28 -0
  40. package/lib/reporter/PlaywrightErrorParser.js.map +1 -0
  41. package/lib/reporter/PlaywrightEventBuffer.d.ts +25 -0
  42. package/lib/reporter/PlaywrightEventBuffer.d.ts.map +1 -0
  43. package/lib/reporter/PlaywrightEventBuffer.js +147 -0
  44. package/lib/reporter/PlaywrightEventBuffer.js.map +1 -0
  45. package/lib/reporter/PlaywrightTestSceneIdFactory.d.ts +8 -0
  46. package/lib/reporter/PlaywrightTestSceneIdFactory.d.ts.map +1 -0
  47. package/lib/reporter/PlaywrightTestSceneIdFactory.js +15 -0
  48. package/lib/reporter/PlaywrightTestSceneIdFactory.js.map +1 -0
  49. package/lib/reporter/SerenityReporterForPlaywrightTest.d.ts +15 -22
  50. package/lib/reporter/SerenityReporterForPlaywrightTest.d.ts.map +1 -1
  51. package/lib/reporter/SerenityReporterForPlaywrightTest.js +62 -163
  52. package/lib/reporter/SerenityReporterForPlaywrightTest.js.map +1 -1
  53. package/lib/reporter/index.d.ts +0 -2
  54. package/lib/reporter/index.d.ts.map +1 -1
  55. package/lib/reporter/index.js +0 -2
  56. package/lib/reporter/index.js.map +1 -1
  57. package/package.json +9 -9
  58. package/src/api/PlaywrightTestConfig.ts +7 -6
  59. package/src/api/WorkerEventStreamReader.ts +27 -0
  60. package/src/api/WorkerEventStreamWriter.ts +117 -0
  61. package/src/api/index.ts +1 -2
  62. package/src/api/serenity-fixtures.ts +392 -0
  63. package/src/api/test-api.ts +187 -99
  64. package/src/events/EventFactory.ts +204 -0
  65. package/src/events/PlaywrightSceneId.ts +20 -0
  66. package/src/events/index.ts +2 -0
  67. package/src/reporter/PlaywrightErrorParser.ts +35 -0
  68. package/src/reporter/PlaywrightEventBuffer.ts +251 -0
  69. package/src/reporter/PlaywrightTestSceneIdFactory.ts +14 -0
  70. package/src/reporter/SerenityReporterForPlaywrightTest.ts +89 -250
  71. package/src/reporter/index.ts +0 -2
  72. package/lib/api/SerenityFixtures.d.ts +0 -130
  73. package/lib/api/SerenityFixtures.d.ts.map +0 -1
  74. package/lib/api/SerenityFixtures.js +0 -3
  75. package/lib/api/SerenityFixtures.js.map +0 -1
  76. package/lib/api/SerenityOptions.d.ts +0 -271
  77. package/lib/api/SerenityOptions.d.ts.map +0 -1
  78. package/lib/api/SerenityOptions.js.map +0 -1
  79. package/lib/reporter/DomainEventBuffer.d.ts +0 -11
  80. package/lib/reporter/DomainEventBuffer.d.ts.map +0 -1
  81. package/lib/reporter/DomainEventBuffer.js +0 -24
  82. package/lib/reporter/DomainEventBuffer.js.map +0 -1
  83. package/lib/reporter/PlaywrightAttachments.d.ts +0 -2
  84. package/lib/reporter/PlaywrightAttachments.d.ts.map +0 -1
  85. package/lib/reporter/PlaywrightAttachments.js +0 -5
  86. package/lib/reporter/PlaywrightAttachments.js.map +0 -1
  87. package/src/api/SerenityFixtures.ts +0 -132
  88. package/src/api/SerenityOptions.ts +0 -277
  89. package/src/reporter/DomainEventBuffer.ts +0 -28
  90. 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
- ClassDescription,
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 type { DomainEvent } from '@serenity-js/core/lib/events';
13
- import * as events from '@serenity-js/core/lib/events';
14
- import {
15
- InteractionFinished,
16
- RetryableSceneDetected,
17
- SceneFinished,
18
- SceneStarts,
19
- SceneTagged,
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
- * See [`SerenityOptions`](https://serenity-js.org/api/playwright-test/interface/SerenityOptions/) for usage examples.
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
- * - [`SerenityOptions`](https://serenity-js.org/api/playwright-test/interface/SerenityOptions/)
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
- private sceneIds: Map<string, CorrelationId> = new Map();
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
- config: SerenityReporterForPlaywrightTestConfig,
91
- private readonly serenity: Serenity = reporterSerenityInstance,
92
- private requirementsHierarchy: RequirementsHierarchy = new RequirementsHierarchy(
93
- new FileSystem(Path.from(process.cwd())),
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.requirementsHierarchy = new RequirementsHierarchy(
101
- new FileSystem(Path.from(config.rootDir)),
102
- );
75
+ this.eventBuffer.configure(config);
76
+ this.serenity.announce(new TestRunStarts(this.serenity.currentTime()));
103
77
 
104
- this.serenity.announce(new TestRunStarts(this.now()));
78
+ this.countTestsPerSuite(suite);
105
79
  }
106
80
 
107
- onTestBegin(test: TestCase): void {
108
- const currentSceneId = this.serenity.assignNewSceneId();
109
-
110
- this.sceneIds.set(test.id, currentSceneId);
111
-
112
- const { scenarioDetails, scenarioTags } = this.scenarioDetailsFrom(test);
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
- ...this.requirementsHierarchy
123
- .requirementTagsFor(scenarioDetails.location.path, scenarioDetails.category.value)
124
- .map(tag => new SceneTagged(currentSceneId, tag, this.serenity.currentTime())),
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
- ...tags.map(tag => new SceneTagged(currentSceneId, tag, this.serenity.currentTime())),
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 currentSceneId = this.sceneIds.get(test.id);
109
+ const pendingAfterAllHooks = this.countPendingAfterAllHooks(test);
149
110
 
150
- let worstInteractionOutcome: Outcome = new ExecutionSuccessful();
111
+ if (test.retries > 0) {
112
+ this.eventBuffer.appendRetryableSceneEvents(test, result);
113
+ }
151
114
 
152
- for (const attachment of result.attachments) {
153
- if (! (attachment.contentType === SERENITY_JS_DOMAIN_EVENTS_ATTACHMENT_CONTENT_TYPE && attachment.body)) {
154
- continue;
155
- }
115
+ this.eventBuffer.appendCrashedWorkerEvents(test, result);
116
+ this.eventBuffer.appendSceneEvents(test, result);
156
117
 
157
- const messages = JSON.parse(attachment.body.toString());
118
+ if (pendingAfterAllHooks === 0) {
119
+ this.eventBuffer.appendSceneFinishedEvent(test, result)
158
120
 
159
- for (const message of messages) {
160
- if (message.value.sceneId === 'unknown') {
161
- message.value.sceneId = currentSceneId.value;
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
- const event = events[message.type].fromJSON(message.value);
130
+ private countPendingAfterAllHooks(test: TestCase): number {
131
+ let currentSuite: Suite | undefined = test.parent;
132
+ const pendingAfterAllHooks: Suite[] = [];
165
133
 
166
- this.serenity.announce(event);
134
+ while (currentSuite) {
135
+ const remainingSuites = (this.suiteTestCounts.get(currentSuite) || 0) - 1;
136
+ this.suiteTestCounts.set(currentSuite, remainingSuites);
167
137
 
168
- if (event instanceof InteractionFinished && event.outcome.isWorseThan(worstInteractionOutcome)) {
169
- worstInteractionOutcome = event.outcome;
170
- }
138
+ if (remainingSuites === 0 && currentSuite['_hooks'].some((hook: { type: HookType }) => hook.type === 'afterAll')) {
139
+ pendingAfterAllHooks.push(currentSuite);
171
140
  }
172
- }
173
141
 
174
- const scenarioOutcome = this.outcomeFrom(test, result);
142
+ currentSuite = currentSuite.parent;
143
+ }
175
144
 
176
- this.serenity.announce(
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
- private determineScenarioOutcome(
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
- if (outcome === 'unexpected' && result.status === 'passed') {
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
- return new ExecutionSuccessful();
229
- }
158
+ this.serenity.announce(
159
+ ...deferredEvents,
160
+ );
230
161
 
231
- private scenarioDetailsFrom(test: TestCase): { scenarioDetails: ScenarioDetails, scenarioTags: Tag[] } {
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
- async onEnd(): Promise<void> {
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
- this.serenity.currentTime(),
177
+ endTime,
270
178
  ),
271
179
  );
272
- } catch (error) {
180
+ }
181
+ catch (error) {
273
182
  this.serenity.announce(
274
183
  new TestRunFinished(
275
184
  new ExecutionFailedWithError(error),
276
- this.serenity.currentTime(),
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
- }
@@ -1,4 +1,2 @@
1
- export * from './DomainEventBuffer';
2
- export * from './PlaywrightAttachments';
3
1
  export * from './PlaywrightStepReporter';
4
2
  export * from './SerenityReporterForPlaywrightTest';
@@ -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,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=SerenityFixtures.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SerenityFixtures.js","sourceRoot":"","sources":["../../src/api/SerenityFixtures.ts"],"names":[],"mappings":""}