@definitely-fine/playwright 0.1.0
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/LICENSE +21 -0
- package/README.md +131 -0
- package/dist/index.d.ts +420 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 definitely-fine contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# @definitely-fine/playwright
|
|
2
|
+
|
|
3
|
+
`@definitely-fine/playwright` helps Playwright tests activate `definitely-fine` scenarios in browser-driven flows.
|
|
4
|
+
|
|
5
|
+
It extends the core scenario builder with request headers plus helpers for creating browser contexts and pages that already send the active scenario id.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add -D @playwright/test @definitely-fine/playwright
|
|
11
|
+
pnpm add definitely-fine
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## What This Package Adds
|
|
15
|
+
|
|
16
|
+
`createScenario()` from this package builds on the core `definitely-fine` scenario builder and adds:
|
|
17
|
+
|
|
18
|
+
- `headerName`
|
|
19
|
+
- `headers`
|
|
20
|
+
- `createContext(browser, options?)`
|
|
21
|
+
- `createPage(browser, options?)`
|
|
22
|
+
|
|
23
|
+
```mermaid
|
|
24
|
+
flowchart LR
|
|
25
|
+
subgraph P[Playwright worker process]
|
|
26
|
+
P1[createScenario]
|
|
27
|
+
P2[define rules and save scenario]
|
|
28
|
+
P3[createContext or createPage]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
subgraph B[Browser process]
|
|
32
|
+
B1[request with scenario header]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
subgraph A[Application server process]
|
|
36
|
+
A1[@definitely-fine/nextjs or @definitely-fine/hono]
|
|
37
|
+
A2[runWithRuntimeScenarioContext]
|
|
38
|
+
A3[definitely-fine runtime]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
subgraph S[Shared scenario storage]
|
|
42
|
+
S1[(persisted scenario JSON)]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
P1 --> P2 --> S1
|
|
46
|
+
P2 --> P3
|
|
47
|
+
P3 --> B1
|
|
48
|
+
B1 --> A1 --> A2 --> A3
|
|
49
|
+
A3 -- load active scenario --> S1
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Example
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { test, expect } from "@playwright/test";
|
|
56
|
+
import { DEFINITELY_FINE_SCENARIO_HEADER } from "@definitely-fine/nextjs";
|
|
57
|
+
import { createScenario } from "@definitely-fine/playwright";
|
|
58
|
+
|
|
59
|
+
type DemoContract = {
|
|
60
|
+
services: {
|
|
61
|
+
counter: {
|
|
62
|
+
incrementApi(): number;
|
|
63
|
+
incrementAction(): number;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
functions: Record<string, never>;
|
|
67
|
+
errors: Record<string, never>;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
test("uses a scenario-backed browser context", async ({ browser }) => {
|
|
71
|
+
const scenario = createScenario<DemoContract>({
|
|
72
|
+
headerName: DEFINITELY_FINE_SCENARIO_HEADER,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
scenario.service("counter").method("incrementApi").onCall(1).returns(10);
|
|
76
|
+
await scenario.save();
|
|
77
|
+
|
|
78
|
+
const context = await scenario.createContext(browser);
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const page = await context.newPage();
|
|
82
|
+
|
|
83
|
+
await page.goto("/");
|
|
84
|
+
await page
|
|
85
|
+
.getByRole("button", { name: "Increment with API route" })
|
|
86
|
+
.click();
|
|
87
|
+
await expect(page.locator("#api-count")).toHaveText("10");
|
|
88
|
+
} finally {
|
|
89
|
+
await context.close();
|
|
90
|
+
await scenario.dispose();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Header Behavior
|
|
96
|
+
|
|
97
|
+
The helper merges the scenario header into `extraHTTPHeaders` when it creates a new browser context.
|
|
98
|
+
|
|
99
|
+
That means requests from pages created through that context automatically activate the saved scenario in your server-side runtime, as long as your app reads the same header.
|
|
100
|
+
|
|
101
|
+
## Explicit Directory Override
|
|
102
|
+
|
|
103
|
+
The built-in JSON storage can infer its directory automatically, so this is often enough:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
const scenario = createScenario({
|
|
107
|
+
headerName: "x-definitely-fine-scenario-id",
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
If you need scenarios in a known local path, you can still override the directory:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
const scenario = createScenario({
|
|
115
|
+
directory: ".definitely-fine",
|
|
116
|
+
headerName: "x-definitely-fine-scenario-id",
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Typical Setup
|
|
121
|
+
|
|
122
|
+
1. Build a scenario in the test.
|
|
123
|
+
2. Save it before navigating.
|
|
124
|
+
3. Create a browser context or page through the scenario helper.
|
|
125
|
+
4. Run your browser flow.
|
|
126
|
+
5. Let your app's `definitely-fine` runtime intercept the targeted calls.
|
|
127
|
+
|
|
128
|
+
## Related Packages
|
|
129
|
+
|
|
130
|
+
- [`definitely-fine`](../definitely-fine/README.md) provides the runtime and storage model.
|
|
131
|
+
- [`@definitely-fine/nextjs`](../nextjs/README.md) reads the scenario header inside Next.js route handlers and server actions.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import { BrowserContextOptions } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
//#region ../definitely-fine/src/types.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Generic callable shape used throughout definitely-fine contracts.
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Generic callable shape used throughout definitely-fine contracts.
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
type UnknownFunction = (...args: never[]) => unknown;
|
|
13
|
+
/**
|
|
14
|
+
* Contract shape for a named service whose values are callable methods.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
type ServiceContract = Record<string, UnknownFunction>;
|
|
18
|
+
/**
|
|
19
|
+
* Map of named services available to a system under test.
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
type ServiceContracts = Record<string, ServiceContract>;
|
|
23
|
+
/**
|
|
24
|
+
* Map of named top-level functions available to a system under test.
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
type FunctionContracts = Record<string, UnknownFunction>;
|
|
28
|
+
/**
|
|
29
|
+
* Map of named error factory functions available to a runtime.
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
type ErrorFactoryContracts = Record<string, UnknownFunction>;
|
|
33
|
+
/**
|
|
34
|
+
* Full contract definition for services, functions, and error factories.
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
37
|
+
type SutContract = {
|
|
38
|
+
/**
|
|
39
|
+
* Named service contracts whose members are callable methods.
|
|
40
|
+
*/
|
|
41
|
+
services: ServiceContracts;
|
|
42
|
+
/**
|
|
43
|
+
* Named top-level function contracts.
|
|
44
|
+
*/
|
|
45
|
+
functions: FunctionContracts;
|
|
46
|
+
/**
|
|
47
|
+
* Named error factory contracts available to runtime rules.
|
|
48
|
+
*/
|
|
49
|
+
errors: ErrorFactoryContracts;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Union of valid service names from a contract.
|
|
53
|
+
* @public
|
|
54
|
+
*/
|
|
55
|
+
type ContractServiceName<TContract extends SutContract> = Extract<keyof TContract["services"], string>;
|
|
56
|
+
/**
|
|
57
|
+
* Union of valid function names from a contract.
|
|
58
|
+
* @public
|
|
59
|
+
*/
|
|
60
|
+
type ContractFunctionName<TContract extends SutContract> = Extract<keyof TContract["functions"], string>;
|
|
61
|
+
/**
|
|
62
|
+
* Union of valid error factory names from a contract.
|
|
63
|
+
* @public
|
|
64
|
+
*/
|
|
65
|
+
type ContractErrorFactoryName<TContract extends SutContract> = Extract<keyof TContract["errors"], string>;
|
|
66
|
+
/**
|
|
67
|
+
* Union of valid method names for a service in a contract.
|
|
68
|
+
* @public
|
|
69
|
+
*/
|
|
70
|
+
type ContractServiceMethodName<TContract extends SutContract, TServiceName extends ContractServiceName<TContract>> = Extract<keyof TContract["services"][TServiceName], string>;
|
|
71
|
+
/**
|
|
72
|
+
* Function type for a named contract function.
|
|
73
|
+
* @public
|
|
74
|
+
*/
|
|
75
|
+
type ContractFunction<TContract extends SutContract, TFunctionName extends ContractFunctionName<TContract>> = TContract["functions"][TFunctionName];
|
|
76
|
+
/**
|
|
77
|
+
* Method type for a named service method in a contract.
|
|
78
|
+
* @public
|
|
79
|
+
*/
|
|
80
|
+
type ContractServiceMethod<TContract extends SutContract, TServiceName extends ContractServiceName<TContract>, TMethodName extends ContractServiceMethodName<TContract, TServiceName>> = TContract["services"][TServiceName][TMethodName];
|
|
81
|
+
/**
|
|
82
|
+
* Error factory type for a named contract factory.
|
|
83
|
+
* @public
|
|
84
|
+
*/
|
|
85
|
+
type ContractErrorFactory<TContract extends SutContract, TFactoryName extends ContractErrorFactoryName<TContract>> = TContract["errors"][TFactoryName];
|
|
86
|
+
/**
|
|
87
|
+
* Resolved return value for a named contract function.
|
|
88
|
+
* @public
|
|
89
|
+
*/
|
|
90
|
+
type ContractFunctionReturnValue<TContract extends SutContract, TFunctionName extends ContractFunctionName<TContract>> = Awaited<ReturnType<ContractFunction<TContract, TFunctionName>>>;
|
|
91
|
+
/**
|
|
92
|
+
* Resolved return value for a named contract service method.
|
|
93
|
+
* @public
|
|
94
|
+
*/
|
|
95
|
+
type ContractServiceMethodReturnValue<TContract extends SutContract, TServiceName extends ContractServiceName<TContract>, TMethodName extends ContractServiceMethodName<TContract, TServiceName>> = Awaited<ReturnType<ContractServiceMethod<TContract, TServiceName, TMethodName>>>;
|
|
96
|
+
/**
|
|
97
|
+
* First input argument accepted by a named contract error factory.
|
|
98
|
+
* @public
|
|
99
|
+
*/
|
|
100
|
+
type ContractErrorFactoryInput<TContract extends SutContract, TFactoryName extends ContractErrorFactoryName<TContract>> = Parameters<ContractErrorFactory<TContract, TFactoryName>>[0];
|
|
101
|
+
type ContractErrorFactoryParameters<TContract extends SutContract, TFactoryName extends ContractErrorFactoryName<TContract>> = Parameters<ContractErrorFactory<TContract, TFactoryName>>;
|
|
102
|
+
/**
|
|
103
|
+
* Tuple form accepted when configuring a thrown error factory action.
|
|
104
|
+
* @public
|
|
105
|
+
*/
|
|
106
|
+
type ContractErrorFactoryArguments<TContract extends SutContract, TFactoryName extends ContractErrorFactoryName<TContract>> = ContractErrorFactoryParameters<TContract, TFactoryName>["length"] extends 0 ? [] : 0 extends ContractErrorFactoryParameters<TContract, TFactoryName>["length"] ? [input?: ContractErrorFactoryInput<TContract, TFactoryName>] : [input: ContractErrorFactoryInput<TContract, TFactoryName>];
|
|
107
|
+
/**
|
|
108
|
+
* Serialized identifier for a wrapped function or service method target.
|
|
109
|
+
* @public
|
|
110
|
+
*/
|
|
111
|
+
type SerializedTarget = {
|
|
112
|
+
/**
|
|
113
|
+
* Marks the target as a service method.
|
|
114
|
+
*/
|
|
115
|
+
kind: "service-method";
|
|
116
|
+
/**
|
|
117
|
+
* Service name that owns the intercepted method.
|
|
118
|
+
*/
|
|
119
|
+
service: string;
|
|
120
|
+
/**
|
|
121
|
+
* Method name being intercepted on the service.
|
|
122
|
+
*/
|
|
123
|
+
method: string;
|
|
124
|
+
} | {
|
|
125
|
+
/**
|
|
126
|
+
* Marks the target as a top-level function.
|
|
127
|
+
*/
|
|
128
|
+
kind: "function";
|
|
129
|
+
/**
|
|
130
|
+
* Function name being intercepted.
|
|
131
|
+
*/
|
|
132
|
+
function: string;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Serialized scenario action executed when a rule matches.
|
|
136
|
+
* @public
|
|
137
|
+
*/
|
|
138
|
+
type SerializedAction = {
|
|
139
|
+
/**
|
|
140
|
+
* Marks the action as returning a value.
|
|
141
|
+
*/
|
|
142
|
+
kind: "return";
|
|
143
|
+
/**
|
|
144
|
+
* Value returned to the caller when the rule matches.
|
|
145
|
+
*/
|
|
146
|
+
value: unknown;
|
|
147
|
+
} | {
|
|
148
|
+
/**
|
|
149
|
+
* Marks the action as throwing a plain error message.
|
|
150
|
+
*/
|
|
151
|
+
kind: "throw-message";
|
|
152
|
+
/**
|
|
153
|
+
* Error message thrown when the rule matches.
|
|
154
|
+
*/
|
|
155
|
+
message: string;
|
|
156
|
+
} | {
|
|
157
|
+
/**
|
|
158
|
+
* Marks the action as invoking an error factory.
|
|
159
|
+
*/
|
|
160
|
+
kind: "throw-factory";
|
|
161
|
+
/**
|
|
162
|
+
* Registered error factory name to invoke.
|
|
163
|
+
*/
|
|
164
|
+
factory: string;
|
|
165
|
+
/**
|
|
166
|
+
* Optional input passed to the error factory.
|
|
167
|
+
*/
|
|
168
|
+
input?: unknown;
|
|
169
|
+
};
|
|
170
|
+
/**
|
|
171
|
+
* Serialized interception rule for a single call target and call number.
|
|
172
|
+
* @public
|
|
173
|
+
*/
|
|
174
|
+
type SerializedRule = {
|
|
175
|
+
/**
|
|
176
|
+
* Target that this rule applies to.
|
|
177
|
+
*/
|
|
178
|
+
target: SerializedTarget;
|
|
179
|
+
/**
|
|
180
|
+
* One-based call number that activates this rule.
|
|
181
|
+
*/
|
|
182
|
+
callNumber: number;
|
|
183
|
+
/**
|
|
184
|
+
* Action executed when the target is called at the matching count.
|
|
185
|
+
*/
|
|
186
|
+
action: SerializedAction;
|
|
187
|
+
};
|
|
188
|
+
/**
|
|
189
|
+
* Serialized scenario document persisted by storage adapters.
|
|
190
|
+
* @public
|
|
191
|
+
*/
|
|
192
|
+
type SerializedScenario = {
|
|
193
|
+
/**
|
|
194
|
+
* Stable identifier for the persisted scenario.
|
|
195
|
+
*/
|
|
196
|
+
id: string;
|
|
197
|
+
/**
|
|
198
|
+
* Persisted schema version for the scenario document.
|
|
199
|
+
*/
|
|
200
|
+
version: 1;
|
|
201
|
+
/**
|
|
202
|
+
* ISO timestamp when the scenario was created.
|
|
203
|
+
*/
|
|
204
|
+
createdAt: string;
|
|
205
|
+
/**
|
|
206
|
+
* Ordered list of interception rules stored in the scenario.
|
|
207
|
+
*/
|
|
208
|
+
rules: SerializedRule[];
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* Async-local context that carries the active runtime scenario id.
|
|
212
|
+
* @public
|
|
213
|
+
*/
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Builder API for assigning an action to a single intercepted call.
|
|
217
|
+
* @public
|
|
218
|
+
*/
|
|
219
|
+
type ScenarioActionBuilder<TContract extends SutContract, TReturnValue> = {
|
|
220
|
+
returns(value: TReturnValue): ScenarioBuilder<TContract>;
|
|
221
|
+
throwsMessage(message: string): ScenarioBuilder<TContract>;
|
|
222
|
+
throwsFactory<TFactoryName extends ContractErrorFactoryName<TContract>>(factory: TFactoryName, ...args: ContractErrorFactoryArguments<TContract, TFactoryName>): ScenarioBuilder<TContract>;
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Builder API for configuring rules for a named function.
|
|
226
|
+
* @public
|
|
227
|
+
*/
|
|
228
|
+
type ScenarioFunctionRuleBuilder<TContract extends SutContract, TFunctionName extends ContractFunctionName<TContract>> = {
|
|
229
|
+
onCall(callNumber: number): ScenarioActionBuilder<TContract, ContractFunctionReturnValue<TContract, TFunctionName>>;
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Builder API for configuring rules for a named service method.
|
|
233
|
+
* @public
|
|
234
|
+
*/
|
|
235
|
+
type ScenarioServiceMethodRuleBuilder<TContract extends SutContract, TServiceName extends ContractServiceName<TContract>, TMethodName extends ContractServiceMethodName<TContract, TServiceName>> = {
|
|
236
|
+
onCall(callNumber: number): ScenarioActionBuilder<TContract, ContractServiceMethodReturnValue<TContract, TServiceName, TMethodName>>;
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* Builder API for selecting a method on a named service.
|
|
240
|
+
* @public
|
|
241
|
+
*/
|
|
242
|
+
type ScenarioServiceRuleBuilder<TContract extends SutContract, TServiceName extends ContractServiceName<TContract>> = {
|
|
243
|
+
method<TMethodName extends ContractServiceMethodName<TContract, TServiceName>>(method: TMethodName): ScenarioServiceMethodRuleBuilder<TContract, TServiceName, TMethodName>;
|
|
244
|
+
};
|
|
245
|
+
/**
|
|
246
|
+
* Scenario builder API used to author and persist interception rules.
|
|
247
|
+
* @public
|
|
248
|
+
*/
|
|
249
|
+
type ScenarioBuilder<TContract extends SutContract> = {
|
|
250
|
+
/**
|
|
251
|
+
* Phantom contract marker that preserves generic inference.
|
|
252
|
+
*/
|
|
253
|
+
readonly __contract?: TContract;
|
|
254
|
+
/**
|
|
255
|
+
* Scenario id that will be used for persistence and runtime lookup.
|
|
256
|
+
*/
|
|
257
|
+
readonly id: string;
|
|
258
|
+
service<TServiceName extends ContractServiceName<TContract>>(service: TServiceName): ScenarioServiceRuleBuilder<TContract, TServiceName>;
|
|
259
|
+
fn<TFunctionName extends ContractFunctionName<TContract>>(fn: TFunctionName): ScenarioFunctionRuleBuilder<TContract, TFunctionName>;
|
|
260
|
+
save(): Promise<void>;
|
|
261
|
+
dispose(): Promise<void>;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
//#endregion
|
|
265
|
+
//#region ../definitely-fine/src/services/interfaces/IScenarioStorageAdapter.d.ts
|
|
266
|
+
/**
|
|
267
|
+
* Runtime API for wrapping contract functions and services.
|
|
268
|
+
* @public
|
|
269
|
+
*/
|
|
270
|
+
/**
|
|
271
|
+
* Storage contract for loading, saving, and deleting persisted scenarios.
|
|
272
|
+
* @public
|
|
273
|
+
*/
|
|
274
|
+
interface IScenarioStorageAdapter {
|
|
275
|
+
saveScenario(scenario: SerializedScenario): Promise<void>;
|
|
276
|
+
loadScenario(scenarioId: string): SerializedScenario | undefined;
|
|
277
|
+
deleteScenario(scenarioId: string): Promise<void>;
|
|
278
|
+
describeScenarioLocation?(scenarioId: string): string;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
//#endregion
|
|
282
|
+
//#region ../definitely-fine/src/index.d.ts
|
|
283
|
+
//# sourceMappingURL=IScenarioStorageAdapter.d.ts.map
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Storage options for persisting scenarios.
|
|
287
|
+
*
|
|
288
|
+
* Pass an explicit `adapter` to route persistence through custom storage, or a
|
|
289
|
+
* `directory` to keep using the built-in file adapter behavior.
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* ```ts
|
|
293
|
+
* import {
|
|
294
|
+
* JsonScenarioStorageAdapter,
|
|
295
|
+
* createScenario,
|
|
296
|
+
* type IScenarioStorageAdapter,
|
|
297
|
+
* } from "definitely-fine";
|
|
298
|
+
*
|
|
299
|
+
* const customAdapter: IScenarioStorageAdapter = {
|
|
300
|
+
* async deleteScenario(_scenarioId) {},
|
|
301
|
+
* loadScenario(_scenarioId) {
|
|
302
|
+
* return undefined;
|
|
303
|
+
* },
|
|
304
|
+
* async saveScenario(_scenario) {},
|
|
305
|
+
* };
|
|
306
|
+
*
|
|
307
|
+
* createScenario({
|
|
308
|
+
* adapter: new JsonScenarioStorageAdapter({}),
|
|
309
|
+
* });
|
|
310
|
+
*
|
|
311
|
+
* createScenario({
|
|
312
|
+
* adapter: customAdapter,
|
|
313
|
+
* });
|
|
314
|
+
* ```
|
|
315
|
+
* @public
|
|
316
|
+
*/
|
|
317
|
+
type ScenarioOptions = {
|
|
318
|
+
/**
|
|
319
|
+
* Omit storage options to use the built-in JSON adapter with its inferred default directory.
|
|
320
|
+
*/
|
|
321
|
+
adapter?: never;
|
|
322
|
+
/**
|
|
323
|
+
* Omit storage options to use the built-in JSON adapter with its inferred default directory.
|
|
324
|
+
*/
|
|
325
|
+
directory?: never;
|
|
326
|
+
} | {
|
|
327
|
+
/**
|
|
328
|
+
* Directory where the scenario should be saved.
|
|
329
|
+
*/
|
|
330
|
+
directory: string;
|
|
331
|
+
/**
|
|
332
|
+
* Explicit adapters cannot be combined with a directory.
|
|
333
|
+
*/
|
|
334
|
+
adapter?: never;
|
|
335
|
+
} | {
|
|
336
|
+
/**
|
|
337
|
+
* Custom adapter used to persist the scenario.
|
|
338
|
+
*/
|
|
339
|
+
adapter: IScenarioStorageAdapter;
|
|
340
|
+
/**
|
|
341
|
+
* Explicit adapters cannot be combined with a directory.
|
|
342
|
+
*/
|
|
343
|
+
directory?: never;
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
//#endregion
|
|
347
|
+
//#region src/index.d.ts
|
|
348
|
+
type BrowserContextFactory<TBrowserContext> = {
|
|
349
|
+
newContext(options?: BrowserContextOptions): Promise<TBrowserContext>;
|
|
350
|
+
};
|
|
351
|
+
type BrowserPageFactory<TPage> = {
|
|
352
|
+
newPage(): Promise<TPage>;
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* Playwright-aware scenario builder that can create preconfigured browser contexts.
|
|
356
|
+
* @public
|
|
357
|
+
*/
|
|
358
|
+
type PlaywrightScenario<TContract extends SutContract> = ScenarioBuilder<TContract> & {
|
|
359
|
+
/**
|
|
360
|
+
* Header name used to activate the persisted scenario at runtime.
|
|
361
|
+
*/
|
|
362
|
+
readonly headerName: string;
|
|
363
|
+
/**
|
|
364
|
+
* Request headers that activate the persisted scenario in browser-driven tests.
|
|
365
|
+
*/
|
|
366
|
+
readonly headers: Record<string, string>;
|
|
367
|
+
/**
|
|
368
|
+
* Creates a new browser context with the scenario header already applied.
|
|
369
|
+
*/
|
|
370
|
+
createContext<TBrowserContext>(browser: BrowserContextFactory<TBrowserContext>, options?: BrowserContextOptions): Promise<TBrowserContext>;
|
|
371
|
+
/**
|
|
372
|
+
* Creates a new page from a browser context that already includes the scenario header.
|
|
373
|
+
*/
|
|
374
|
+
createPage<TPage, TBrowserContext extends BrowserPageFactory<TPage>>(browser: BrowserContextFactory<TBrowserContext>, options?: BrowserContextOptions): Promise<TPage>;
|
|
375
|
+
};
|
|
376
|
+
/**
|
|
377
|
+
* Options for creating a Playwright-aware definitely-fine scenario.
|
|
378
|
+
* @public
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* ```ts
|
|
382
|
+
* import { createScenario } from "@definitely-fine/playwright";
|
|
383
|
+
*
|
|
384
|
+
* const scenario = createScenario({
|
|
385
|
+
* headerName: "x-scenario-id",
|
|
386
|
+
* });
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
389
|
+
type CreatePlaywrightScenarioOptions = ScenarioOptions & {
|
|
390
|
+
/**
|
|
391
|
+
* Header name used to activate the saved scenario in browser requests.
|
|
392
|
+
*/
|
|
393
|
+
headerName: string;
|
|
394
|
+
};
|
|
395
|
+
/**
|
|
396
|
+
* Creates a definitely-fine scenario builder with helpers for Playwright browser contexts.
|
|
397
|
+
* @public
|
|
398
|
+
*
|
|
399
|
+
* @example
|
|
400
|
+
* ```ts
|
|
401
|
+
* import { test } from "@playwright/test";
|
|
402
|
+
* import { createScenario } from "@definitely-fine/playwright";
|
|
403
|
+
*
|
|
404
|
+
* test("uses a scenario-backed page", async ({ browser }) => {
|
|
405
|
+
* const scenario = createScenario({
|
|
406
|
+
* headerName: "x-scenario-id",
|
|
407
|
+
* });
|
|
408
|
+
*
|
|
409
|
+
* await scenario.save();
|
|
410
|
+
*
|
|
411
|
+
* const page = await scenario.createPage(browser);
|
|
412
|
+
* await page.goto("/");
|
|
413
|
+
* });
|
|
414
|
+
* ```
|
|
415
|
+
*/
|
|
416
|
+
declare function createScenario<TContract extends SutContract>(options: CreatePlaywrightScenarioOptions): PlaywrightScenario<TContract>;
|
|
417
|
+
|
|
418
|
+
//#endregion
|
|
419
|
+
export { CreatePlaywrightScenarioOptions, PlaywrightScenario, createScenario };
|
|
420
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../definitely-fine/src/types.ts","../../definitely-fine/src/services/interfaces/IScenarioStorageAdapter.ts","../../definitely-fine/src/index.ts","../src/index.ts"],"sourcesContent":null,"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { createScenario as createScenario$1 } from "definitely-fine";
|
|
2
|
+
|
|
3
|
+
//#region src/index.ts
|
|
4
|
+
function mergeScenarioHeaders(extraHTTPHeaders, scenarioHeaders) {
|
|
5
|
+
const mergedHeaders = new Headers(extraHTTPHeaders);
|
|
6
|
+
for (const [name, value] of Object.entries(scenarioHeaders)) mergedHeaders.set(name, value);
|
|
7
|
+
return Object.fromEntries(mergedHeaders.entries());
|
|
8
|
+
}
|
|
9
|
+
function createPlaywrightScenarioHelpers(scenario, headerName) {
|
|
10
|
+
const headers = { [headerName]: scenario.id };
|
|
11
|
+
return {
|
|
12
|
+
headerName,
|
|
13
|
+
headers,
|
|
14
|
+
async createContext(browser, options = {}) {
|
|
15
|
+
return browser.newContext({
|
|
16
|
+
...options,
|
|
17
|
+
extraHTTPHeaders: mergeScenarioHeaders(options.extraHTTPHeaders, headers)
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
async createPage(browser, options = {}) {
|
|
21
|
+
const context = await this.createContext(browser, options);
|
|
22
|
+
return context.newPage();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Creates a definitely-fine scenario builder with helpers for Playwright browser contexts.
|
|
28
|
+
* @public
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* import { test } from "@playwright/test";
|
|
33
|
+
* import { createScenario } from "@definitely-fine/playwright";
|
|
34
|
+
*
|
|
35
|
+
* test("uses a scenario-backed page", async ({ browser }) => {
|
|
36
|
+
* const scenario = createScenario({
|
|
37
|
+
* headerName: "x-scenario-id",
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* await scenario.save();
|
|
41
|
+
*
|
|
42
|
+
* const page = await scenario.createPage(browser);
|
|
43
|
+
* await page.goto("/");
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
function createScenario(options) {
|
|
48
|
+
const scenario = createScenario$1(options);
|
|
49
|
+
return Object.assign(scenario, createPlaywrightScenarioHelpers(scenario, options.headerName));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
export { createScenario };
|
|
54
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["extraHTTPHeaders: BrowserContextOptions[\"extraHTTPHeaders\"]","scenarioHeaders: Record<string, string>","scenario: ScenarioBuilder<TContract>","headerName: string","browser: BrowserContextFactory<TBrowserContext>","options: BrowserContextOptions","options: CreatePlaywrightScenarioOptions"],"sources":["../src/index.ts"],"sourcesContent":["import { createScenario as createCoreScenario } from \"definitely-fine\";\n\nimport type { BrowserContextOptions } from \"@playwright/test\";\nimport type {\n ScenarioBuilder,\n ScenarioOptions,\n SutContract,\n} from \"definitely-fine\";\n\ntype BrowserContextFactory<TBrowserContext> = {\n newContext(options?: BrowserContextOptions): Promise<TBrowserContext>;\n};\n\ntype BrowserPageFactory<TPage> = {\n newPage(): Promise<TPage>;\n};\n\n/**\n * Playwright-aware scenario builder that can create preconfigured browser contexts.\n * @public\n */\nexport type PlaywrightScenario<TContract extends SutContract> =\n ScenarioBuilder<TContract> & {\n /**\n * Header name used to activate the persisted scenario at runtime.\n */\n readonly headerName: string;\n /**\n * Request headers that activate the persisted scenario in browser-driven tests.\n */\n readonly headers: Record<string, string>;\n /**\n * Creates a new browser context with the scenario header already applied.\n */\n createContext<TBrowserContext>(\n browser: BrowserContextFactory<TBrowserContext>,\n options?: BrowserContextOptions,\n ): Promise<TBrowserContext>;\n /**\n * Creates a new page from a browser context that already includes the scenario header.\n */\n createPage<TPage, TBrowserContext extends BrowserPageFactory<TPage>>(\n browser: BrowserContextFactory<TBrowserContext>,\n options?: BrowserContextOptions,\n ): Promise<TPage>;\n };\n\n/**\n * Options for creating a Playwright-aware definitely-fine scenario.\n * @public\n *\n * @example\n * ```ts\n * import { createScenario } from \"@definitely-fine/playwright\";\n *\n * const scenario = createScenario({\n * headerName: \"x-scenario-id\",\n * });\n * ```\n */\nexport type CreatePlaywrightScenarioOptions = ScenarioOptions & {\n /**\n * Header name used to activate the saved scenario in browser requests.\n */\n headerName: string;\n};\n\nfunction mergeScenarioHeaders(\n extraHTTPHeaders: BrowserContextOptions[\"extraHTTPHeaders\"],\n scenarioHeaders: Record<string, string>,\n): Record<string, string> {\n const mergedHeaders = new Headers(extraHTTPHeaders);\n\n for (const [name, value] of Object.entries(scenarioHeaders)) {\n mergedHeaders.set(name, value);\n }\n\n return Object.fromEntries(mergedHeaders.entries());\n}\n\nfunction createPlaywrightScenarioHelpers<TContract extends SutContract>(\n scenario: ScenarioBuilder<TContract>,\n headerName: string,\n) {\n const headers = {\n [headerName]: scenario.id,\n };\n\n return {\n headerName,\n headers,\n async createContext<TBrowserContext>(\n browser: BrowserContextFactory<TBrowserContext>,\n options: BrowserContextOptions = {},\n ): Promise<TBrowserContext> {\n return browser.newContext({\n ...options,\n extraHTTPHeaders: mergeScenarioHeaders(\n options.extraHTTPHeaders,\n headers,\n ),\n });\n },\n async createPage<TPage, TBrowserContext extends BrowserPageFactory<TPage>>(\n browser: BrowserContextFactory<TBrowserContext>,\n options: BrowserContextOptions = {},\n ): Promise<TPage> {\n const context = await this.createContext(browser, options);\n\n return context.newPage();\n },\n };\n}\n\n/**\n * Creates a definitely-fine scenario builder with helpers for Playwright browser contexts.\n * @public\n *\n * @example\n * ```ts\n * import { test } from \"@playwright/test\";\n * import { createScenario } from \"@definitely-fine/playwright\";\n *\n * test(\"uses a scenario-backed page\", async ({ browser }) => {\n * const scenario = createScenario({\n * headerName: \"x-scenario-id\",\n * });\n *\n * await scenario.save();\n *\n * const page = await scenario.createPage(browser);\n * await page.goto(\"/\");\n * });\n * ```\n */\nexport function createScenario<TContract extends SutContract>(\n options: CreatePlaywrightScenarioOptions,\n): PlaywrightScenario<TContract> {\n const scenario = createCoreScenario<TContract>(options);\n\n return Object.assign(\n scenario,\n createPlaywrightScenarioHelpers(scenario, options.headerName),\n );\n}\n"],"mappings":";;;AAmEA,SAAS,qBACPA,kBACAC,iBACwB;CACxB,MAAM,gBAAgB,IAAI,QAAQ;AAElC,MAAK,MAAM,CAAC,MAAM,MAAM,IAAI,OAAO,QAAQ,gBAAgB,CACzD,eAAc,IAAI,MAAM,MAAM;AAGhC,QAAO,OAAO,YAAY,cAAc,SAAS,CAAC;AACnD;AAED,SAAS,gCACPC,UACAC,YACA;CACA,MAAM,UAAU,GACb,aAAa,SAAS,GACxB;AAED,QAAO;EACL;EACA;EACA,MAAM,cACJC,SACAC,UAAiC,CAAE,GACT;AAC1B,UAAO,QAAQ,WAAW;IACxB,GAAG;IACH,kBAAkB,qBAChB,QAAQ,kBACR,QACD;GACF,EAAC;EACH;EACD,MAAM,WACJD,SACAC,UAAiC,CAAE,GACnB;GAChB,MAAM,UAAU,MAAM,KAAK,cAAc,SAAS,QAAQ;AAE1D,UAAO,QAAQ,SAAS;EACzB;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;AAuBD,SAAgB,eACdC,SAC+B;CAC/B,MAAM,WAAW,iBAA8B,QAAQ;AAEvD,QAAO,OAAO,OACZ,UACA,gCAAgC,UAAU,QAAQ,WAAW,CAC9D;AACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@definitely-fine/playwright",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Playwright helpers for definitely-fine.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"definitely-fine": "0.1.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@playwright/test": "^1.56.1"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@playwright/test": ">=1.56"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=22"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsdown src/index.ts --format esm --dts --publint",
|
|
36
|
+
"typecheck": "tsc --project tsconfig.json"
|
|
37
|
+
}
|
|
38
|
+
}
|