@chaos-maker/playwright 0.4.0 → 0.5.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/README.md +108 -2
- package/dist/{chunk-KHKPTES5.js → chunk-IJDMHBUQ.js} +95 -5
- package/dist/fixture.cjs +98 -2
- package/dist/fixture.d.cts +5 -1
- package/dist/fixture.d.ts +5 -1
- package/dist/fixture.js +10 -2
- package/dist/index.cjs +101 -4
- package/dist/index.d.cts +31 -3
- package/dist/index.d.ts +31 -3
- package/dist/index.js +17 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -59,6 +59,27 @@ test('handles slow network', async ({ page, chaos }) => {
|
|
|
59
59
|
|
|
60
60
|
### With Presets
|
|
61
61
|
|
|
62
|
+
Drop a built-in preset by name with the declarative `presets` field:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
await injectChaos(page, { presets: ['slow-api'] });
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Register your own bundle inline via `customPresets`:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
await injectChaos(page, {
|
|
72
|
+
customPresets: {
|
|
73
|
+
'team-flow': {
|
|
74
|
+
network: { failures: [{ urlPattern: '/checkout', statusCode: 503, probability: 1 }] },
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
presets: ['team-flow'],
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The legacy spread style still works for migration:
|
|
82
|
+
|
|
62
83
|
```ts
|
|
63
84
|
import { test, expect } from '@playwright/test';
|
|
64
85
|
import { presets } from '@chaos-maker/core';
|
|
@@ -90,6 +111,49 @@ test('checkout handles combined chaos', async ({ page }) => {
|
|
|
90
111
|
});
|
|
91
112
|
```
|
|
92
113
|
|
|
114
|
+
### Rule Groups
|
|
115
|
+
|
|
116
|
+
Use Rule Groups to toggle a set of rules during a test without reinjecting chaos.
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { test, expect } from '@playwright/test';
|
|
120
|
+
import { ChaosConfigBuilder } from '@chaos-maker/core';
|
|
121
|
+
import {
|
|
122
|
+
injectChaos,
|
|
123
|
+
enableGroup,
|
|
124
|
+
disableGroup,
|
|
125
|
+
enableSWGroup,
|
|
126
|
+
disableSWGroup,
|
|
127
|
+
} from '@chaos-maker/playwright';
|
|
128
|
+
|
|
129
|
+
test('toggles checkout chaos', async ({ page }) => {
|
|
130
|
+
const config = new ChaosConfigBuilder()
|
|
131
|
+
.defineGroup('payments', { enabled: false })
|
|
132
|
+
.inGroup('payments')
|
|
133
|
+
.failRequests('/api/pay', 503, 1)
|
|
134
|
+
.build();
|
|
135
|
+
|
|
136
|
+
await injectChaos(page, config);
|
|
137
|
+
await page.goto('/checkout');
|
|
138
|
+
|
|
139
|
+
await enableGroup(page, 'payments');
|
|
140
|
+
await expect(page.getByText('Try again')).toBeVisible();
|
|
141
|
+
|
|
142
|
+
await disableGroup(page, 'payments');
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
With the fixture, the same helpers are available as `chaos.enableGroup(name)` and `chaos.disableGroup(name)`.
|
|
147
|
+
|
|
148
|
+
For Service Worker rules, use the SW helpers after `injectSWChaos`:
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
await enableSWGroup(page, 'payments');
|
|
152
|
+
await disableSWGroup(page, 'payments');
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Browser-side `enableGroup` and `disableGroup` affect page rules from `injectChaos`. `enableSWGroup` and `disableSWGroup` affect Service Worker rules from `injectSWChaos`.
|
|
156
|
+
|
|
93
157
|
### SSE and GraphQL
|
|
94
158
|
|
|
95
159
|
```ts
|
|
@@ -133,6 +197,14 @@ Stop chaos and restore original `fetch`/`XHR`/DOM behavior.
|
|
|
133
197
|
|
|
134
198
|
Retrieve the chaos event log from the page. Returns `ChaosEvent[]` — every chaos check emitted since injection, with `applied: true/false`.
|
|
135
199
|
|
|
200
|
+
### `enableGroup(page, name)` / `disableGroup(page, name)`
|
|
201
|
+
|
|
202
|
+
Toggle a browser-side Rule Group at runtime.
|
|
203
|
+
|
|
204
|
+
### `enableSWGroup(page, name, opts?)` / `disableSWGroup(page, name, opts?)`
|
|
205
|
+
|
|
206
|
+
Toggle a Service Worker Rule Group at runtime. Pass `opts.timeoutMs` to override the Service Worker acknowledgement timeout.
|
|
207
|
+
|
|
136
208
|
### Fixture: `chaos`
|
|
137
209
|
|
|
138
210
|
Available when importing `test` from `@chaos-maker/playwright/fixture`:
|
|
@@ -140,6 +212,29 @@ Available when importing `test` from `@chaos-maker/playwright/fixture`:
|
|
|
140
212
|
- `chaos.inject(config)` — same as `injectChaos(page, config)`
|
|
141
213
|
- `chaos.remove()` — same as `removeChaos(page)` (also called automatically after each test)
|
|
142
214
|
- `chaos.getLog()` — same as `getChaosLog(page)`
|
|
215
|
+
- `chaos.enableGroup(name)` — same as `enableGroup(page, name)`
|
|
216
|
+
- `chaos.disableGroup(name)` — same as `disableGroup(page, name)`
|
|
217
|
+
- `chaos.enableSWGroup(name, opts?)` — same as `enableSWGroup(page, name, opts)`
|
|
218
|
+
- `chaos.disableSWGroup(name, opts?)` — same as `disableSWGroup(page, name, opts)`
|
|
219
|
+
|
|
220
|
+
## Validation
|
|
221
|
+
|
|
222
|
+
`injectChaos` validates the config from Node BEFORE any page touch. A malformed config throws `ChaosConfigError` synchronously from the test runner — your test fails before navigation, not in the browser console. `ChaosConfigError.issues` is a structured `ValidationIssue[]` with `path`, `code`, `ruleType`, and optional `expected` / `received`. See the [Rule Validation concept page](https://chaos-maker-dev.github.io/chaos-maker/concepts/validation/).
|
|
223
|
+
|
|
224
|
+
```ts
|
|
225
|
+
import { injectChaos, ChaosConfigError } from '@chaos-maker/playwright';
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
await injectChaos(page, config, {
|
|
229
|
+
validation: { unknownFields: 'warn' },
|
|
230
|
+
});
|
|
231
|
+
} catch (e) {
|
|
232
|
+
if (e instanceof ChaosConfigError) {
|
|
233
|
+
for (const issue of e.issues) console.error(issue.path, issue.code, issue.message);
|
|
234
|
+
}
|
|
235
|
+
throw e;
|
|
236
|
+
}
|
|
237
|
+
```
|
|
143
238
|
|
|
144
239
|
## Debugging with trace
|
|
145
240
|
|
|
@@ -199,18 +294,29 @@ importScripts('/chaos-maker-sw.js');
|
|
|
199
294
|
```
|
|
200
295
|
|
|
201
296
|
```ts
|
|
202
|
-
import {
|
|
297
|
+
import {
|
|
298
|
+
injectSWChaos,
|
|
299
|
+
removeSWChaos,
|
|
300
|
+
getSWChaosLog,
|
|
301
|
+
enableSWGroup,
|
|
302
|
+
disableSWGroup,
|
|
303
|
+
} from '@chaos-maker/playwright';
|
|
203
304
|
|
|
204
305
|
test('SW-fetched /api returns 503', async ({ page }) => {
|
|
205
306
|
await page.goto('/app-with-sw/');
|
|
206
307
|
// wait for controller after your app's SW registration
|
|
207
308
|
await injectSWChaos(page, {
|
|
208
|
-
|
|
309
|
+
groups: [{ name: 'payments', enabled: false }],
|
|
310
|
+
network: {
|
|
311
|
+
failures: [{ urlPattern: '/api/data', statusCode: 503, probability: 1, group: 'payments' }],
|
|
312
|
+
},
|
|
209
313
|
seed: 1,
|
|
210
314
|
});
|
|
315
|
+
await enableSWGroup(page, 'payments');
|
|
211
316
|
await page.click('#trigger');
|
|
212
317
|
const log = await getSWChaosLog(page);
|
|
213
318
|
expect(log.some(e => e.type === 'network:failure' && e.applied)).toBe(true);
|
|
319
|
+
await disableSWGroup(page, 'payments');
|
|
214
320
|
await removeSWChaos(page);
|
|
215
321
|
});
|
|
216
322
|
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { serializeForTransport } from "@chaos-maker/core";
|
|
2
|
+
import { serializeForTransport, validateChaosConfig as validateChaosConfig2 } from "@chaos-maker/core";
|
|
3
3
|
import { resolve, dirname } from "path";
|
|
4
4
|
import { createRequire } from "module";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
@@ -50,6 +50,7 @@ function truncate(s, max) {
|
|
|
50
50
|
return `\u2026${s.slice(-(max - 1))}`;
|
|
51
51
|
}
|
|
52
52
|
function shouldEmitStep(event, verbose) {
|
|
53
|
+
if (event.type === "debug") return false;
|
|
53
54
|
if (event.applied) return true;
|
|
54
55
|
return verbose;
|
|
55
56
|
}
|
|
@@ -108,9 +109,14 @@ async function createTraceReporter(page, testInfo, opts = {}) {
|
|
|
108
109
|
};
|
|
109
110
|
}
|
|
110
111
|
|
|
112
|
+
// src/index.ts
|
|
113
|
+
import { Logger } from "@chaos-maker/core";
|
|
114
|
+
import { validateChaosConfig as validateChaosConfig3, ChaosConfigError } from "@chaos-maker/core";
|
|
115
|
+
|
|
111
116
|
// src/sw.ts
|
|
112
|
-
import {
|
|
117
|
+
import { validateChaosConfig, SW_BRIDGE_SOURCE } from "@chaos-maker/core";
|
|
113
118
|
var BRIDGE_INIT_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.sw.bridgeInit");
|
|
119
|
+
var DEFAULT_SW_TOGGLE_TIMEOUT = 2e3;
|
|
114
120
|
async function ensurePageBridge(page) {
|
|
115
121
|
if (!page[BRIDGE_INIT_KEY]) {
|
|
116
122
|
await page.addInitScript({ content: SW_BRIDGE_SOURCE });
|
|
@@ -120,7 +126,7 @@ async function ensurePageBridge(page) {
|
|
|
120
126
|
});
|
|
121
127
|
}
|
|
122
128
|
async function injectSWChaos(page, config, opts = {}) {
|
|
123
|
-
const validated =
|
|
129
|
+
const validated = validateChaosConfig(config, opts.validation);
|
|
124
130
|
const timeoutMs = opts.timeoutMs ?? 1e4;
|
|
125
131
|
await ensurePageBridge(page);
|
|
126
132
|
const result = await page.evaluate(
|
|
@@ -146,6 +152,38 @@ async function removeSWChaos(page, opts = {}) {
|
|
|
146
152
|
).catch(() => {
|
|
147
153
|
});
|
|
148
154
|
}
|
|
155
|
+
async function enableSWGroup(page, name, opts = {}) {
|
|
156
|
+
if (typeof name !== "string") {
|
|
157
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
158
|
+
}
|
|
159
|
+
const nameNorm = name.trim();
|
|
160
|
+
if (!nameNorm) {
|
|
161
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
162
|
+
}
|
|
163
|
+
await toggleSWGroup(page, nameNorm, true, opts);
|
|
164
|
+
}
|
|
165
|
+
async function disableSWGroup(page, name, opts = {}) {
|
|
166
|
+
if (typeof name !== "string") {
|
|
167
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
168
|
+
}
|
|
169
|
+
const nameNorm = name.trim();
|
|
170
|
+
if (!nameNorm) {
|
|
171
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
172
|
+
}
|
|
173
|
+
await toggleSWGroup(page, nameNorm, false, opts);
|
|
174
|
+
}
|
|
175
|
+
async function toggleSWGroup(page, name, enabled, opts) {
|
|
176
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_SW_TOGGLE_TIMEOUT;
|
|
177
|
+
await ensurePageBridge(page);
|
|
178
|
+
await page.evaluate(
|
|
179
|
+
async ({ n, e, t }) => {
|
|
180
|
+
const bridge = globalThis.__chaosMakerSWBridge;
|
|
181
|
+
if (!bridge) throw new Error("[chaos-maker] SW bridge missing \u2014 ensurePageBridge failed");
|
|
182
|
+
await bridge.toggleGroup(n, e, t);
|
|
183
|
+
},
|
|
184
|
+
{ n: name, e: enabled, t: timeoutMs }
|
|
185
|
+
);
|
|
186
|
+
}
|
|
149
187
|
async function getSWChaosLog(page) {
|
|
150
188
|
return page.evaluate(() => {
|
|
151
189
|
const bridge = globalThis.__chaosMakerSWBridge;
|
|
@@ -178,6 +216,7 @@ function getCoreUmdPath() {
|
|
|
178
216
|
}
|
|
179
217
|
var TRACE_HANDLE_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.traceHandle");
|
|
180
218
|
async function injectChaos(page, config, opts = {}) {
|
|
219
|
+
const validated = validateChaosConfig2(config, opts.validation);
|
|
181
220
|
const umdPath = getCoreUmdPath();
|
|
182
221
|
const tracingEnabled = resolveTracing(opts);
|
|
183
222
|
if (tracingEnabled) {
|
|
@@ -192,7 +231,7 @@ async function injectChaos(page, config, opts = {}) {
|
|
|
192
231
|
page[TRACE_HANDLE_KEY] = handle;
|
|
193
232
|
}
|
|
194
233
|
}
|
|
195
|
-
const serialized = serializeForTransport(
|
|
234
|
+
const serialized = serializeForTransport(validated);
|
|
196
235
|
await page.addInitScript((cfg) => {
|
|
197
236
|
const win = globalThis;
|
|
198
237
|
win.__CHAOS_CONFIG__ = cfg;
|
|
@@ -234,6 +273,50 @@ async function getChaosLog(page) {
|
|
|
234
273
|
return [];
|
|
235
274
|
});
|
|
236
275
|
}
|
|
276
|
+
async function enableGroup(page, name) {
|
|
277
|
+
if (typeof name !== "string") {
|
|
278
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
279
|
+
}
|
|
280
|
+
const nameNorm = name.trim();
|
|
281
|
+
if (!nameNorm) {
|
|
282
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
283
|
+
}
|
|
284
|
+
await page.evaluate(({ n }) => {
|
|
285
|
+
const utils = globalThis.chaosUtils;
|
|
286
|
+
if (!utils || !utils.instance) {
|
|
287
|
+
throw new Error("[chaos-maker] no chaos instance on page \u2014 call injectChaos first");
|
|
288
|
+
}
|
|
289
|
+
if (typeof utils.enableGroup !== "function") {
|
|
290
|
+
throw new Error("[chaos-maker] enableGroup API unavailable");
|
|
291
|
+
}
|
|
292
|
+
const result = utils.enableGroup(n);
|
|
293
|
+
if (result && result.success === false) {
|
|
294
|
+
throw new Error(`[chaos-maker] enableGroup('${n}') failed: ${result.message}`);
|
|
295
|
+
}
|
|
296
|
+
}, { n: nameNorm });
|
|
297
|
+
}
|
|
298
|
+
async function disableGroup(page, name) {
|
|
299
|
+
if (typeof name !== "string") {
|
|
300
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
301
|
+
}
|
|
302
|
+
const nameNorm = name.trim();
|
|
303
|
+
if (!nameNorm) {
|
|
304
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
305
|
+
}
|
|
306
|
+
await page.evaluate(({ n }) => {
|
|
307
|
+
const utils = globalThis.chaosUtils;
|
|
308
|
+
if (!utils || !utils.instance) {
|
|
309
|
+
throw new Error("[chaos-maker] no chaos instance on page \u2014 call injectChaos first");
|
|
310
|
+
}
|
|
311
|
+
if (typeof utils.disableGroup !== "function") {
|
|
312
|
+
throw new Error("[chaos-maker] disableGroup API unavailable");
|
|
313
|
+
}
|
|
314
|
+
const result = utils.disableGroup(n);
|
|
315
|
+
if (result && result.success === false) {
|
|
316
|
+
throw new Error(`[chaos-maker] disableGroup('${n}') failed: ${result.message}`);
|
|
317
|
+
}
|
|
318
|
+
}, { n: nameNorm });
|
|
319
|
+
}
|
|
237
320
|
async function getChaosSeed(page) {
|
|
238
321
|
return page.evaluate(() => {
|
|
239
322
|
const win = globalThis;
|
|
@@ -247,10 +330,17 @@ async function getChaosSeed(page) {
|
|
|
247
330
|
export {
|
|
248
331
|
injectSWChaos,
|
|
249
332
|
removeSWChaos,
|
|
333
|
+
enableSWGroup,
|
|
334
|
+
disableSWGroup,
|
|
250
335
|
getSWChaosLog,
|
|
251
336
|
getSWChaosLogFromSW,
|
|
252
337
|
injectChaos,
|
|
253
338
|
removeChaos,
|
|
254
339
|
getChaosLog,
|
|
255
|
-
|
|
340
|
+
enableGroup,
|
|
341
|
+
disableGroup,
|
|
342
|
+
getChaosSeed,
|
|
343
|
+
Logger,
|
|
344
|
+
validateChaosConfig3 as validateChaosConfig,
|
|
345
|
+
ChaosConfigError
|
|
256
346
|
};
|
package/dist/fixture.cjs
CHANGED
|
@@ -78,6 +78,7 @@ function truncate(s, max) {
|
|
|
78
78
|
return `\u2026${s.slice(-(max - 1))}`;
|
|
79
79
|
}
|
|
80
80
|
function shouldEmitStep(event, verbose) {
|
|
81
|
+
if (event.type === "debug") return false;
|
|
81
82
|
if (event.applied) return true;
|
|
82
83
|
return verbose;
|
|
83
84
|
}
|
|
@@ -136,8 +137,54 @@ async function createTraceReporter(page, testInfo, opts = {}) {
|
|
|
136
137
|
};
|
|
137
138
|
}
|
|
138
139
|
|
|
140
|
+
// src/index.ts
|
|
141
|
+
var import_core3 = require("@chaos-maker/core");
|
|
142
|
+
var import_core4 = require("@chaos-maker/core");
|
|
143
|
+
|
|
139
144
|
// src/sw.ts
|
|
140
145
|
var import_core = require("@chaos-maker/core");
|
|
146
|
+
var BRIDGE_INIT_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.sw.bridgeInit");
|
|
147
|
+
var DEFAULT_SW_TOGGLE_TIMEOUT = 2e3;
|
|
148
|
+
async function ensurePageBridge(page) {
|
|
149
|
+
if (!page[BRIDGE_INIT_KEY]) {
|
|
150
|
+
await page.addInitScript({ content: import_core.SW_BRIDGE_SOURCE });
|
|
151
|
+
page[BRIDGE_INIT_KEY] = true;
|
|
152
|
+
}
|
|
153
|
+
await page.evaluate(import_core.SW_BRIDGE_SOURCE).catch(() => {
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
async function enableSWGroup(page, name, opts = {}) {
|
|
157
|
+
if (typeof name !== "string") {
|
|
158
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
159
|
+
}
|
|
160
|
+
const nameNorm = name.trim();
|
|
161
|
+
if (!nameNorm) {
|
|
162
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
163
|
+
}
|
|
164
|
+
await toggleSWGroup(page, nameNorm, true, opts);
|
|
165
|
+
}
|
|
166
|
+
async function disableSWGroup(page, name, opts = {}) {
|
|
167
|
+
if (typeof name !== "string") {
|
|
168
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
169
|
+
}
|
|
170
|
+
const nameNorm = name.trim();
|
|
171
|
+
if (!nameNorm) {
|
|
172
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
173
|
+
}
|
|
174
|
+
await toggleSWGroup(page, nameNorm, false, opts);
|
|
175
|
+
}
|
|
176
|
+
async function toggleSWGroup(page, name, enabled, opts) {
|
|
177
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_SW_TOGGLE_TIMEOUT;
|
|
178
|
+
await ensurePageBridge(page);
|
|
179
|
+
await page.evaluate(
|
|
180
|
+
async ({ n, e, t }) => {
|
|
181
|
+
const bridge = globalThis.__chaosMakerSWBridge;
|
|
182
|
+
if (!bridge) throw new Error("[chaos-maker] SW bridge missing \u2014 ensurePageBridge failed");
|
|
183
|
+
await bridge.toggleGroup(n, e, t);
|
|
184
|
+
},
|
|
185
|
+
{ n: name, e: enabled, t: timeoutMs }
|
|
186
|
+
);
|
|
187
|
+
}
|
|
141
188
|
|
|
142
189
|
// src/index.ts
|
|
143
190
|
var import_meta = {};
|
|
@@ -153,6 +200,7 @@ function getCoreUmdPath() {
|
|
|
153
200
|
}
|
|
154
201
|
var TRACE_HANDLE_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.traceHandle");
|
|
155
202
|
async function injectChaos(page, config, opts = {}) {
|
|
203
|
+
const validated = (0, import_core2.validateChaosConfig)(config, opts.validation);
|
|
156
204
|
const umdPath = getCoreUmdPath();
|
|
157
205
|
const tracingEnabled = resolveTracing(opts);
|
|
158
206
|
if (tracingEnabled) {
|
|
@@ -167,7 +215,7 @@ async function injectChaos(page, config, opts = {}) {
|
|
|
167
215
|
page[TRACE_HANDLE_KEY] = handle;
|
|
168
216
|
}
|
|
169
217
|
}
|
|
170
|
-
const serialized = (0, import_core2.serializeForTransport)(
|
|
218
|
+
const serialized = (0, import_core2.serializeForTransport)(validated);
|
|
171
219
|
await page.addInitScript((cfg) => {
|
|
172
220
|
const win = globalThis;
|
|
173
221
|
win.__CHAOS_CONFIG__ = cfg;
|
|
@@ -209,6 +257,50 @@ async function getChaosLog(page) {
|
|
|
209
257
|
return [];
|
|
210
258
|
});
|
|
211
259
|
}
|
|
260
|
+
async function enableGroup(page, name) {
|
|
261
|
+
if (typeof name !== "string") {
|
|
262
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
263
|
+
}
|
|
264
|
+
const nameNorm = name.trim();
|
|
265
|
+
if (!nameNorm) {
|
|
266
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
267
|
+
}
|
|
268
|
+
await page.evaluate(({ n }) => {
|
|
269
|
+
const utils = globalThis.chaosUtils;
|
|
270
|
+
if (!utils || !utils.instance) {
|
|
271
|
+
throw new Error("[chaos-maker] no chaos instance on page \u2014 call injectChaos first");
|
|
272
|
+
}
|
|
273
|
+
if (typeof utils.enableGroup !== "function") {
|
|
274
|
+
throw new Error("[chaos-maker] enableGroup API unavailable");
|
|
275
|
+
}
|
|
276
|
+
const result = utils.enableGroup(n);
|
|
277
|
+
if (result && result.success === false) {
|
|
278
|
+
throw new Error(`[chaos-maker] enableGroup('${n}') failed: ${result.message}`);
|
|
279
|
+
}
|
|
280
|
+
}, { n: nameNorm });
|
|
281
|
+
}
|
|
282
|
+
async function disableGroup(page, name) {
|
|
283
|
+
if (typeof name !== "string") {
|
|
284
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
285
|
+
}
|
|
286
|
+
const nameNorm = name.trim();
|
|
287
|
+
if (!nameNorm) {
|
|
288
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
289
|
+
}
|
|
290
|
+
await page.evaluate(({ n }) => {
|
|
291
|
+
const utils = globalThis.chaosUtils;
|
|
292
|
+
if (!utils || !utils.instance) {
|
|
293
|
+
throw new Error("[chaos-maker] no chaos instance on page \u2014 call injectChaos first");
|
|
294
|
+
}
|
|
295
|
+
if (typeof utils.disableGroup !== "function") {
|
|
296
|
+
throw new Error("[chaos-maker] disableGroup API unavailable");
|
|
297
|
+
}
|
|
298
|
+
const result = utils.disableGroup(n);
|
|
299
|
+
if (result && result.success === false) {
|
|
300
|
+
throw new Error(`[chaos-maker] disableGroup('${n}') failed: ${result.message}`);
|
|
301
|
+
}
|
|
302
|
+
}, { n: nameNorm });
|
|
303
|
+
}
|
|
212
304
|
async function getChaosSeed(page) {
|
|
213
305
|
return page.evaluate(() => {
|
|
214
306
|
const win = globalThis;
|
|
@@ -247,7 +339,11 @@ var test2 = import_test2.test.extend({
|
|
|
247
339
|
},
|
|
248
340
|
remove: () => removeChaos(page),
|
|
249
341
|
getLog: () => getChaosLog(page),
|
|
250
|
-
getSeed: () => getChaosSeed(page)
|
|
342
|
+
getSeed: () => getChaosSeed(page),
|
|
343
|
+
enableGroup: (name) => enableGroup(page, name),
|
|
344
|
+
disableGroup: (name) => disableGroup(page, name),
|
|
345
|
+
enableSWGroup: (name, opts) => enableSWGroup(page, name, opts),
|
|
346
|
+
disableSWGroup: (name, opts) => disableSWGroup(page, name, opts)
|
|
251
347
|
};
|
|
252
348
|
await use(fixture);
|
|
253
349
|
await removeChaos(page);
|
package/dist/fixture.d.cts
CHANGED
|
@@ -2,13 +2,17 @@ import * as _playwright_test from '@playwright/test';
|
|
|
2
2
|
export { expect } from '@playwright/test';
|
|
3
3
|
import { ChaosConfig, ChaosEvent } from '@chaos-maker/core';
|
|
4
4
|
export { ChaosConfig, ChaosEvent } from '@chaos-maker/core';
|
|
5
|
-
import { InjectChaosOptions } from './index.cjs';
|
|
5
|
+
import { InjectChaosOptions, SWChaosOptions } from './index.cjs';
|
|
6
6
|
|
|
7
7
|
interface ChaosFixture {
|
|
8
8
|
inject: (config: ChaosConfig, opts?: InjectChaosOptions) => Promise<void>;
|
|
9
9
|
remove: () => Promise<void>;
|
|
10
10
|
getLog: () => Promise<ChaosEvent[]>;
|
|
11
11
|
getSeed: () => Promise<number | null>;
|
|
12
|
+
enableGroup: (name: string) => Promise<void>;
|
|
13
|
+
disableGroup: (name: string) => Promise<void>;
|
|
14
|
+
enableSWGroup: (name: string, opts?: SWChaosOptions) => Promise<void>;
|
|
15
|
+
disableSWGroup: (name: string, opts?: SWChaosOptions) => Promise<void>;
|
|
12
16
|
}
|
|
13
17
|
/**
|
|
14
18
|
* Extended Playwright test with a `chaos` fixture.
|
package/dist/fixture.d.ts
CHANGED
|
@@ -2,13 +2,17 @@ import * as _playwright_test from '@playwright/test';
|
|
|
2
2
|
export { expect } from '@playwright/test';
|
|
3
3
|
import { ChaosConfig, ChaosEvent } from '@chaos-maker/core';
|
|
4
4
|
export { ChaosConfig, ChaosEvent } from '@chaos-maker/core';
|
|
5
|
-
import { InjectChaosOptions } from './index.js';
|
|
5
|
+
import { InjectChaosOptions, SWChaosOptions } from './index.js';
|
|
6
6
|
|
|
7
7
|
interface ChaosFixture {
|
|
8
8
|
inject: (config: ChaosConfig, opts?: InjectChaosOptions) => Promise<void>;
|
|
9
9
|
remove: () => Promise<void>;
|
|
10
10
|
getLog: () => Promise<ChaosEvent[]>;
|
|
11
11
|
getSeed: () => Promise<number | null>;
|
|
12
|
+
enableGroup: (name: string) => Promise<void>;
|
|
13
|
+
disableGroup: (name: string) => Promise<void>;
|
|
14
|
+
enableSWGroup: (name: string, opts?: SWChaosOptions) => Promise<void>;
|
|
15
|
+
disableSWGroup: (name: string, opts?: SWChaosOptions) => Promise<void>;
|
|
12
16
|
}
|
|
13
17
|
/**
|
|
14
18
|
* Extended Playwright test with a `chaos` fixture.
|
package/dist/fixture.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
+
disableGroup,
|
|
3
|
+
disableSWGroup,
|
|
4
|
+
enableGroup,
|
|
5
|
+
enableSWGroup,
|
|
2
6
|
getChaosLog,
|
|
3
7
|
getChaosSeed,
|
|
4
8
|
injectChaos,
|
|
5
9
|
removeChaos
|
|
6
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-IJDMHBUQ.js";
|
|
7
11
|
|
|
8
12
|
// src/fixture.ts
|
|
9
13
|
import { test as base } from "@playwright/test";
|
|
@@ -34,7 +38,11 @@ var test = base.extend({
|
|
|
34
38
|
},
|
|
35
39
|
remove: () => removeChaos(page),
|
|
36
40
|
getLog: () => getChaosLog(page),
|
|
37
|
-
getSeed: () => getChaosSeed(page)
|
|
41
|
+
getSeed: () => getChaosSeed(page),
|
|
42
|
+
enableGroup: (name) => enableGroup(page, name),
|
|
43
|
+
disableGroup: (name) => disableGroup(page, name),
|
|
44
|
+
enableSWGroup: (name, opts) => enableSWGroup(page, name, opts),
|
|
45
|
+
disableSWGroup: (name, opts) => disableSWGroup(page, name, opts)
|
|
38
46
|
};
|
|
39
47
|
await use(fixture);
|
|
40
48
|
await removeChaos(page);
|
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
ChaosConfigError: () => import_core4.ChaosConfigError,
|
|
24
|
+
Logger: () => import_core3.Logger,
|
|
25
|
+
disableGroup: () => disableGroup,
|
|
26
|
+
disableSWGroup: () => disableSWGroup,
|
|
27
|
+
enableGroup: () => enableGroup,
|
|
28
|
+
enableSWGroup: () => enableSWGroup,
|
|
23
29
|
getChaosLog: () => getChaosLog,
|
|
24
30
|
getChaosSeed: () => getChaosSeed,
|
|
25
31
|
getSWChaosLog: () => getSWChaosLog,
|
|
@@ -27,7 +33,8 @@ __export(index_exports, {
|
|
|
27
33
|
injectChaos: () => injectChaos,
|
|
28
34
|
injectSWChaos: () => injectSWChaos,
|
|
29
35
|
removeChaos: () => removeChaos,
|
|
30
|
-
removeSWChaos: () => removeSWChaos
|
|
36
|
+
removeSWChaos: () => removeSWChaos,
|
|
37
|
+
validateChaosConfig: () => import_core4.validateChaosConfig
|
|
31
38
|
});
|
|
32
39
|
module.exports = __toCommonJS(index_exports);
|
|
33
40
|
var import_core2 = require("@chaos-maker/core");
|
|
@@ -81,6 +88,7 @@ function truncate(s, max) {
|
|
|
81
88
|
return `\u2026${s.slice(-(max - 1))}`;
|
|
82
89
|
}
|
|
83
90
|
function shouldEmitStep(event, verbose) {
|
|
91
|
+
if (event.type === "debug") return false;
|
|
84
92
|
if (event.applied) return true;
|
|
85
93
|
return verbose;
|
|
86
94
|
}
|
|
@@ -139,9 +147,14 @@ async function createTraceReporter(page, testInfo, opts = {}) {
|
|
|
139
147
|
};
|
|
140
148
|
}
|
|
141
149
|
|
|
150
|
+
// src/index.ts
|
|
151
|
+
var import_core3 = require("@chaos-maker/core");
|
|
152
|
+
var import_core4 = require("@chaos-maker/core");
|
|
153
|
+
|
|
142
154
|
// src/sw.ts
|
|
143
155
|
var import_core = require("@chaos-maker/core");
|
|
144
156
|
var BRIDGE_INIT_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.sw.bridgeInit");
|
|
157
|
+
var DEFAULT_SW_TOGGLE_TIMEOUT = 2e3;
|
|
145
158
|
async function ensurePageBridge(page) {
|
|
146
159
|
if (!page[BRIDGE_INIT_KEY]) {
|
|
147
160
|
await page.addInitScript({ content: import_core.SW_BRIDGE_SOURCE });
|
|
@@ -151,7 +164,7 @@ async function ensurePageBridge(page) {
|
|
|
151
164
|
});
|
|
152
165
|
}
|
|
153
166
|
async function injectSWChaos(page, config, opts = {}) {
|
|
154
|
-
const validated = (0, import_core.
|
|
167
|
+
const validated = (0, import_core.validateChaosConfig)(config, opts.validation);
|
|
155
168
|
const timeoutMs = opts.timeoutMs ?? 1e4;
|
|
156
169
|
await ensurePageBridge(page);
|
|
157
170
|
const result = await page.evaluate(
|
|
@@ -177,6 +190,38 @@ async function removeSWChaos(page, opts = {}) {
|
|
|
177
190
|
).catch(() => {
|
|
178
191
|
});
|
|
179
192
|
}
|
|
193
|
+
async function enableSWGroup(page, name, opts = {}) {
|
|
194
|
+
if (typeof name !== "string") {
|
|
195
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
196
|
+
}
|
|
197
|
+
const nameNorm = name.trim();
|
|
198
|
+
if (!nameNorm) {
|
|
199
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
200
|
+
}
|
|
201
|
+
await toggleSWGroup(page, nameNorm, true, opts);
|
|
202
|
+
}
|
|
203
|
+
async function disableSWGroup(page, name, opts = {}) {
|
|
204
|
+
if (typeof name !== "string") {
|
|
205
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
206
|
+
}
|
|
207
|
+
const nameNorm = name.trim();
|
|
208
|
+
if (!nameNorm) {
|
|
209
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
210
|
+
}
|
|
211
|
+
await toggleSWGroup(page, nameNorm, false, opts);
|
|
212
|
+
}
|
|
213
|
+
async function toggleSWGroup(page, name, enabled, opts) {
|
|
214
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_SW_TOGGLE_TIMEOUT;
|
|
215
|
+
await ensurePageBridge(page);
|
|
216
|
+
await page.evaluate(
|
|
217
|
+
async ({ n, e, t }) => {
|
|
218
|
+
const bridge = globalThis.__chaosMakerSWBridge;
|
|
219
|
+
if (!bridge) throw new Error("[chaos-maker] SW bridge missing \u2014 ensurePageBridge failed");
|
|
220
|
+
await bridge.toggleGroup(n, e, t);
|
|
221
|
+
},
|
|
222
|
+
{ n: name, e: enabled, t: timeoutMs }
|
|
223
|
+
);
|
|
224
|
+
}
|
|
180
225
|
async function getSWChaosLog(page) {
|
|
181
226
|
return page.evaluate(() => {
|
|
182
227
|
const bridge = globalThis.__chaosMakerSWBridge;
|
|
@@ -210,6 +255,7 @@ function getCoreUmdPath() {
|
|
|
210
255
|
}
|
|
211
256
|
var TRACE_HANDLE_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.traceHandle");
|
|
212
257
|
async function injectChaos(page, config, opts = {}) {
|
|
258
|
+
const validated = (0, import_core2.validateChaosConfig)(config, opts.validation);
|
|
213
259
|
const umdPath = getCoreUmdPath();
|
|
214
260
|
const tracingEnabled = resolveTracing(opts);
|
|
215
261
|
if (tracingEnabled) {
|
|
@@ -224,7 +270,7 @@ async function injectChaos(page, config, opts = {}) {
|
|
|
224
270
|
page[TRACE_HANDLE_KEY] = handle;
|
|
225
271
|
}
|
|
226
272
|
}
|
|
227
|
-
const serialized = (0, import_core2.serializeForTransport)(
|
|
273
|
+
const serialized = (0, import_core2.serializeForTransport)(validated);
|
|
228
274
|
await page.addInitScript((cfg) => {
|
|
229
275
|
const win = globalThis;
|
|
230
276
|
win.__CHAOS_CONFIG__ = cfg;
|
|
@@ -266,6 +312,50 @@ async function getChaosLog(page) {
|
|
|
266
312
|
return [];
|
|
267
313
|
});
|
|
268
314
|
}
|
|
315
|
+
async function enableGroup(page, name) {
|
|
316
|
+
if (typeof name !== "string") {
|
|
317
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
318
|
+
}
|
|
319
|
+
const nameNorm = name.trim();
|
|
320
|
+
if (!nameNorm) {
|
|
321
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
322
|
+
}
|
|
323
|
+
await page.evaluate(({ n }) => {
|
|
324
|
+
const utils = globalThis.chaosUtils;
|
|
325
|
+
if (!utils || !utils.instance) {
|
|
326
|
+
throw new Error("[chaos-maker] no chaos instance on page \u2014 call injectChaos first");
|
|
327
|
+
}
|
|
328
|
+
if (typeof utils.enableGroup !== "function") {
|
|
329
|
+
throw new Error("[chaos-maker] enableGroup API unavailable");
|
|
330
|
+
}
|
|
331
|
+
const result = utils.enableGroup(n);
|
|
332
|
+
if (result && result.success === false) {
|
|
333
|
+
throw new Error(`[chaos-maker] enableGroup('${n}') failed: ${result.message}`);
|
|
334
|
+
}
|
|
335
|
+
}, { n: nameNorm });
|
|
336
|
+
}
|
|
337
|
+
async function disableGroup(page, name) {
|
|
338
|
+
if (typeof name !== "string") {
|
|
339
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
340
|
+
}
|
|
341
|
+
const nameNorm = name.trim();
|
|
342
|
+
if (!nameNorm) {
|
|
343
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
344
|
+
}
|
|
345
|
+
await page.evaluate(({ n }) => {
|
|
346
|
+
const utils = globalThis.chaosUtils;
|
|
347
|
+
if (!utils || !utils.instance) {
|
|
348
|
+
throw new Error("[chaos-maker] no chaos instance on page \u2014 call injectChaos first");
|
|
349
|
+
}
|
|
350
|
+
if (typeof utils.disableGroup !== "function") {
|
|
351
|
+
throw new Error("[chaos-maker] disableGroup API unavailable");
|
|
352
|
+
}
|
|
353
|
+
const result = utils.disableGroup(n);
|
|
354
|
+
if (result && result.success === false) {
|
|
355
|
+
throw new Error(`[chaos-maker] disableGroup('${n}') failed: ${result.message}`);
|
|
356
|
+
}
|
|
357
|
+
}, { n: nameNorm });
|
|
358
|
+
}
|
|
269
359
|
async function getChaosSeed(page) {
|
|
270
360
|
return page.evaluate(() => {
|
|
271
361
|
const win = globalThis;
|
|
@@ -277,6 +367,12 @@ async function getChaosSeed(page) {
|
|
|
277
367
|
}
|
|
278
368
|
// Annotate the CommonJS export names for ESM import in node:
|
|
279
369
|
0 && (module.exports = {
|
|
370
|
+
ChaosConfigError,
|
|
371
|
+
Logger,
|
|
372
|
+
disableGroup,
|
|
373
|
+
disableSWGroup,
|
|
374
|
+
enableGroup,
|
|
375
|
+
enableSWGroup,
|
|
280
376
|
getChaosLog,
|
|
281
377
|
getChaosSeed,
|
|
282
378
|
getSWChaosLog,
|
|
@@ -284,5 +380,6 @@ async function getChaosSeed(page) {
|
|
|
284
380
|
injectChaos,
|
|
285
381
|
injectSWChaos,
|
|
286
382
|
removeChaos,
|
|
287
|
-
removeSWChaos
|
|
383
|
+
removeSWChaos,
|
|
384
|
+
validateChaosConfig
|
|
288
385
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Page, TestInfo } from '@playwright/test';
|
|
2
|
-
import { ChaosEvent, ChaosConfig } from '@chaos-maker/core';
|
|
3
|
-
export { ChaosConfig, ChaosEvent, CorruptionStrategy, GraphQLOperationMatcher, NetworkAbortConfig, NetworkConfig, NetworkCorruptionConfig, NetworkCorsConfig, NetworkFailureConfig, NetworkLatencyConfig, NetworkRuleMatchers, SSECloseConfig, SSEConfig, SSECorruptConfig, SSECorruptionStrategy, SSEDelayConfig, SSEDropConfig, SSEEventTypeMatcher, WebSocketCloseConfig, WebSocketConfig, WebSocketCorruptConfig, WebSocketCorruptionStrategy, WebSocketDelayConfig, WebSocketDirection, WebSocketDropConfig } from '@chaos-maker/core';
|
|
2
|
+
import { ChaosEvent, ValidateChaosConfigOptions, ChaosConfig } from '@chaos-maker/core';
|
|
3
|
+
export { ChaosConfig, ChaosConfigError, ChaosDebugStage, ChaosEvent, ChaosLifecyclePhase, CorruptionStrategy, CustomRuleValidator, CustomValidatorMap, DebugOptions, GraphQLOperationMatcher, Logger, NetworkAbortConfig, NetworkConfig, NetworkCorruptionConfig, NetworkCorsConfig, NetworkFailureConfig, NetworkLatencyConfig, NetworkRuleMatchers, RuleType, SSECloseConfig, SSEConfig, SSECorruptConfig, SSECorruptionStrategy, SSEDelayConfig, SSEDropConfig, SSEEventTypeMatcher, ValidateChaosConfigOptions, ValidationIssue, ValidationIssueCode, WebSocketCloseConfig, WebSocketConfig, WebSocketCorruptConfig, WebSocketCorruptionStrategy, WebSocketDelayConfig, WebSocketDirection, WebSocketDropConfig, validateChaosConfig } from '@chaos-maker/core';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Shape of the JSON attachment written to `testInfo.attachments` on teardown.
|
|
@@ -28,6 +28,11 @@ interface SWChaosOptions {
|
|
|
28
28
|
* SWs that do heavy work during `install`.
|
|
29
29
|
*/
|
|
30
30
|
timeoutMs?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Forwarded to `validateChaosConfig` before the config is posted
|
|
33
|
+
* to the SW. Malformed configs throw a `ChaosConfigError` from Node.
|
|
34
|
+
*/
|
|
35
|
+
validation?: ValidateChaosConfigOptions;
|
|
31
36
|
}
|
|
32
37
|
interface InjectSWChaosResult {
|
|
33
38
|
/** Seed used by the PRNG inside the SW. `null` if the ack did not carry one. */
|
|
@@ -56,6 +61,14 @@ declare function injectSWChaos(page: Page, config: ChaosConfig, opts?: SWChaosOp
|
|
|
56
61
|
* the current controller and clears the page's in-memory log buffer.
|
|
57
62
|
*/
|
|
58
63
|
declare function removeSWChaos(page: Page, opts?: SWChaosOptions): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Enable a rule group inside the active SW chaos engine. Posts
|
|
66
|
+
* `__chaosMakerToggleGroup` over MessageChannel and resolves only after the SW
|
|
67
|
+
* acks. Engine state and request counters are preserved (no restart).
|
|
68
|
+
*/
|
|
69
|
+
declare function enableSWGroup(page: Page, name: string, opts?: SWChaosOptions): Promise<void>;
|
|
70
|
+
/** Disable a rule group inside the active SW chaos engine. */
|
|
71
|
+
declare function disableSWGroup(page: Page, name: string, opts?: SWChaosOptions): Promise<void>;
|
|
59
72
|
/**
|
|
60
73
|
* Read the chaos event log buffered on the page side. Every event emitted by
|
|
61
74
|
* the SW is broadcast to all controlled clients and captured here.
|
|
@@ -90,6 +103,13 @@ interface InjectChaosOptions {
|
|
|
90
103
|
testInfo?: TestInfo;
|
|
91
104
|
/** Pass through to the trace reporter. */
|
|
92
105
|
traceOptions?: TraceReporterOptions;
|
|
106
|
+
/**
|
|
107
|
+
* Forwarded to `validateChaosConfig` before the config is
|
|
108
|
+
* serialized for the page. Use to relax unknown-field handling, hook
|
|
109
|
+
* deprecation events, or run custom per-`RuleType` validators. Malformed
|
|
110
|
+
* configs throw a `ChaosConfigError` synchronously from Node.
|
|
111
|
+
*/
|
|
112
|
+
validation?: ValidateChaosConfigOptions;
|
|
93
113
|
}
|
|
94
114
|
/**
|
|
95
115
|
* Inject chaos into a Playwright page. Call before `page.goto()` to ensure
|
|
@@ -119,10 +139,18 @@ declare function removeChaos(page: Page): Promise<void>;
|
|
|
119
139
|
* Returns all events emitted since chaos was injected.
|
|
120
140
|
*/
|
|
121
141
|
declare function getChaosLog(page: Page): Promise<ChaosEvent[]>;
|
|
142
|
+
/**
|
|
143
|
+
* Enable a rule group at runtime in the page-side chaos engine. Resolves once
|
|
144
|
+
* `page.evaluate` round-trips so the call is safe to await before triggering
|
|
145
|
+
* the assertion that depends on the group being live.
|
|
146
|
+
*/
|
|
147
|
+
declare function enableGroup(page: Page, name: string): Promise<void>;
|
|
148
|
+
/** Disable a rule group at runtime in the page-side chaos engine. */
|
|
149
|
+
declare function disableGroup(page: Page, name: string): Promise<void>;
|
|
122
150
|
/**
|
|
123
151
|
* Retrieve the PRNG seed from a Playwright page.
|
|
124
152
|
* Log this value on test failure to replay exact chaos decisions.
|
|
125
153
|
*/
|
|
126
154
|
declare function getChaosSeed(page: Page): Promise<number | null>;
|
|
127
155
|
|
|
128
|
-
export { type ChaosTraceAttachment, type InjectChaosOptions, type InjectSWChaosResult, type SWChaosOptions, type TraceReporterOptions, getChaosLog, getChaosSeed, getSWChaosLog, getSWChaosLogFromSW, injectChaos, injectSWChaos, removeChaos, removeSWChaos };
|
|
156
|
+
export { type ChaosTraceAttachment, type InjectChaosOptions, type InjectSWChaosResult, type SWChaosOptions, type TraceReporterOptions, disableGroup, disableSWGroup, enableGroup, enableSWGroup, getChaosLog, getChaosSeed, getSWChaosLog, getSWChaosLogFromSW, injectChaos, injectSWChaos, removeChaos, removeSWChaos };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Page, TestInfo } from '@playwright/test';
|
|
2
|
-
import { ChaosEvent, ChaosConfig } from '@chaos-maker/core';
|
|
3
|
-
export { ChaosConfig, ChaosEvent, CorruptionStrategy, GraphQLOperationMatcher, NetworkAbortConfig, NetworkConfig, NetworkCorruptionConfig, NetworkCorsConfig, NetworkFailureConfig, NetworkLatencyConfig, NetworkRuleMatchers, SSECloseConfig, SSEConfig, SSECorruptConfig, SSECorruptionStrategy, SSEDelayConfig, SSEDropConfig, SSEEventTypeMatcher, WebSocketCloseConfig, WebSocketConfig, WebSocketCorruptConfig, WebSocketCorruptionStrategy, WebSocketDelayConfig, WebSocketDirection, WebSocketDropConfig } from '@chaos-maker/core';
|
|
2
|
+
import { ChaosEvent, ValidateChaosConfigOptions, ChaosConfig } from '@chaos-maker/core';
|
|
3
|
+
export { ChaosConfig, ChaosConfigError, ChaosDebugStage, ChaosEvent, ChaosLifecyclePhase, CorruptionStrategy, CustomRuleValidator, CustomValidatorMap, DebugOptions, GraphQLOperationMatcher, Logger, NetworkAbortConfig, NetworkConfig, NetworkCorruptionConfig, NetworkCorsConfig, NetworkFailureConfig, NetworkLatencyConfig, NetworkRuleMatchers, RuleType, SSECloseConfig, SSEConfig, SSECorruptConfig, SSECorruptionStrategy, SSEDelayConfig, SSEDropConfig, SSEEventTypeMatcher, ValidateChaosConfigOptions, ValidationIssue, ValidationIssueCode, WebSocketCloseConfig, WebSocketConfig, WebSocketCorruptConfig, WebSocketCorruptionStrategy, WebSocketDelayConfig, WebSocketDirection, WebSocketDropConfig, validateChaosConfig } from '@chaos-maker/core';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Shape of the JSON attachment written to `testInfo.attachments` on teardown.
|
|
@@ -28,6 +28,11 @@ interface SWChaosOptions {
|
|
|
28
28
|
* SWs that do heavy work during `install`.
|
|
29
29
|
*/
|
|
30
30
|
timeoutMs?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Forwarded to `validateChaosConfig` before the config is posted
|
|
33
|
+
* to the SW. Malformed configs throw a `ChaosConfigError` from Node.
|
|
34
|
+
*/
|
|
35
|
+
validation?: ValidateChaosConfigOptions;
|
|
31
36
|
}
|
|
32
37
|
interface InjectSWChaosResult {
|
|
33
38
|
/** Seed used by the PRNG inside the SW. `null` if the ack did not carry one. */
|
|
@@ -56,6 +61,14 @@ declare function injectSWChaos(page: Page, config: ChaosConfig, opts?: SWChaosOp
|
|
|
56
61
|
* the current controller and clears the page's in-memory log buffer.
|
|
57
62
|
*/
|
|
58
63
|
declare function removeSWChaos(page: Page, opts?: SWChaosOptions): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Enable a rule group inside the active SW chaos engine. Posts
|
|
66
|
+
* `__chaosMakerToggleGroup` over MessageChannel and resolves only after the SW
|
|
67
|
+
* acks. Engine state and request counters are preserved (no restart).
|
|
68
|
+
*/
|
|
69
|
+
declare function enableSWGroup(page: Page, name: string, opts?: SWChaosOptions): Promise<void>;
|
|
70
|
+
/** Disable a rule group inside the active SW chaos engine. */
|
|
71
|
+
declare function disableSWGroup(page: Page, name: string, opts?: SWChaosOptions): Promise<void>;
|
|
59
72
|
/**
|
|
60
73
|
* Read the chaos event log buffered on the page side. Every event emitted by
|
|
61
74
|
* the SW is broadcast to all controlled clients and captured here.
|
|
@@ -90,6 +103,13 @@ interface InjectChaosOptions {
|
|
|
90
103
|
testInfo?: TestInfo;
|
|
91
104
|
/** Pass through to the trace reporter. */
|
|
92
105
|
traceOptions?: TraceReporterOptions;
|
|
106
|
+
/**
|
|
107
|
+
* Forwarded to `validateChaosConfig` before the config is
|
|
108
|
+
* serialized for the page. Use to relax unknown-field handling, hook
|
|
109
|
+
* deprecation events, or run custom per-`RuleType` validators. Malformed
|
|
110
|
+
* configs throw a `ChaosConfigError` synchronously from Node.
|
|
111
|
+
*/
|
|
112
|
+
validation?: ValidateChaosConfigOptions;
|
|
93
113
|
}
|
|
94
114
|
/**
|
|
95
115
|
* Inject chaos into a Playwright page. Call before `page.goto()` to ensure
|
|
@@ -119,10 +139,18 @@ declare function removeChaos(page: Page): Promise<void>;
|
|
|
119
139
|
* Returns all events emitted since chaos was injected.
|
|
120
140
|
*/
|
|
121
141
|
declare function getChaosLog(page: Page): Promise<ChaosEvent[]>;
|
|
142
|
+
/**
|
|
143
|
+
* Enable a rule group at runtime in the page-side chaos engine. Resolves once
|
|
144
|
+
* `page.evaluate` round-trips so the call is safe to await before triggering
|
|
145
|
+
* the assertion that depends on the group being live.
|
|
146
|
+
*/
|
|
147
|
+
declare function enableGroup(page: Page, name: string): Promise<void>;
|
|
148
|
+
/** Disable a rule group at runtime in the page-side chaos engine. */
|
|
149
|
+
declare function disableGroup(page: Page, name: string): Promise<void>;
|
|
122
150
|
/**
|
|
123
151
|
* Retrieve the PRNG seed from a Playwright page.
|
|
124
152
|
* Log this value on test failure to replay exact chaos decisions.
|
|
125
153
|
*/
|
|
126
154
|
declare function getChaosSeed(page: Page): Promise<number | null>;
|
|
127
155
|
|
|
128
|
-
export { type ChaosTraceAttachment, type InjectChaosOptions, type InjectSWChaosResult, type SWChaosOptions, type TraceReporterOptions, getChaosLog, getChaosSeed, getSWChaosLog, getSWChaosLogFromSW, injectChaos, injectSWChaos, removeChaos, removeSWChaos };
|
|
156
|
+
export { type ChaosTraceAttachment, type InjectChaosOptions, type InjectSWChaosResult, type SWChaosOptions, type TraceReporterOptions, disableGroup, disableSWGroup, enableGroup, enableSWGroup, getChaosLog, getChaosSeed, getSWChaosLog, getSWChaosLogFromSW, injectChaos, injectSWChaos, removeChaos, removeSWChaos };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ChaosConfigError,
|
|
3
|
+
Logger,
|
|
4
|
+
disableGroup,
|
|
5
|
+
disableSWGroup,
|
|
6
|
+
enableGroup,
|
|
7
|
+
enableSWGroup,
|
|
2
8
|
getChaosLog,
|
|
3
9
|
getChaosSeed,
|
|
4
10
|
getSWChaosLog,
|
|
@@ -6,9 +12,16 @@ import {
|
|
|
6
12
|
injectChaos,
|
|
7
13
|
injectSWChaos,
|
|
8
14
|
removeChaos,
|
|
9
|
-
removeSWChaos
|
|
10
|
-
|
|
15
|
+
removeSWChaos,
|
|
16
|
+
validateChaosConfig
|
|
17
|
+
} from "./chunk-IJDMHBUQ.js";
|
|
11
18
|
export {
|
|
19
|
+
ChaosConfigError,
|
|
20
|
+
Logger,
|
|
21
|
+
disableGroup,
|
|
22
|
+
disableSWGroup,
|
|
23
|
+
enableGroup,
|
|
24
|
+
enableSWGroup,
|
|
12
25
|
getChaosLog,
|
|
13
26
|
getChaosSeed,
|
|
14
27
|
getSWChaosLog,
|
|
@@ -16,5 +29,6 @@ export {
|
|
|
16
29
|
injectChaos,
|
|
17
30
|
injectSWChaos,
|
|
18
31
|
removeChaos,
|
|
19
|
-
removeSWChaos
|
|
32
|
+
removeSWChaos,
|
|
33
|
+
validateChaosConfig
|
|
20
34
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chaos-maker/playwright",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Playwright adapter for @chaos-maker/core — one-line chaos injection in E2E tests",
|
|
6
6
|
"keywords": [
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"dist"
|
|
50
50
|
],
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@chaos-maker/core": "0.
|
|
52
|
+
"@chaos-maker/core": "0.5.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"@playwright/test": ">=1.40.0"
|