@chaos-maker/playwright 0.4.0 → 0.6.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/dist/index.cjs CHANGED
@@ -20,6 +20,13 @@ 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_core6.ChaosConfigError,
24
+ Logger: () => import_core5.Logger,
25
+ disableGroup: () => disableGroup,
26
+ disableSWGroup: () => disableSWGroup,
27
+ enableGroup: () => enableGroup,
28
+ enableSWGroup: () => enableSWGroup,
29
+ formatSeedReproduction: () => import_core6.formatSeedReproduction,
23
30
  getChaosLog: () => getChaosLog,
24
31
  getChaosSeed: () => getChaosSeed,
25
32
  getSWChaosLog: () => getSWChaosLog,
@@ -27,100 +34,70 @@ __export(index_exports, {
27
34
  injectChaos: () => injectChaos,
28
35
  injectSWChaos: () => injectSWChaos,
29
36
  removeChaos: () => removeChaos,
30
- removeSWChaos: () => removeSWChaos
37
+ removeSWChaos: () => removeSWChaos,
38
+ validateChaosConfig: () => import_core6.validateChaosConfig
31
39
  });
32
40
  module.exports = __toCommonJS(index_exports);
33
- var import_core2 = require("@chaos-maker/core");
41
+ var import_core4 = require("@chaos-maker/core");
34
42
  var import_path = require("path");
35
43
  var import_module = require("module");
36
44
  var import_url = require("url");
37
45
 
38
46
  // src/trace.ts
39
47
  var import_test = require("@playwright/test");
48
+ var import_core = require("@chaos-maker/core");
49
+ var import_core2 = require("@chaos-maker/core");
40
50
  var CHAOS_BINDING = "__chaosMakerReport";
