@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serenity-js/playwright-test",
3
- "version": "3.31.17",
3
+ "version": "3.32.1",
4
4
  "description": "Serenity/JS test runner adapter for Playwright Test, combining Playwright's developer experience with the advanced reporting and automation capabilities of Serenity/JS",
5
5
  "author": {
6
6
  "name": "Jan Molak",
@@ -59,26 +59,26 @@
59
59
  "node": "^18.12 || ^20 || ^22"
60
60
  },
61
61
  "dependencies": {
62
- "@serenity-js/core": "3.31.17",
63
- "@serenity-js/playwright": "3.31.17",
64
- "@serenity-js/rest": "3.31.17",
65
- "@serenity-js/web": "3.31.17",
62
+ "@serenity-js/core": "3.32.1",
63
+ "@serenity-js/playwright": "3.32.1",
64
+ "@serenity-js/rest": "3.32.1",
65
+ "@serenity-js/web": "3.32.1",
66
66
  "deepmerge": "4.3.1",
67
67
  "tiny-types": "1.23.0"
68
68
  },
69
69
  "peerDependencies": {
70
- "@playwright/test": "~1.53.0"
70
+ "@playwright/test": "~1.53.1"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@integration/testing-tools": "3.0.0",
74
- "@playwright/test": "1.53.0",
74
+ "@playwright/test": "1.53.1",
75
75
  "@types/chai": "4.3.20",
76
76
  "@types/mocha": "10.0.10",
77
77
  "c8": "10.1.3",
78
- "mocha": "11.6.0",
78
+ "mocha": "11.7.0",
79
79
  "mocha-multi": "1.1.7",
80
80
  "ts-node": "10.9.2",
81
81
  "typescript": "5.8.3"
82
82
  },
83
- "gitHead": "317a2371b182d2182225eada1d1a9110a74a779f"
83
+ "gitHead": "f1f288c9a75d28270dfe4ba16ca4f367a4dbba22"
84
84
  }
@@ -1,10 +1,11 @@
1
1
  import type { PlaywrightTestConfig as BasePlaywrightTestConfig } from '@playwright/test';
2
2
 
3
- import type { SerenityOptions } from './SerenityOptions';
3
+ import type { SerenityFixtures, SerenityWorkerFixtures } from './serenity-fixtures';
4
4
 
5
5
  /**
6
6
  * Convenience alias for [PlaywrightTestConfig](https://playwright.dev/docs/test-configuration) object
7
- * that includes [`SerenityOptions`](https://serenity-js.org/api/playwright-test/interface/SerenityOptions/) and allows for any other custom options when needed.
7
+ * that includes [`SerenityFixtures`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/) and
8
+ * [`SerenityWorkerFixtures`](https://serenity-js.org/api/playwright-test/interface/SerenityWorkerFixtures/) and allows for any other custom options when needed.
8
9
  *
9
10
  * #### Example
10
11
  * Configuring Playwright Test using the standard `PlaywrightTestConfig` from `@playwright/test`:
@@ -12,9 +13,9 @@ import type { SerenityOptions } from './SerenityOptions';
12
13
  * ```typescript
13
14
  * // playwright.config.ts
14
15
  * import type { PlaywrightTestConfig } from '@playwright/test'
15
- * import type { SerenityOptions } from '@serenity-js/playwright-test'
16
+ * import type { SerenityFixtures, SerenityWorkerFixtures } from '@serenity-js/playwright-test'
16
17
  *
17
- * const config: PlaywrightTestConfig<SerenityOptions & MyCustomOptions> = {
18
+ * const config: PlaywrightTestConfig<SerenityFixtures & MyCustomOptions, SerenityWorkerFixtures> = {
18
19
  * // ...
19
20
  * }
20
21
  *
@@ -34,9 +35,9 @@ import type { SerenityOptions } from './SerenityOptions';
34
35
  * ```
35
36
  *
36
37
  * #### Learn more
37
- * - [`SerenityOptions`](https://serenity-js.org/api/playwright-test/interface/SerenityOptions/)
38
38
  * - [`SerenityFixtures`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/)
39
+ * - [`SerenityWorkerFixtures`](https://serenity-js.org/api/playwright-test/interface/SerenityWorkerFixtures/)
39
40
  * - [`SerenityReporterForPlaywrightTestConfig`](https://serenity-js.org/api/playwright-test/interface/SerenityReporterForPlaywrightTestConfig/)
40
41
  * - [Playwright Test configuration](https://playwright.dev/docs/test-configuration)
41
42
  */
