@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/README.md +159 -28
- package/dist/chunk-ZJZRSTXG.js +324 -0
- package/dist/fixture.cjs +150 -81
- package/dist/fixture.d.cts +5 -1
- package/dist/fixture.d.ts +5 -1
- package/dist/fixture.js +10 -2
- package/dist/index.cjs +163 -87
- package/dist/index.d.cts +32 -3
- package/dist/index.d.ts +32 -3
- package/dist/index.js +19 -3
- package/package.json +3 -3
- package/dist/chunk-KHKPTES5.js +0 -256
package/dist/fixture.cjs
CHANGED
|
@@ -27,97 +27,66 @@ module.exports = __toCommonJS(fixture_exports);
|
|
|
27
27
|
var import_test2 = require("@playwright/test");
|
|
28
28
|
|
|
29
29
|
// src/index.ts
|
|
30
|
-
var
|
|
30
|
+
var import_core4 = require("@chaos-maker/core");
|
|
31
31
|
var import_path = require("path");
|
|
32
32
|
var import_module = require("module");
|
|
33
33
|
var import_url = require("url");
|
|
34
34
|
|
|
35
35
|
// src/trace.ts
|
|
36
36
|
var import_test = require("@playwright/test");
|
|
37
|
+
var import_core = require("@chaos-maker/core");
|
|
38
|
+
var import_core2 = require("@chaos-maker/core");
|
|
37
39
|
var CHAOS_BINDING = "__chaosMakerReport";
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const d = event.detail ?? {};
|
|
41
|
-
const parts = [];
|
|
42
|
-
const subject = d.url ?? d.selector;
|
|
43
|
-
if (subject) parts.push(truncate(subject, 48));
|
|
44
|
-
const outcome = formatOutcome(event);
|
|
45
|
-
if (outcome) parts.push(`\u2192 ${outcome}`);
|
|
46
|
-
if (!event.applied) parts.push("(skipped)");
|
|
47
|
-
return parts.length > 0 ? `${prefix} ${parts.join(" ")}` : prefix;
|
|
48
|
-
}
|
|
49
|
-
function formatOutcome(event) {
|
|
50
|
-
const d = event.detail ?? {};
|
|
51
|
-
switch (event.type) {
|
|
52
|
-
case "network:failure":
|
|
53
|
-
return d.statusCode != null ? String(d.statusCode) : null;
|
|
54
|
-
case "network:latency":
|
|
55
|
-
return d.delayMs != null ? `+${d.delayMs}ms` : null;
|
|
56
|
-
case "network:abort":
|
|
57
|
-
return "abort";
|
|
58
|
-
case "network:corruption":
|
|
59
|
-
return d.strategy ?? "corrupted";
|
|
60
|
-
case "network:cors":
|
|
61
|
-
return "cors-block";
|
|
62
|
-
case "ui:assault":
|
|
63
|
-
return d.action ?? null;
|
|
64
|
-
case "websocket:drop":
|
|
65
|
-
return d.direction ? `drop ${d.direction}` : "drop";
|
|
66
|
-
case "websocket:delay":
|
|
67
|
-
return d.delayMs != null ? `delay ${d.direction ?? ""} +${d.delayMs}ms` : "delay";
|
|
68
|
-
case "websocket:corrupt":
|
|
69
|
-
return d.strategy ?? "corrupt";
|
|
70
|
-
case "websocket:close":
|
|
71
|
-
return d.closeCode != null ? `close ${d.closeCode}` : "close";
|
|
72
|
-
default:
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
function truncate(s, max) {
|
|
77
|
-
if (s.length <= max) return s;
|
|
78
|
-
return `\u2026${s.slice(-(max - 1))}`;
|
|
79
|
-
}
|
|
80
|
-
function shouldEmitStep(event, verbose) {
|
|
81
|
-
if (event.applied) return true;
|
|
82
|
-
return verbose;
|
|
83
|
-
}
|
|
40
|
+
var TRACE_HANDLE_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.traceHandle");
|
|
41
|
+
var TRACE_BINDING_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.traceBinding");
|
|
84
42
|
async function createTraceReporter(page, testInfo, opts = {}) {
|
|
43
|
+
const existing = page[TRACE_HANDLE_KEY];
|
|
44
|
+
if (existing) return existing;
|
|
85
45
|
const verbose = opts.verbose ?? false;
|
|
86
46
|
const attachmentName = opts.attachmentName ?? "chaos-log.json";
|
|
87
47
|
const events = [];
|
|
88
48
|
const handler = (_source, event) => {
|
|
89
49
|
events.push(event);
|
|
90
|
-
if (!shouldEmitStep(event, verbose)) return;
|
|
91
|
-
const title = formatStepTitle(event);
|
|
50
|
+
if (!(0, import_core.shouldEmitStep)(event, verbose)) return;
|
|
51
|
+
const title = (0, import_core.formatStepTitle)(event);
|
|
92
52
|
import_test.test.step(title, async () => {
|
|
93
53
|
}).catch(() => {
|
|
94
54
|
});
|
|
95
55
|
};
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
56
|
+
let state = page[TRACE_BINDING_KEY];
|
|
57
|
+
if (!state) {
|
|
58
|
+
state = { handler };
|
|
59
|
+
page[TRACE_BINDING_KEY] = state;
|
|
60
|
+
await page.exposeBinding(CHAOS_BINDING, (source, event) => {
|
|
61
|
+
state.handler(source, event);
|
|
62
|
+
});
|
|
63
|
+
await page.addInitScript((bindingName) => {
|
|
64
|
+
const win = globalThis;
|
|
65
|
+
const attach = () => {
|
|
66
|
+
const utils = win.chaosUtils;
|
|
67
|
+
if (!utils || !utils.instance) return false;
|
|
68
|
+
if (utils.__chaosMakerTraceBound === utils.instance) return true;
|
|
69
|
+
utils.__chaosMakerTraceBound = utils.instance;
|
|
70
|
+
utils.instance.on("*", (event) => {
|
|
71
|
+
try {
|
|
72
|
+
if (typeof win[bindingName] === "function") {
|
|
73
|
+
win[bindingName](event);
|
|
74
|
+
}
|
|
75
|
+
} catch {
|
|
108
76
|
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
return
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
},
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
77
|
+
});
|
|
78
|
+
return true;
|
|
79
|
+
};
|
|
80
|
+
if (attach()) return;
|
|
81
|
+
const intervalId = setInterval(() => {
|
|
82
|
+
if (attach()) clearInterval(intervalId);
|
|
83
|
+
}, 10);
|
|
84
|
+
setTimeout(() => clearInterval(intervalId), 5e3);
|
|
85
|
+
}, CHAOS_BINDING);
|
|
86
|
+
} else {
|
|
87
|
+
state.handler = handler;
|
|
88
|
+
}
|
|
89
|
+
const handle = {
|
|
121
90
|
events,
|
|
122
91
|
dispose: async (seed = null) => {
|
|
123
92
|
const payload = {
|
|
@@ -132,12 +101,63 @@ async function createTraceReporter(page, testInfo, opts = {}) {
|
|
|
132
101
|
});
|
|
133
102
|
} catch {
|
|
134
103
|
}
|
|
104
|
+
if (page[TRACE_HANDLE_KEY] === handle) {
|
|
105
|
+
delete page[TRACE_HANDLE_KEY];
|
|
106
|
+
}
|
|
135
107
|
}
|
|
136
108
|
};
|
|
109
|
+
page[TRACE_HANDLE_KEY] = handle;
|
|
110
|
+
return handle;
|
|
137
111
|
}
|
|
138
112
|
|
|
113
|
+
// src/index.ts
|
|
114
|
+
var import_core5 = require("@chaos-maker/core");
|
|
115
|
+
var import_core6 = require("@chaos-maker/core");
|
|
116
|
+
|
|
139
117
|
// src/sw.ts
|
|
140
|
-
var
|
|
118
|
+
var import_core3 = require("@chaos-maker/core");
|
|
119
|
+
var BRIDGE_INIT_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.sw.bridgeInit");
|
|
120
|
+
var DEFAULT_SW_TOGGLE_TIMEOUT = 2e3;
|
|
121
|
+
async function ensurePageBridge(page) {
|
|
122
|
+
if (!page[BRIDGE_INIT_KEY]) {
|
|
123
|
+
await page.addInitScript({ content: import_core3.SW_BRIDGE_SOURCE });
|
|
124
|
+
page[BRIDGE_INIT_KEY] = true;
|
|
125
|
+
}
|
|
126
|
+
await page.evaluate(import_core3.SW_BRIDGE_SOURCE).catch(() => {
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async function enableSWGroup(page, name, opts = {}) {
|
|
130
|
+
if (typeof name !== "string") {
|
|
131
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
132
|
+
}
|
|
133
|
+
const nameNorm = name.trim();
|
|
134
|
+
if (!nameNorm) {
|
|
135
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
136
|
+
}
|
|
137
|
+
await toggleSWGroup(page, nameNorm, true, opts);
|
|
138
|
+
}
|
|
139
|
+
async function disableSWGroup(page, name, opts = {}) {
|
|
140
|
+
if (typeof name !== "string") {
|
|
141
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
142
|
+
}
|
|
143
|
+
const nameNorm = name.trim();
|
|
144
|
+
if (!nameNorm) {
|
|
145
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
146
|
+
}
|
|
147
|
+
await toggleSWGroup(page, nameNorm, false, opts);
|
|
148
|
+
}
|
|
149
|
+
async function toggleSWGroup(page, name, enabled, opts) {
|
|
150
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_SW_TOGGLE_TIMEOUT;
|
|
151
|
+
await ensurePageBridge(page);
|
|
152
|
+
await page.evaluate(
|
|
153
|
+
async ({ n, e, t }) => {
|
|
154
|
+
const bridge = globalThis.__chaosMakerSWBridge;
|
|
155
|
+
if (!bridge) throw new Error("[chaos-maker] SW bridge missing \u2014 ensurePageBridge failed");
|
|
156
|
+
await bridge.toggleGroup(n, e, t);
|
|
157
|
+
},
|
|
158
|
+
{ n: name, e: enabled, t: timeoutMs }
|
|
159
|
+
);
|
|
160
|
+
}
|
|
141
161
|
|
|
142
162
|
// src/index.ts
|
|
143
163
|
var import_meta = {};
|
|
@@ -151,8 +171,9 @@ function getCoreUmdPath() {
|
|
|
151
171
|
cachedUmdPath = (0, import_path.resolve)(coreDistDir, "chaos-maker.umd.js");
|
|
152
172
|
return cachedUmdPath;
|
|
153
173
|
}
|
|
154
|
-
var
|
|
174
|
+
var TRACE_HANDLE_KEY2 = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.traceHandle");
|
|
155
175
|
async function injectChaos(page, config, opts = {}) {
|
|
176
|
+
const validated = (0, import_core4.validateChaosConfig)(config, opts.validation);
|
|
156
177
|
const umdPath = getCoreUmdPath();
|
|
157
178
|
const tracingEnabled = resolveTracing(opts);
|
|
158
179
|
if (tracingEnabled) {
|
|
@@ -161,13 +182,13 @@ async function injectChaos(page, config, opts = {}) {
|
|
|
161
182
|
"[chaos-maker] tracing requires a `testInfo` in InjectChaosOptions. Use the fixture (`@chaos-maker/playwright/fixture`) or pass testInfo explicitly."
|
|
162
183
|
);
|
|
163
184
|
}
|
|
164
|
-
const existing = page[
|
|
185
|
+
const existing = page[TRACE_HANDLE_KEY2];
|
|
165
186
|
if (!existing) {
|
|
166
187
|
const handle = await createTraceReporter(page, opts.testInfo, opts.traceOptions);
|
|
167
|
-
page[
|
|
188
|
+
page[TRACE_HANDLE_KEY2] = handle;
|
|
168
189
|
}
|
|
169
190
|
}
|
|
170
|
-
const serialized = (0,
|
|
191
|
+
const serialized = (0, import_core4.serializeForTransport)(validated);
|
|
171
192
|
await page.addInitScript((cfg) => {
|
|
172
193
|
const win = globalThis;
|
|
173
194
|
win.__CHAOS_CONFIG__ = cfg;
|
|
@@ -180,7 +201,7 @@ function resolveTracing(opts) {
|
|
|
180
201
|
return false;
|
|
181
202
|
}
|
|
182
203
|
async function removeChaos(page) {
|
|
183
|
-
const handle = page[
|
|
204
|
+
const handle = page[TRACE_HANDLE_KEY2];
|
|
184
205
|
let seed = null;
|
|
185
206
|
if (handle) {
|
|
186
207
|
try {
|
|
@@ -197,7 +218,7 @@ async function removeChaos(page) {
|
|
|
197
218
|
});
|
|
198
219
|
if (handle) {
|
|
199
220
|
await handle.dispose(seed);
|
|
200
|
-
delete page[
|
|
221
|
+
delete page[TRACE_HANDLE_KEY2];
|
|
201
222
|
}
|
|
202
223
|
}
|
|
203
224
|
async function getChaosLog(page) {
|
|
@@ -209,6 +230,50 @@ async function getChaosLog(page) {
|
|
|
209
230
|
return [];
|
|
210
231
|
});
|
|
211
232
|
}
|
|
233
|
+
async function enableGroup(page, name) {
|
|
234
|
+
if (typeof name !== "string") {
|
|
235
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
236
|
+
}
|
|
237
|
+
const nameNorm = name.trim();
|
|
238
|
+
if (!nameNorm) {
|
|
239
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
240
|
+
}
|
|
241
|
+
await page.evaluate(({ n }) => {
|
|
242
|
+
const utils = globalThis.chaosUtils;
|
|
243
|
+
if (!utils || !utils.instance) {
|
|
244
|
+
throw new Error("[chaos-maker] no chaos instance on page \u2014 call injectChaos first");
|
|
245
|
+
}
|
|
246
|
+
if (typeof utils.enableGroup !== "function") {
|
|
247
|
+
throw new Error("[chaos-maker] enableGroup API unavailable");
|
|
248
|
+
}
|
|
249
|
+
const result = utils.enableGroup(n);
|
|
250
|
+
if (result && result.success === false) {
|
|
251
|
+
throw new Error(`[chaos-maker] enableGroup('${n}') failed: ${result.message}`);
|
|
252
|
+
}
|
|
253
|
+
}, { n: nameNorm });
|
|
254
|
+
}
|
|
255
|
+
async function disableGroup(page, name) {
|
|
256
|
+
if (typeof name !== "string") {
|
|
257
|
+
throw new Error("[chaos-maker] group name must be a string");
|
|
258
|
+
}
|
|
259
|
+
const nameNorm = name.trim();
|
|
260
|
+
if (!nameNorm) {
|
|
261
|
+
throw new Error("[chaos-maker] group name cannot be empty");
|
|
262
|
+
}
|
|
263
|
+
await page.evaluate(({ n }) => {
|
|
264
|
+
const utils = globalThis.chaosUtils;
|
|
265
|
+
if (!utils || !utils.instance) {
|
|
266
|
+
throw new Error("[chaos-maker] no chaos instance on page \u2014 call injectChaos first");
|
|
267
|
+
}
|
|
268
|
+
if (typeof utils.disableGroup !== "function") {
|
|
269
|
+
throw new Error("[chaos-maker] disableGroup API unavailable");
|
|
270
|
+
}
|
|
271
|
+
const result = utils.disableGroup(n);
|
|
272
|
+
if (result && result.success === false) {
|
|
273
|
+
throw new Error(`[chaos-maker] disableGroup('${n}') failed: ${result.message}`);
|
|
274
|
+
}
|
|
275
|
+
}, { n: nameNorm });
|
|
276
|
+
}
|
|
212
277
|
async function getChaosSeed(page) {
|
|
213
278
|
return page.evaluate(() => {
|
|
214
279
|
const win = globalThis;
|
|
@@ -247,7 +312,11 @@ var test2 = import_test2.test.extend({
|
|
|
247
312
|
},
|
|
248
313
|
remove: () => removeChaos(page),
|
|
249
314
|
getLog: () => getChaosLog(page),
|
|
250
|
-
getSeed: () => getChaosSeed(page)
|
|
315
|
+
getSeed: () => getChaosSeed(page),
|
|
316
|
+
enableGroup: (name) => enableGroup(page, name),
|
|
317
|
+
disableGroup: (name) => disableGroup(page, name),
|
|
318
|
+
enableSWGroup: (name, opts) => enableSWGroup(page, name, opts),
|
|
319
|
+
disableSWGroup: (name, opts) => disableSWGroup(page, name, opts)
|
|
251
320
|
};
|
|
252
321
|
await use(fixture);
|
|
253
322
|
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-ZJZRSTXG.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);
|