41
- function formatStepTitle(event) {
42
- const prefix = `chaos:${event.type}`;
43
- const d = event.detail ?? {};
44
- const parts = [];
45
- const subject = d.url ?? d.selector;
46
- if (subject) parts.push(truncate(subject, 48));
47
- const outcome = formatOutcome(event);
48
- if (outcome) parts.push(`\u2192 ${outcome}`);
49
- if (!event.applied) parts.push("(skipped)");
50
- return parts.length > 0 ? `${prefix} ${parts.join(" ")}` : prefix;
51
- }
52
- function formatOutcome(event) {
53
- const d = event.detail ?? {};
54
- switch (event.type) {
55
- case "network:failure":
56
- return d.statusCode != null ? String(d.statusCode) : null;
57
- case "network:latency":
58
- return d.delayMs != null ? `+${d.delayMs}ms` : null;
59
- case "network:abort":
60
- return "abort";
61
- case "network:corruption":
62
- return d.strategy ?? "corrupted";
63
- case "network:cors":
64
- return "cors-block";
65
- case "ui:assault":
66
- return d.action ?? null;
67
- case "websocket:drop":
68
- return d.direction ? `drop ${d.direction}` : "drop";
69
- case "websocket:delay":
70
- return d.delayMs != null ? `delay ${d.direction ?? ""} +${d.delayMs}ms` : "delay";
71
- case "websocket:corrupt":
72
- return d.strategy ?? "corrupt";
73
- case "websocket:close":
74
- return d.closeCode != null ? `close ${d.closeCode}` : "close";
75
- default:
76
- return null;
77
- }
78
- }
79
- function truncate(s, max) {
80
- if (s.length <= max) return s;
81
- return `\u2026${s.slice(-(max - 1))}`;
82
- }
83
- function shouldEmitStep(event, verbose) {
84
- if (event.applied) return true;
85
- return verbose;
86
- }
51
+ var TRACE_HANDLE_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.traceHandle");
52
+ var TRACE_BINDING_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.traceBinding");
87
53
  async function createTraceReporter(page, testInfo, opts = {}) {
54
+ const existing = page[TRACE_HANDLE_KEY];
55
+ if (existing) return existing;
88
56
  const verbose = opts.verbose ?? false;
89
57
  const attachmentName = opts.attachmentName ?? "chaos-log.json";
90
58
  const events = [];
91
59
  const handler = (_source, event) => {
92
60
  events.push(event);
93
- if (!shouldEmitStep(event, verbose)) return;
94
- const title = formatStepTitle(event);
61
+ if (!(0, import_core.shouldEmitStep)(event, verbose)) return;
62
+ const title = (0, import_core.formatStepTitle)(event);
95
63
  import_test.test.step(title, async () => {
96
64
  }).catch(() => {
97
65
  });
98
66
  };
99
- await page.exposeBinding(CHAOS_BINDING, handler);
100
- await page.addInitScript((bindingName) => {
101
- const win = globalThis;
102
- const attach = () => {
103
- const utils = win.chaosUtils;
104
- if (!utils || !utils.instance) return false;
105
- if (utils.__chaosMakerTraceBound === utils.instance) return true;
106
- utils.__chaosMakerTraceBound = utils.instance;
107
- utils.instance.on("*", (event) => {
108
- try {
109
- if (typeof win[bindingName] === "function") {
110
- win[bindingName](event);
67
+ let state = page[TRACE_BINDING_KEY];
68
+ if (!state) {
69
+ state = { handler };
70
+ page[TRACE_BINDING_KEY] = state;
71
+ await page.exposeBinding(CHAOS_BINDING, (source, event) => {
72
+ state.handler(source, event);
73
+ });
74
+ await page.addInitScript((bindingName) => {
75
+ const win = globalThis;
76
+ const attach = () => {
77
+ const utils = win.chaosUtils;
78
+ if (!utils || !utils.instance) return false;
79
+ if (utils.__chaosMakerTraceBound === utils.instance) return true;
80
+ utils.__chaosMakerTraceBound = utils.instance;
81
+ utils.instance.on("*", (event) => {
82
+ try {
83
+ if (typeof win[bindingName] === "function") {
84
+ win[bindingName](event);
85
+ }
86
+ } catch {
111
87
  }
112
- } catch {
113
- }
114
- });
115
- return true;
116
- };
117
- if (attach()) return;
118
- const intervalId = setInterval(() => {
119
- if (attach()) clearInterval(intervalId);
120
- }, 10);
121
- setTimeout(() => clearInterval(intervalId), 5e3);
122
- }, CHAOS_BINDING);
123
- return {
88
+ });
89
+ return true;
90
+ };
91
+ if (attach()) return;
92
+ const intervalId = setInterval(() => {
93
+ if (attach()) clearInterval(intervalId);
94
+ }, 10);
95
+ setTimeout(() => clearInterval(intervalId), 5e3);
96
+ }, CHAOS_BINDING);
97
+ } else {
98
+ state.handler = handler;
99
+ }
100
+ const handle = {
124
101
  events,
125
102
  dispose: async (seed = null) => {
126
103
  const payload = {
@@ -135,23 +112,33 @@ async function createTraceReporter(page, testInfo, opts = {}) {
135
112
  });
136
113
  } catch {
137
114
  }
115
+ if (page[TRACE_HANDLE_KEY] === handle) {
116
+ delete page[TRACE_HANDLE_KEY];
117
+ }
138
118
  }
139
119
  };
120
+ page[TRACE_HANDLE_KEY] = handle;
121
+ return handle;
140
122
  }
141
123
 
124
+ // src/index.ts
125
+ var import_core5 = require("@chaos-maker/core");
126
+ var import_core6 = require("@chaos-maker/core");
127
+
142
128
  // src/sw.ts
143
- var import_core = require("@chaos-maker/core");
129
+ var import_core3 = require("@chaos-maker/core");
144
130
  var BRIDGE_INIT_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.sw.bridgeInit");
131
+ var DEFAULT_SW_TOGGLE_TIMEOUT = 2e3;
145
132
  async function ensurePageBridge(page) {
146
133
  if (!page[BRIDGE_INIT_KEY]) {
147
- await page.addInitScript({ content: import_core.SW_BRIDGE_SOURCE });
134
+ await page.addInitScript({ content: import_core3.SW_BRIDGE_SOURCE });
148
135
  page[BRIDGE_INIT_KEY] = true;
149
136
  }
150
- await page.evaluate(import_core.SW_BRIDGE_SOURCE).catch(() => {
137
+ await page.evaluate(import_core3.SW_BRIDGE_SOURCE).catch(() => {
151
138
  });
152
139
  }
153
140
  async function injectSWChaos(page, config, opts = {}) {
154
- const validated = (0, import_core.validateConfig)(config);
141
+ const validated = (0, import_core3.validateChaosConfig)(config, opts.validation);
155
142
  const timeoutMs = opts.timeoutMs ?? 1e4;
156
143
  await ensurePageBridge(page);
157
144
  const result = await page.evaluate(
@@ -170,13 +157,49 @@ async function removeSWChaos(page, opts = {}) {
170
157
  async ({ timeoutMs: timeoutMs2 }) => {
171
158
  const bridge = globalThis.__chaosMakerSWBridge;
172
159
  if (!bridge) return;
173
- await bridge.stop(timeoutMs2);
174
- bridge.clearLocalLog();
160
+ try {
161
+ await bridge.stop(timeoutMs2);
162
+ } finally {
163
+ bridge.clearLocalLog();
164
+ await bridge.clearRemoteLog?.(timeoutMs2).catch(() => void 0);
165
+ }
175
166
  },
176
167
  { timeoutMs }
177
168
  ).catch(() => {
178
169
  });
179
170
  }
171
+ async function enableSWGroup(page, name, opts = {}) {
172
+ if (typeof name !== "string") {
173
+ throw new Error("[chaos-maker] group name must be a string");
174
+ }
175
+ const nameNorm = name.trim();
176
+ if (!nameNorm) {
177
+ throw new Error("[chaos-maker] group name cannot be empty");
178
+ }
179
+ await toggleSWGroup(page, nameNorm, true, opts);
180
+ }
181
+ async function disableSWGroup(page, name, opts = {}) {
182
+ if (typeof name !== "string") {
183
+ throw new Error("[chaos-maker] group name must be a string");
184
+ }
185
+ const nameNorm = name.trim();
186
+ if (!nameNorm) {
187
+ throw new Error("[chaos-maker] group name cannot be empty");
188
+ }
189
+ await toggleSWGroup(page, nameNorm, false, opts);
190
+ }
191
+ async function toggleSWGroup(page, name, enabled, opts) {
192
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_SW_TOGGLE_TIMEOUT;
193
+ await ensurePageBridge(page);
194
+ await page.evaluate(
195
+ async ({ n, e, t }) => {
196
+ const bridge = globalThis.__chaosMakerSWBridge;
197
+ if (!bridge) throw new Error("[chaos-maker] SW bridge missing \u2014 ensurePageBridge failed");
198
+ await bridge.toggleGroup(n, e, t);
199
+ },
200
+ { n: name, e: enabled, t: timeoutMs }
201
+ );
202
+ }
180
203
  async function getSWChaosLog(page) {
181
204
  return page.evaluate(() => {
182
205
  const bridge = globalThis.__chaosMakerSWBridge;
@@ -208,8 +231,9 @@ function getCoreUmdPath() {
208
231
  cachedUmdPath = (0, import_path.resolve)(coreDistDir, "chaos-maker.umd.js");
209
232
  return cachedUmdPath;
210
233
  }
211
- var TRACE_HANDLE_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.traceHandle");
234
+ var TRACE_HANDLE_KEY2 = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.traceHandle");
212
235
  async function injectChaos(page, config, opts = {}) {
236
+ const validated = (0, import_core4.validateChaosConfig)(config, opts.validation);
213
237
  const umdPath = getCoreUmdPath();
214
238
  const tracingEnabled = resolveTracing(opts);
215
239
  if (tracingEnabled) {
@@ -218,13 +242,13 @@ async function injectChaos(page, config, opts = {}) {
218
242
  "[chaos-maker] tracing requires a `testInfo` in InjectChaosOptions. Use the fixture (`@chaos-maker/playwright/fixture`) or pass testInfo explicitly."
219
243
  );
220
244
  }
221
- const existing = page[TRACE_HANDLE_KEY];
245
+ const existing = page[TRACE_HANDLE_KEY2];
222
246
  if (!existing) {
223
247
  const handle = await createTraceReporter(page, opts.testInfo, opts.traceOptions);
224
- page[TRACE_HANDLE_KEY] = handle;
248
+ page[TRACE_HANDLE_KEY2] = handle;
225
249
  }
226
250
  }
227
- const serialized = (0, import_core2.serializeForTransport)(config);
251
+ const serialized = (0, import_core4.serializeForTransport)(validated);
228
252
  await page.addInitScript((cfg) => {
229
253
  const win = globalThis;
230
254
  win.__CHAOS_CONFIG__ = cfg;
@@ -237,7 +261,7 @@ function resolveTracing(opts) {
237
261
  return false;
238
262
  }
239
263
  async function removeChaos(page) {
240
- const handle = page[TRACE_HANDLE_KEY];
264
+ const handle = page[TRACE_HANDLE_KEY2];
241
265
  let seed = null;
242
266
  if (handle) {
243
267
  try {
@@ -254,7 +278,7 @@ async function removeChaos(page) {
254
278
  });
255
279
  if (handle) {
256
280
  await handle.dispose(seed);
257
- delete page[TRACE_HANDLE_KEY];
281
+ delete page[TRACE_HANDLE_KEY2];
258
282
  }
259
283
  }
260
284
  async function getChaosLog(page) {
@@ -266,6 +290,50 @@ async function getChaosLog(page) {
266
290
  return [];
267
291
  });
268
292
  }
293
+ async function enableGroup(page, name) {
294
+ if (typeof name !== "string") {
295
+ throw new Error("[chaos-maker] group name must be a string");
296
+ }
297
+ const nameNorm = name.trim();
298
+ if (!nameNorm) {
299
+ throw new Error("[chaos-maker] group name cannot be empty");
300
+ }
301
+ await page.evaluate(({ n }) => {
302
+ const utils = globalThis.chaosUtils;
303
+ if (!utils || !utils.instance) {
304
+ throw new Error("[chaos-maker] no chaos instance on page \u2014 call injectChaos first");
305
+ }
306
+ if (typeof utils.enableGroup !== "function") {
307
+ throw new Error("[chaos-maker] enableGroup API unavailable");
308
+ }
309
+ const result = utils.enableGroup(n);
310
+ if (result && result.success === false) {
311
+ throw new Error(`[chaos-maker] enableGroup('${n}') failed: ${result.message}`);
312
+ }
313
+ }, { n: nameNorm });
314
+ }
315
+ async function disableGroup(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.disableGroup !== "function") {
329
+ throw new Error("[chaos-maker] disableGroup API unavailable");
330
+ }
331
+ const result = utils.disableGroup(n);
332
+ if (result && result.success === false) {
333
+ throw new Error(`[chaos-maker] disableGroup('${n}') failed: ${result.message}`);
334
+ }
335
+ }, { n: nameNorm });
336
+ }
269
337
  async function getChaosSeed(page) {
270
338
  return page.evaluate(() => {
271
339
  const win = globalThis;
@@ -277,6 +345,13 @@ async function getChaosSeed(page) {
277
345
  }
278
346
  // Annotate the CommonJS export names for ESM import in node:
279
347
  0 && (module.exports = {
348
+ ChaosConfigError,
349
+ Logger,
350
+ disableGroup,
351
+ disableSWGroup,
352
+ enableGroup,
353
+ enableSWGroup,
354
+ formatSeedReproduction,
280
355
  getChaosLog,
281
356
  getChaosSeed,
282
357
  getSWChaosLog,
@@ -284,5 +359,6 @@ async function getChaosSeed(page) {
284
359
  injectChaos,
285
360
  injectSWChaos,
286
361
  removeChaos,
287
- removeSWChaos
362
+ removeSWChaos,
363
+ validateChaosConfig
288
364
  });
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, formatSeedReproduction, validateChaosConfig } from '@chaos-maker/core';
4
4
 
5
5
  /**
6
6
  * Shape of the JSON attachment written to `testInfo.attachments` on teardown.
@@ -10,6 +10,7 @@ interface ChaosTraceAttachment {
10
10
  eventCount: number;
11
11
  events: ChaosEvent[];
12
12
  }
13
+
13
14
  interface TraceReporterOptions {
14
15
  /** Emit `test.step` for `applied:false` diagnostic events too. Default false. */
15
16
  verbose?: boolean;
@@ -28,6 +29,11 @@ interface SWChaosOptions {
28
29
  * SWs that do heavy work during `install`.
29
30
  */
30
31
  timeoutMs?: number;
32
+ /**
33
+ * Forwarded to `validateChaosConfig` before the config is posted
34
+ * to the SW. Malformed configs throw a `ChaosConfigError` from Node.
35
+ */
36
+ validation?: ValidateChaosConfigOptions;
31
37
  }
32
38
  interface InjectSWChaosResult {
33
39
  /** Seed used by the PRNG inside the SW. `null` if the ack did not carry one. */
@@ -56,6 +62,14 @@ declare function injectSWChaos(page: Page, config: ChaosConfig, opts?: SWChaosOp
56
62
  * the current controller and clears the page's in-memory log buffer.
57
63
  */
58
64
  declare function removeSWChaos(page: Page, opts?: SWChaosOptions): Promise<void>;
65
+ /**
66
+ * Enable a rule group inside the active SW chaos engine. Posts
67
+ * `__chaosMakerToggleGroup` over MessageChannel and resolves only after the SW
68
+ * acks. Engine state and request counters are preserved (no restart).
69
+ */
70
+ declare function enableSWGroup(page: Page, name: string, opts?: SWChaosOptions): Promise<void>;
71
+ /** Disable a rule group inside the active SW chaos engine. */
72
+ declare function disableSWGroup(page: Page, name: string, opts?: SWChaosOptions): Promise<void>;
59
73
  /**
60
74
  * Read the chaos event log buffered on the page side. Every event emitted by
61
75
  * the SW is broadcast to all controlled clients and captured here.
@@ -90,6 +104,13 @@ interface InjectChaosOptions {
90
104
  testInfo?: TestInfo;
91
105
  /** Pass through to the trace reporter. */
92
106
  traceOptions?: TraceReporterOptions;
107
+ /**
108
+ * Forwarded to `validateChaosConfig` before the config is
109
+ * serialized for the page. Use to relax unknown-field handling, hook
110
+ * deprecation events, or run custom per-`RuleType` validators. Malformed
111
+ * configs throw a `ChaosConfigError` synchronously from Node.
112
+ */
113
+ validation?: ValidateChaosConfigOptions;
93
114
  }
94
115
  /**
95
116
  * Inject chaos into a Playwright page. Call before `page.goto()` to ensure
@@ -119,10 +140,18 @@ declare function removeChaos(page: Page): Promise<void>;
119
140
  * Returns all events emitted since chaos was injected.
120
141
  */
121
142
  declare function getChaosLog(page: Page): Promise<ChaosEvent[]>;
143
+ /**
144
+ * Enable a rule group at runtime in the page-side chaos engine. Resolves once
145
+ * `page.evaluate` round-trips so the call is safe to await before triggering
146
+ * the assertion that depends on the group being live.
147
+ */
148
+ declare function enableGroup(page: Page, name: string): Promise<void>;
149
+ /** Disable a rule group at runtime in the page-side chaos engine. */
150
+ declare function disableGroup(page: Page, name: string): Promise<void>;
122
151
  /**
123
152
  * Retrieve the PRNG seed from a Playwright page.
124
153
  * Log this value on test failure to replay exact chaos decisions.
125
154
  */
126
155
  declare function getChaosSeed(page: Page): Promise<number | null>;
127
156
 
128
- export { type ChaosTraceAttachment, type InjectChaosOptions, type InjectSWChaosResult, type SWChaosOptions, type TraceReporterOptions, getChaosLog, getChaosSeed, getSWChaosLog, getSWChaosLogFromSW, injectChaos, injectSWChaos, removeChaos, removeSWChaos };
157
+ 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, formatSeedReproduction, validateChaosConfig } from '@chaos-maker/core';
4
4
 
5
5
  /**
6
6
  * Shape of the JSON attachment written to `testInfo.attachments` on teardown.
@@ -10,6 +10,7 @@ interface ChaosTraceAttachment {
10
10
  eventCount: number;
11
11
  events: ChaosEvent[];
12
12
  }
13
+
13
14
  interface TraceReporterOptions {
14
15
  /** Emit `test.step` for `applied:false` diagnostic events too. Default false. */
15
16
  verbose?: boolean;
@@ -28,6 +29,11 @@ interface SWChaosOptions {
28
29
  * SWs that do heavy work during `install`.
29
30
  */
30
31
  timeoutMs?: number;
32
+ /**
33
+ * Forwarded to `validateChaosConfig` before the config is posted
34
+ * to the SW. Malformed configs throw a `ChaosConfigError` from Node.
35
+ */
36
+ validation?: ValidateChaosConfigOptions;
31
37
  }
32
38
  interface InjectSWChaosResult {
33
39
  /** Seed used by the PRNG inside the SW. `null` if the ack did not carry one. */
@@ -56,6 +62,14 @@ declare function injectSWChaos(page: Page, config: ChaosConfig, opts?: SWChaosOp
56
62
  * the current controller and clears the page's in-memory log buffer.
57
63
  */
58
64
  declare function removeSWChaos(page: Page, opts?: SWChaosOptions): Promise<void>;
65
+ /**
66
+ * Enable a rule group inside the active SW chaos engine. Posts
67
+ * `__chaosMakerToggleGroup` over MessageChannel and resolves only after the SW
68
+ * acks. Engine state and request counters are preserved (no restart).
69
+ */
70
+ declare function enableSWGroup(page: Page, name: string, opts?: SWChaosOptions): Promise<void>;
71
+ /** Disable a rule group inside the active SW chaos engine. */
72
+ declare function disableSWGroup(page: Page, name: string, opts?: SWChaosOptions): Promise<void>;
59
73
  /**
60
74
  * Read the chaos event log buffered on the page side. Every event emitted by
61
75
  * the SW is broadcast to all controlled clients and captured here.
@@ -90,6 +104,13 @@ interface InjectChaosOptions {
90
104
  testInfo?: TestInfo;
91
105
  /** Pass through to the trace reporter. */
92
106
  traceOptions?: TraceReporterOptions;
107
+ /**
108
+ * Forwarded to `validateChaosConfig` before the config is
109
+ * serialized for the page. Use to relax unknown-field handling, hook
110
+ * deprecation events, or run custom per-`RuleType` validators. Malformed
111
+ * configs throw a `ChaosConfigError` synchronously from Node.
112
+ */
113
+ validation?: ValidateChaosConfigOptions;
93
114
  }
94
115
  /**
95
116
  * Inject chaos into a Playwright page. Call before `page.goto()` to ensure
@@ -119,10 +140,18 @@ declare function removeChaos(page: Page): Promise<void>;
119
140
  * Returns all events emitted since chaos was injected.
120
141
  */
121
142
  declare function getChaosLog(page: Page): Promise<ChaosEvent[]>;
143
+ /**
144
+ * Enable a rule group at runtime in the page-side chaos engine. Resolves once
145
+ * `page.evaluate` round-trips so the call is safe to await before triggering
146
+ * the assertion that depends on the group being live.
147
+ */
148
+ declare function enableGroup(page: Page, name: string): Promise<void>;
149
+ /** Disable a rule group at runtime in the page-side chaos engine. */
150
+ declare function disableGroup(page: Page, name: string): Promise<void>;
122
151
  /**
123
152
  * Retrieve the PRNG seed from a Playwright page.
124
153
  * Log this value on test failure to replay exact chaos decisions.
125
154
  */
126
155
  declare function getChaosSeed(page: Page): Promise<number | null>;
127
156
 
128
- export { type ChaosTraceAttachment, type InjectChaosOptions, type InjectSWChaosResult, type SWChaosOptions, type TraceReporterOptions, getChaosLog, getChaosSeed, getSWChaosLog, getSWChaosLogFromSW, injectChaos, injectSWChaos, removeChaos, removeSWChaos };
157
+ 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,11 @@
1
1
  import {
2
+ ChaosConfigError,
3
+ Logger,
4
+ disableGroup,
5
+ disableSWGroup,
6
+ enableGroup,
7
+ enableSWGroup,
8
+ formatSeedReproduction,
2
9
  getChaosLog,
3
10
  getChaosSeed,
4
11
  getSWChaosLog,
@@ -6,9 +13,17 @@ import {
6
13
  injectChaos,
7
14
  injectSWChaos,
8
15
  removeChaos,
9
- removeSWChaos
10
- } from "./chunk-KHKPTES5.js";
16
+ removeSWChaos,
17
+ validateChaosConfig
18
+ } from "./chunk-ZJZRSTXG.js";
11
19
  export {
20
+ ChaosConfigError,
21
+ Logger,
22
+ disableGroup,
23
+ disableSWGroup,
24
+ enableGroup,
25
+ enableSWGroup,
26
+ formatSeedReproduction,
12
27
  getChaosLog,
13
28
  getChaosSeed,
14
29
  getSWChaosLog,
@@ -16,5 +31,6 @@ export {
16
31
  injectChaos,
17
32
  injectSWChaos,
18
33
  removeChaos,
19
- removeSWChaos
34
+ removeSWChaos,
35
+ validateChaosConfig
20
36
  };
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@chaos-maker/playwright",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
- "description": "Playwright adapter for @chaos-maker/core one-line chaos injection in E2E tests",
5
+ "description": "Playwright adapter for @chaos-maker/core - one-line chaos injection in E2E tests",
6
6
  "keywords": [
7
7
  "chaos-engineering",
8
8
  "playwright",
@@ -49,7 +49,7 @@
49
49
  "dist"
50
50
  ],
51
51
  "dependencies": {
52
- "@chaos-maker/core": "0.4.0"
52
+ "@chaos-maker/core": "0.6.0"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "@playwright/test": ">=1.40.0"