42
- export type PlaywrightTestConfig<TestArgs = object, WorkerArgs = object> = BasePlaywrightTestConfig<SerenityOptions & TestArgs, WorkerArgs>;
43
+ export type PlaywrightTestConfig<TestArgs = object, WorkerArgs = object> = BasePlaywrightTestConfig<SerenityFixtures & TestArgs, SerenityWorkerFixtures & WorkerArgs>;
@@ -0,0 +1,27 @@
1
+ import fs from 'node:fs';
2
+
3
+ import type { DomainEvent } from '@serenity-js/core/lib/events';
4
+ import * as events from '@serenity-js/core/lib/events';
5
+ import type { JSONObject } from 'tiny-types';
6
+
7
+ export class WorkerEventStreamReader {
8
+
9
+ hasStream(pathToEventStreamFile: string): boolean {
10
+ return fs.existsSync(pathToEventStreamFile);
11
+ }
12
+
13
+ read<T extends DomainEvent>(
14
+ pathToEventStreamFile: string,
15
+ mapper: (input: { type: string, value: JSONObject }) => { type: string, value: JSONObject } = input => input
16
+ ): T[] {
17
+ const content = fs.readFileSync(pathToEventStreamFile, 'utf8');
18
+
19
+ return content
20
+ .split('\n')
21
+ .filter(Boolean)
22
+ .map(line => {
23
+ const { type, value } = mapper(JSON.parse(line));
24
+ return events[type].fromJSON(value);
25
+ });
26
+ }
27
+ }
@@ -0,0 +1,117 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ import { type WorkerInfo } from '@playwright/test';
5
+ import type { TestCase } from '@playwright/test/reporter';
6
+ import type { Stage, StageCrewMember } from '@serenity-js/core';
7
+ import { LogicError } from '@serenity-js/core';
8
+ import type { DomainEvent } from '@serenity-js/core/lib/events';
9
+ import { CorrelationId } from '@serenity-js/core/lib/model';
10
+ import type { JSONObject } from 'tiny-types';
11
+
12
+ export class WorkerEventStreamWriter implements StageCrewMember {
13
+
14
+ private readonly beforeAllId: CorrelationId; // = new CorrelationId('unknown');
15
+ private activeSceneId: CorrelationId; // = WorkerEventStreamWriter.beforeTest;
16
+
17
+ private events: Map<TestCase['id'], DomainEvent[]> = new Map();
18
+
19
+ static workerStreamIdFor(workerIndex: number): CorrelationId {
20
+ return new CorrelationId(`worker-${ workerIndex }`);
21
+ }
22
+
23
+ constructor(
24
+ private readonly outputDirectory: string,
25
+ private readonly workerInfo: WorkerInfo,
26
+ private stage?: Stage,
27
+ ) {
28
+
29
+ this.beforeAllId = WorkerEventStreamWriter.workerStreamIdFor(this.workerInfo.workerIndex);
30
+ this.activeSceneId = this.beforeAllId;
31
+ this.events.set(this.beforeAllId.value, []);
32
+ }
33
+
34
+ assignedTo(stage: Stage): StageCrewMember {
35
+ this.stage = stage;
36
+
37
+ return this;
38
+ }
39
+
40
+ notifyOf(event: DomainEvent): void {
41
+
42
+ if (this.isSceneEvent(event) && ! this.activeSceneExistsFor(event)) {
43
+ this.activateScene(event);
44
+ }
45
+
46
+ this.events.get(this.activeSceneId.value).push(event);
47
+ }
48
+
49
+ private isSceneEvent(event: DomainEvent & { sceneId?: CorrelationId }): event is DomainEvent & { sceneId: CorrelationId } {
50
+ return event['sceneId'] instanceof CorrelationId;
51
+ }
52
+
53
+ private activeSceneExistsFor(event: DomainEvent & { sceneId: CorrelationId }): boolean {
54
+ return this.activeSceneId.equals(event.sceneId);
55
+ }
56
+
57
+ private activateScene(event: DomainEvent & { sceneId: CorrelationId }): void {
58
+ this.activeSceneId = event.sceneId;
59
+
60
+ const testId = event.sceneId.value;
61
+
62
+ if (! this.events.has(testId)) {
63
+ this.events.set(testId, []);
64
+ }
65
+
66
+ this.events.get(testId).push(
67
+ ...this.events.get(this.beforeAllId.value),
68
+ );
69
+
70
+ this.events.set(this.beforeAllId.value, []);
71
+ }
72
+
73
+ async persistAll(workerBeforeAllSceneId: CorrelationId): Promise<void> {
74
+ const testIds = [...this.events.keys()];
75
+
76
+ await Promise.all(testIds.map(testId => this.persist(testId, workerBeforeAllSceneId)));
77
+ }
78
+
79
+ async persist(testId: TestCase['id'], workerBeforeAllSceneId?: CorrelationId): Promise<void> {
80
+ const testOutputDirectory = path.join(this.outputDirectory, testId);
81
+
82
+ const filePath = path.join(testOutputDirectory, 'events.ndjson');
83
+
84
+ const events = this.flush(testId);
85
+
86
+ if (events.length === 0) {
87
+ return;
88
+ }
89
+
90
+ await fs.promises.mkdir(testOutputDirectory, { recursive: true })
91
+
92
+ for (const event of events) {
93
+ const shouldReattachToScene = event['sceneId'] && event['sceneId'].equals(workerBeforeAllSceneId);
94
+
95
+ const type = event.constructor.name;
96
+
97
+ const value = shouldReattachToScene
98
+ ? ({ ...(event.toJSON() as JSONObject), sceneId: testId })
99
+ : event.toJSON();
100
+
101
+ const serialisedEvent = JSON.stringify({ type, value }, undefined, 0);
102
+
103
+ await fs.promises.appendFile(filePath, serialisedEvent + '\n');
104
+ }
105
+ }
106
+
107
+ private flush(testId: TestCase['id']): DomainEvent[] {
108
+ if (! this.events.has(testId)) {
109
+ throw new LogicError(`No events recorded for test with id ${ testId }`);
110
+ }
111
+
112
+ const events = this.events.get(testId);
113
+ this.events.set(testId, []);
114
+
115
+ return events;
116
+ }
117
+ }
package/src/api/index.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  export * from './PlaywrightTestConfig';
2
- export * from './SerenityFixtures';
3
- export * from './SerenityOptions';
2
+ export * from './serenity-fixtures';
4
3
  export * from './test-api';
@@ -0,0 +1,392 @@
1
+ import type {
2
+ Cast,
3
+ ClassDescription,
4
+ Duration,
5
+ Serenity,
6
+ StageCrewMember,
7
+ StageCrewMemberBuilder
8
+ } from '@serenity-js/core';
9
+ import type { Actor } from '@serenity-js/core';
10
+ import type { ExtraBrowserContextOptions } from '@serenity-js/playwright';
11
+
12
+ /**
13
+ * Serenity/JS-specific [Playwright Test fixtures](https://playwright.dev/docs/test-fixtures)
14
+ * injected into your [test scenarios](https://serenity-js.org/api/playwright-test/function/it/).
15
+ *
16
+ * ### Configuring Serenity/JS using a test file
17
+ *
18
+ * ```typescript
19
+ * import { Ensure, equals } from '@serenity-js/assertions'
20
+ * import { describe, it, test } from '@serenity-js/playwright-test'
21
+ * import { Photographer, TakePhotosOfFailures } from '@serenity-js/web'
22
+ *
23
+ * describe(`Recording items`, () => {
24
+ *
25
+ * test.use({
26
+ * defaultActorName: 'Serena',
27
+ * crew: [
28
+ * Photographer.whoWill(TakePhotosOfFailures),
29
+ * ],
30
+ *
31
+ * // Register a custom cast of Serenity/JS actors to replace the default one
32
+ * actors: async ({ browser, contextOptions, extraContextOptions, baseURL }, use) => {
33
+ * const cast = Cast.where(actor =>
34
+ * actor.whoCan(
35
+ * BrowseTheWebWithPlaywright.using(browser, contextOptions, extraContextOptions),
36
+ * TakeNotes.usingAnEmptyNotepad(),
37
+ * CallAnApi.at(baseURL),
38
+ * )
39
+ * )
40
+ *
41
+ * await use(cast)
42
+ * },
43
+ * })
44
+ *
45
+ * describe(`Todo List App`, () => {
46
+ *
47
+ * it(`should allow me to add a todo item`, async ({ actor }) => {
48
+ * await actor.attemptsTo(
49
+ * startWithAnEmptyList(),
50
+ *
51
+ * recordItem('Buy some milk'),
52
+ *
53
+ * Ensure.that(itemNames(), equals([
54
+ * 'Buy some milk',
55
+ * ])),
56
+ * )
57
+ * })
58
+ * })
59
+ * })
60
+ * ```
61
+ *
62
+ * ### Configuring Serenity/JS using Playwright configuration file
63
+ *
64
+ * ```typescript
65
+ * // playwright.config.ts
66
+ * import { defineConfig } from '@playwright/test'
67
+ * import type { Cast, TakeNotes } from '@serenity-js/core'
68
+ * import type { BrowseTheWebWithPlaywright } from '@serenity-js/playwright'
69
+ * import type { SerenityFixtures, SerenityWorkerFixtures } from '@serenity-js/playwright-test'
70
+ * import type { CallAnApi } from '@serenity-js/rest'
71
+ *
72
+ * export default defineConfig<SerenityFixtures & MyCustomOptions, SerenityWorkerFixtures> = {
73
+ *
74
+ * // Register Serenity/JS reporter for Playwright Test
75
+ * // to enable integration with Serenity/JS stage crew members
76
+ * // and have them instantiated in the Playwright reporter process
77
+ * reporter: [
78
+ * [ '@serenity-js/playwright-test', {
79
+ * // Stage crew members instantiated in the test reporter process
80
+ * crew: [
81
+ * '@serenity-js/serenity-bdd',
82
+ * '@serenity-js/console-reporter',
83
+ * [ '@serenity-js/core:ArtifactArchiver', { outputDirectory: 'target/site/serenity' } ],
84
+ * ]
85
+ * }]
86
+ * ],
87
+ *
88
+ * use: {
89
+ *
90
+ * // Register Serenity/JS stage crew members
91
+ * // and have them instantiated in Playwright Test worker processes
92
+ * crew: [
93
+ * [ '@serenity-js/web:Photographer', { strategy: 'TakePhotosOfFailures' } ]
94
+ * ],
95
+ *
96
+ * // Name to be given to an actor injected via `actor` fixture
97
+ * defaultActorName: 'Alice',
98
+ *
99
+ * // Any other Playwright options
100
+ * baseURL: 'https://todo-app.serenity-js.org/',
101
+ * video: 'on-first-retry',
102
+ * trace: 'on-first-retry',
103
+ * },
104
+ * })
105
+ * ```
106
+ *
107
+ * ## Learn more
108
+ * - [Using Serenity/JS with Playwright Test](https://serenity-js.org/handbook/test-runners/playwright-test/)
109
+ * - [`PlaywrightTestConfig`](https://serenity-js.org/api/playwright-test/#PlaywrightTestConfig)
110
+ * - [`Cast`](https://serenity-js.org/api/core/class/Cast/)
111
+ * - [`SerenityFixtures`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/)
112
+ */
113
+ export interface SerenityFixtures {
114
+
115
+ /**
116
+ * Configures the name given to the default Serenity/JS [`actor`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#actor)
117
+ * injected into a [test scenario](https://serenity-js.org/api/playwright-test/function/it/).
118
+ *
119
+ * #### Learn more
120
+ * - Declaring a Serenity/JS [test scenario](https://serenity-js.org/api/playwright-test/function/it/)
121
+ * - [`SerenityFixtures`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/)
122
+ */
123
+ defaultActorName: string;
124
+
125
+ /**
126
+ * Configures the [stage crew members](https://serenity-js.org/api/core/class/SerenityConfig/#crew)
127
+ * to be instantiated in Playwright Test worker processes.
128
+ *
129
+ * :::info Did you know?
130
+ * By default, Serenity/JS registers a [`Photographer`](https://serenity-js.org/api/web/class/Photographer/).whoWill([`TakePhotosOfFailures`](https://serenity-js.org/api/web/class/TakePhotosOfFailures/)),
131
+ * so that any test failures are automatically accompanied by a screenshot.
132
+ *
133
+ * If you prefer a different behaviour, you can configure the `crew` with an empty array to disable taking screenshots altogether (`crew: []`),
134
+ * or with a [`Photographer`](https://serenity-js.org/api/web/class/Photographer/) who uses a different [`PhotoTakingStrategy`](https://serenity-js.org/api/web/class/PhotoTakingStrategy/), like to [`TakePhotosOfInteractions`](https://serenity-js.org/api/web/class/TakePhotosOfInteractions/).
135
+ * :::
136
+ *
137
+ * #### Example
138
+ *
139
+ * ```typescript
140
+ * // playwright.config.ts
141
+ * import type { SerenityFixtures, SerenityWorkerFixtures } from '@serenity-js/playwright-test'
142
+ * import { defineConfig } from '@playwright/test'
143
+ *
144
+ * export default defineConfig<SerenityFixtures, SerenityWorkerFixtures>({
145
+ * use: {
146
+ * crew: [
147
+ * [ '@serenity-js/web:Photographer', { strategy: 'TakePhotosOfFailures' } ]
148
+ * ],
149
+ * },
150
+ * });
151
+ * ```
152
+ *
153
+ * #### Learn more
154
+ * - [`SerenityConfig.crew`](https://serenity-js.org/api/core/class/SerenityConfig/#crew)
155
+ */
156
+ crew: Array<ClassDescription | StageCrewMember | StageCrewMemberBuilder>;
157
+
158
+ /**
159
+ * Sets the [`cueTimeout`](https://serenity-js.org/api/core/class/SerenityConfig/#cueTimeout) to a given [duration](https://serenity-js.org/api/core/class/Duration/) or a numeric value in milliseconds.
160
+ * Defaults to **5 seconds**.
161
+ *
162
+ * #### Learn more
163
+ * - [`SerenityConfig.cueTimeout`](https://serenity-js.org/api/core/class/SerenityConfig/#cueTimeout)
164
+ * - [`Discardable`](https://serenity-js.org/api/core/interface/Discardable/)
165
+ * - [`Ability`](https://serenity-js.org/api/core/class/Ability/)
166
+ */
167
+ cueTimeout: number | Duration;
168
+
169
+ /**
170
+ * The maximum default amount of time allowed for interactions such as [`Wait.until`](https://serenity-js.org/api/core/class/Wait/#until)
171
+ * to complete.
172
+ *
173
+ * Defaults to **5 seconds**, can be overridden per interaction.
174
+ *
175
+ * #### Learn more
176
+ * - [`Wait.until`](https://serenity-js.org/api/core/class/Wait/#until)
177
+ */
178
+ interactionTimeout: number | Duration;
179
+
180
+ /**
181
+ * Convenience properties to be used with the [ability](https://serenity-js.org/api/core/class/Ability/)
182
+ * to [`BrowseTheWebWithPlaywright`](https://serenity-js.org/api/playwright/class/BrowseTheWebWithPlaywright/),
183
+ * in addition to Playwright [BrowserContextOptions](https://playwright.dev/docs/api/class-testoptions#test-options-context-options):
184
+ *
185
+ * - [`defaultNavigationTimeout`](https://serenity-js.org/api/playwright/interface/ExtraBrowserContextOptions/#defaultNavigationTimeout)
186
+ * - [`defaultNavigationWaitUntil`](https://serenity-js.org/api/playwright/interface/ExtraBrowserContextOptions/#defaultNavigationWaitUntil)
187
+ * - [`defaultTimeout`](https://serenity-js.org/api/playwright/interface/ExtraBrowserContextOptions/#defaultTimeout)
188
+ *
189
+ * #### Using `extraContextOptions` with the default cast of Serenity/JS actors
190
+ *
191
+ * ```typescript
192
+ * // playwright.config.ts
193
+ * import type { SerenityFixtures, SerenityWorkerFixtures } from '@serenity-js/playwright-test'
194
+ * import { defineConfig } from '@playwright/test'
195
+ *
196
+ * export default defineConfig<SerenityFixtures, SerenityWorkerFixtures>({
197
+ * use: {
198
+ * extraContextOptions: {
199
+ * defaultNavigationTimeout: 30_000,
200
+ * }
201
+ *
202
+ * // Since `actors` property is not defined,
203
+ * // `extraContextOptions` will be passed to the default cast of Serenity/JS actors
204
+ * // and injected into the ability to `BrowseTheWebWithPlaywright`
205
+ * // that each actor receives.
206
+ * },
207
+ * })
208
+ * ```
209
+ *
210
+ * #### Using `extraContextOptions` with a custom cast of Serenity/JS actors
211
+ *
212
+ * ```typescript
213
+ * // playwright.config.ts
214
+ * import type { SerenityFixtures, SerenityWorkerFixtures } from '@serenity-js/playwright-test'
215
+ * import { defineConfig } from '@playwright/test'
216
+ *
217
+ * export default defineConfig<SerenityFixtures, SerenityWorkerFixtures>({
218
+ * use: {
219
+ * extraContextOptions: {
220
+ * defaultNavigationTimeout: 30_000,
221
+ * }
222
+ *
223
+ * // Custom cast of actors receives the default `contextOptions` and
224
+ * // the `extraContextOptions` with the additional Serenity/JS properties.
225
+ * actors: async ({ browser, contextOptions, extraContextOptions }, use) => {
226
+ * const cast = Cast.where(actor => actor.whoCan(
227
+ * BrowseTheWebWithPlaywright.using(browser, contextOptions, extraContextOptions),
228
+ * TakeNotes.usingAnEmptyNotepad(),
229
+ * ))
230
+ *
231
+ * await use(cast)
232
+ * },
233
+ * },
234
+ * })
235
+ * ```
236
+ *
237
+ * #### Learn more
238
+ * - [`SerenityFixtures`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/)
239
+ * - [Playwright Browser Context options](https://playwright.dev/docs/api/class-testoptions#test-options-context-options)
240
+ * - [Playwright Test fixtures](https://playwright.dev/docs/test-fixtures)
241
+ */
242
+ extraContextOptions: Partial<ExtraBrowserContextOptions>;
243
+
244
+ /**
245
+ * A cast of Serenity/JS actors to be used instead of the default cast
246
+ * when instantiating [`actor`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#actor)
247
+ * and invoking [`actorCalled`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#actorCalled).
248
+ *
249
+ * :::info Did you know?
250
+ * When you use `@serenity-js/playwright-test` [test APIs](https://serenity-js.org/api/playwright-test/function/it/), Serenity/JS already provides a default cast of actors for you.
251
+ * Each one of the default actors receives [abilities](https://serenity-js.org/api/core/class/Ability/) to [`BrowseTheWebWithPlaywright`](https://serenity-js.org/api/playwright/class/BrowseTheWebWithPlaywright/) and [`TakeNotes.usingAnEmptyNotepad`](https://serenity-js.org/api/core/class/TakeNotes/#usingAnEmptyNotepad).
252
+ *
253
+ * The default abilities should be sufficient in most web testing scenarios. However, you might want to override this default configuration
254
+ * when you need your actors to [interact with REST APIs](https://serenity-js.org/api/rest/class/CallAnApi/),
255
+ * [manage local servers](https://serenity-js.org/api/local-server/class/ManageALocalServer/),
256
+ * start with a notepad that has some [initial state](https://serenity-js.org/api/core/class/TakeNotes/#using),
257
+ * or receive [custom abilities](https://serenity-js.org/api/core/class/Ability/).
258
+ * :::
259
+ *
260
+ *
261
+ * #### Overriding the default cast of Serenity/JS actors
262
+ *
263
+ * ```typescript
264
+ * import { Cast, TakeNotes } from '@serenity-js/core'
265
+ * import { Ensure, equals } from '@serenity-js/assertions'
266
+ * import { BrowseTheWebWithPlaywright } from '@serenity-js/playwright'
267
+ * import { describe, it, test } from '@serenity-js/playwright-test'
268
+ *
269
+ * describe(`Recording items`, () => {
270
+ *
271
+ * test.use({
272
+ * extraContextOptions: {
273
+ * defaultNavigationTimeout: 30_000,
274
+ * },
275
+ *
276
+ * defaultActorName: 'Serena',
277
+ * actors: async ({ browser, contextOptions, extraContextOptions }, use) => {
278
+ * const cast = Cast.where(actor =>
279
+ * actor.whoCan(
280
+ * BrowseTheWebWithPlaywright.using(browser, contextOptions, extraContextOptions),
281
+ * TakeNotes.usingAnEmptyNotepad(),
282
+ * )
283
+ * )
284
+ *
285
+ * // Make sure to pass your custom cast to Playwright `use` callback
286
+ * await use(cast)
287
+ * },
288
+ * })
289
+ *
290
+ * describe(`Todo List App`, () => {
291
+ *
292
+ * it(`should allow me to add a todo item`, async ({ actor }) => {
293
+ * await actor.attemptsTo(
294
+ * startWithAnEmptyList(),
295
+ *
296
+ * recordItem('Buy some milk'),
297
+ *
298
+ * Ensure.that(itemNames(), equals([
299
+ * 'Buy some milk',
300
+ * ])),
301
+ * )
302
+ * })
303
+ * })
304
+ * })
305
+ *
306
+ *
307
+ * #### Learn more
308
+ * - Declaring a Serenity/JS [test scenario](https://serenity-js.org/api/playwright-test/function/it/)
309
+ * - [`SerenityFixtures`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/)
310
+ */
311
+ actors: Cast;
312
+
313
+ /**
314
+ * 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/).
315
+ *
316
+ * Using `actor` fixture is equivalent to invoking [`actorCalled`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#actorCalled)
317
+ * with [`defaultActorName`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#defaultActorName).
318
+ *
319
+ * #### Learn more
320
+ * - [`actorCalled`](https://serenity-js.org/api/playwright-test/interface/SerenityWorkerFixtures/#actorCalled)
321
+ * - [`defaultActorName`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#defaultActorName)
322
+ * - Declaring a Serenity/JS [test scenario](https://serenity-js.org/api/playwright-test/function/it/)
323
+ */
324
+ actor: Actor;
325
+ }
326
+
327
+ /**
328
+ * Serenity/JS-specific [Playwright Test fixtures](https://playwright.dev/docs/test-fixtures)
329
+ * injected into your [test scenarios](https://serenity-js.org/api/playwright-test/function/it/).
330
+ *
331
+ * ## Example test scenario
332
+ *
333
+ * ```typescript
334
+ * import { Ensure, equals } from '@serenity-js/assertions'
335
+ * import { describe, it, test } from '@serenity-js/playwright-test'
336
+ * import { Photographer, TakePhotosOfFailures } from '@serenity-js/web'
337
+ *
338
+ * describe(`Recording items`, () => {
339
+ *
340
+ * test.use({
341
+ * defaultActorName: 'Serena',
342
+ * crew: [
343
+ * Photographer.whoWill(TakePhotosOfFailures),
344
+ * ],
345
+ * })
346
+ *
347
+ * describe(`Todo List App`, () => {
348
+ *
349
+ * it(`should allow me to add a todo item`, async ({ actor }) => {
350
+ * await actor.attemptsTo(
351
+ * startWithAnEmptyList(),
352
+ *
353
+ * recordItem('Buy some milk'),
354
+ *
355
+ * Ensure.that(itemNames(), equals([
356
+ * 'Buy some milk',
357
+ * ])),
358
+ * )
359
+ * })
360
+ * })
361
+ * })
362
+ * ```
363
+ *
364
+ * ## Learn more
365
+ * - [Using Serenity/JS with Playwright Test](https://serenity-js.org/handbook/test-runners/playwright-test/)
366
+ */
367
+ export interface SerenityWorkerFixtures {
368
+ /**
369
+ * Name and version of the operating system that Playwright Test worker process runs on.
370
+ */
371
+ platform: { name: string, version: string };
372
+
373
+ /**
374
+ * Retrieves the root object of the Serenity/JS framework.
375
+ */
376
+ serenity: Serenity;
377
+
378
+ /**
379
+ * 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`
380
+ * and inject it into a [test scenario](https://serenity-js.org/api/playwright-test/function/it/).
381
+ *
382
+ * Retrieves an existing actor if one has already been instantiated.
383
+ *
384
+ * #### Learn more
385
+ * - Declaring a Serenity/JS [test scenario](https://serenity-js.org/api/playwright-test/function/it/)
386
+ * - [`SerenityFixtures.actors`](https://serenity-js.org/api/playwright-test/interface/SerenityFixtures/#actors)
387
+ *
388
+ * @param name
389
+ */
390
+ actorCalled: (name: string) => Actor;
391
+ }
392
+