@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/chunk-KHKPTES5.js
DELETED
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
// src/index.ts
|
|
2
|
-
import { serializeForTransport } from "@chaos-maker/core";
|
|
3
|
-
import { resolve, dirname } from "path";
|
|
4
|
-
import { createRequire } from "module";
|
|
5
|
-
import { fileURLToPath } from "url";
|
|
6
|
-
|
|
7
|
-
// src/trace.ts
|
|
8
|
-
import { test } from "@playwright/test";
|
|
9
|
-
var CHAOS_BINDING = "__chaosMakerReport";
|
|
10
|
-
function formatStepTitle(event) {
|
|
11
|
-
const prefix = `chaos:${event.type}`;
|
|
12
|
-
const d = event.detail ?? {};
|
|
13
|
-
const parts = [];
|
|
14
|
-
const subject = d.url ?? d.selector;
|
|
15
|
-
if (subject) parts.push(truncate(subject, 48));
|
|
16
|
-
const outcome = formatOutcome(event);
|
|
17
|
-
if (outcome) parts.push(`\u2192 ${outcome}`);
|
|
18
|
-
if (!event.applied) parts.push("(skipped)");
|
|
19
|
-
return parts.length > 0 ? `${prefix} ${parts.join(" ")}` : prefix;
|
|
20
|
-
}
|
|
21
|
-
function formatOutcome(event) {
|
|
22
|
-
const d = event.detail ?? {};
|
|
23
|
-
switch (event.type) {
|
|
24
|
-
case "network:failure":
|
|
25
|
-
return d.statusCode != null ? String(d.statusCode) : null;
|
|
26
|
-
case "network:latency":
|
|
27
|
-
return d.delayMs != null ? `+${d.delayMs}ms` : null;
|
|
28
|
-
case "network:abort":
|
|
29
|
-
return "abort";
|
|
30
|
-
case "network:corruption":
|
|
31
|
-
return d.strategy ?? "corrupted";
|
|
32
|
-
case "network:cors":
|
|
33
|
-
return "cors-block";
|
|
34
|
-
case "ui:assault":
|
|
35
|
-
return d.action ?? null;
|
|
36
|
-
case "websocket:drop":
|
|
37
|
-
return d.direction ? `drop ${d.direction}` : "drop";
|
|
38
|
-
case "websocket:delay":
|
|
39
|
-
return d.delayMs != null ? `delay ${d.direction ?? ""} +${d.delayMs}ms` : "delay";
|
|
40
|
-
case "websocket:corrupt":
|
|
41
|
-
return d.strategy ?? "corrupt";
|
|
42
|
-
case "websocket:close":
|
|
43
|
-
return d.closeCode != null ? `close ${d.closeCode}` : "close";
|
|
44
|
-
default:
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
function truncate(s, max) {
|
|
49
|
-
if (s.length <= max) return s;
|
|
50
|
-
return `\u2026${s.slice(-(max - 1))}`;
|
|
51
|
-
}
|
|
52
|
-
function shouldEmitStep(event, verbose) {
|
|
53
|
-
if (event.applied) return true;
|
|
54
|
-
return verbose;
|
|
55
|
-
}
|
|
56
|
-
async function createTraceReporter(page, testInfo, opts = {}) {
|
|
57
|
-
const verbose = opts.verbose ?? false;
|
|
58
|
-
const attachmentName = opts.attachmentName ?? "chaos-log.json";
|
|
59
|
-
const events = [];
|
|
60
|
-
const handler = (_source, event) => {
|
|
61
|
-
events.push(event);
|
|
62
|
-
if (!shouldEmitStep(event, verbose)) return;
|
|
63
|
-
const title = formatStepTitle(event);
|
|
64
|
-
test.step(title, async () => {
|
|
65
|
-
}).catch(() => {
|
|
66
|
-
});
|
|
67
|
-
};
|
|
68
|
-
await page.exposeBinding(CHAOS_BINDING, handler);
|
|
69
|
-
await page.addInitScript((bindingName) => {
|
|
70
|
-
const win = globalThis;
|
|
71
|
-
const attach = () => {
|
|
72
|
-
const utils = win.chaosUtils;
|
|
73
|
-
if (!utils || !utils.instance) return false;
|
|
74
|
-
if (utils.__chaosMakerTraceBound === utils.instance) return true;
|
|
75
|
-
utils.__chaosMakerTraceBound = utils.instance;
|
|
76
|
-
utils.instance.on("*", (event) => {
|
|
77
|
-
try {
|
|
78
|
-
if (typeof win[bindingName] === "function") {
|
|
79
|
-
win[bindingName](event);
|
|
80
|
-
}
|
|
81
|
-
} catch {
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
return true;
|
|
85
|
-
};
|
|
86
|
-
if (attach()) return;
|
|
87
|
-
const intervalId = setInterval(() => {
|
|
88
|
-
if (attach()) clearInterval(intervalId);
|
|
89
|
-
}, 10);
|
|
90
|
-
setTimeout(() => clearInterval(intervalId), 5e3);
|
|
91
|
-
}, CHAOS_BINDING);
|
|
92
|
-
return {
|
|
93
|
-
events,
|
|
94
|
-
dispose: async (seed = null) => {
|
|
95
|
-
const payload = {
|
|
96
|
-
seed,
|
|
97
|
-
eventCount: events.length,
|
|
98
|
-
events
|
|
99
|
-
};
|
|
100
|
-
try {
|
|
101
|
-
await testInfo.attach(attachmentName, {
|
|
102
|
-
body: Buffer.from(JSON.stringify(payload, null, 2), "utf-8"),
|
|
103
|
-
contentType: "application/json"
|
|
104
|
-
});
|
|
105
|
-
} catch {
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// src/sw.ts
|
|
112
|
-
import { validateConfig, SW_BRIDGE_SOURCE } from "@chaos-maker/core";
|
|
113
|
-
var BRIDGE_INIT_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.sw.bridgeInit");
|
|
114
|
-
async function ensurePageBridge(page) {
|
|
115
|
-
if (!page[BRIDGE_INIT_KEY]) {
|
|
116
|
-
await page.addInitScript({ content: SW_BRIDGE_SOURCE });
|
|
117
|
-
page[BRIDGE_INIT_KEY] = true;
|
|
118
|
-
}
|
|
119
|
-
await page.evaluate(SW_BRIDGE_SOURCE).catch(() => {
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
async function injectSWChaos(page, config, opts = {}) {
|
|
123
|
-
const validated = validateConfig(config);
|
|
124
|
-
const timeoutMs = opts.timeoutMs ?? 1e4;
|
|
125
|
-
await ensurePageBridge(page);
|
|
126
|
-
const result = await page.evaluate(
|
|
127
|
-
async ({ cfg, timeoutMs: timeoutMs2 }) => {
|
|
128
|
-
const bridge = globalThis.__chaosMakerSWBridge;
|
|
129
|
-
if (!bridge) throw new Error("[chaos-maker] SW bridge missing from page \u2014 ensurePageBridge failed");
|
|
130
|
-
return await bridge.apply(cfg, timeoutMs2);
|
|
131
|
-
},
|
|
132
|
-
{ cfg: validated, timeoutMs }
|
|
133
|
-
);
|
|
134
|
-
return result;
|
|
135
|
-
}
|
|
136
|
-
async function removeSWChaos(page, opts = {}) {
|
|
137
|
-
const timeoutMs = opts.timeoutMs ?? 5e3;
|
|
138
|
-
await page.evaluate(
|
|
139
|
-
async ({ timeoutMs: timeoutMs2 }) => {
|
|
140
|
-
const bridge = globalThis.__chaosMakerSWBridge;
|
|
141
|
-
if (!bridge) return;
|
|
142
|
-
await bridge.stop(timeoutMs2);
|
|
143
|
-
bridge.clearLocalLog();
|
|
144
|
-
},
|
|
145
|
-
{ timeoutMs }
|
|
146
|
-
).catch(() => {
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
async function getSWChaosLog(page) {
|
|
150
|
-
return page.evaluate(() => {
|
|
151
|
-
const bridge = globalThis.__chaosMakerSWBridge;
|
|
152
|
-
if (!bridge) return [];
|
|
153
|
-
return bridge.getLocalLog();
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
async function getSWChaosLogFromSW(page, opts = {}) {
|
|
157
|
-
const timeoutMs = opts.timeoutMs ?? 5e3;
|
|
158
|
-
return page.evaluate(
|
|
159
|
-
async ({ timeoutMs: timeoutMs2 }) => {
|
|
160
|
-
const bridge = globalThis.__chaosMakerSWBridge;
|
|
161
|
-
if (!bridge) return [];
|
|
162
|
-
return bridge.getRemoteLog(timeoutMs2);
|
|
163
|
-
},
|
|
164
|
-
{ timeoutMs }
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// src/index.ts
|
|
169
|
-
var cachedUmdPath = null;
|
|
170
|
-
function getCoreUmdPath() {
|
|
171
|
-
if (cachedUmdPath) return cachedUmdPath;
|
|
172
|
-
const currentDir = typeof __dirname !== "undefined" ? __dirname : dirname(fileURLToPath(import.meta.url));
|
|
173
|
-
const req = createRequire(resolve(currentDir, "package.json"));
|
|
174
|
-
const coreEntry = req.resolve("@chaos-maker/core");
|
|
175
|
-
const coreDistDir = dirname(coreEntry);
|
|
176
|
-
cachedUmdPath = resolve(coreDistDir, "chaos-maker.umd.js");
|
|
177
|
-
return cachedUmdPath;
|
|
178
|
-
}
|
|
179
|
-
var TRACE_HANDLE_KEY = /* @__PURE__ */ Symbol.for("chaos-maker.playwright.traceHandle");
|
|
180
|
-
async function injectChaos(page, config, opts = {}) {
|
|
181
|
-
const umdPath = getCoreUmdPath();
|
|
182
|
-
const tracingEnabled = resolveTracing(opts);
|
|
183
|
-
if (tracingEnabled) {
|
|
184
|
-
if (!opts.testInfo) {
|
|
185
|
-
throw new Error(
|
|
186
|
-
"[chaos-maker] tracing requires a `testInfo` in InjectChaosOptions. Use the fixture (`@chaos-maker/playwright/fixture`) or pass testInfo explicitly."
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
const existing = page[TRACE_HANDLE_KEY];
|
|
190
|
-
if (!existing) {
|
|
191
|
-
const handle = await createTraceReporter(page, opts.testInfo, opts.traceOptions);
|
|
192
|
-
page[TRACE_HANDLE_KEY] = handle;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
const serialized = serializeForTransport(config);
|
|
196
|
-
await page.addInitScript((cfg) => {
|
|
197
|
-
const win = globalThis;
|
|
198
|
-
win.__CHAOS_CONFIG__ = cfg;
|
|
199
|
-
}, serialized);
|
|
200
|
-
await page.addInitScript({ path: umdPath });
|
|
201
|
-
}
|
|
202
|
-
function resolveTracing(opts) {
|
|
203
|
-
if (opts.tracing === true) return true;
|
|
204
|
-
if (opts.tracing === false || opts.tracing === void 0) return false;
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
async function removeChaos(page) {
|
|
208
|
-
const handle = page[TRACE_HANDLE_KEY];
|
|
209
|
-
let seed = null;
|
|
210
|
-
if (handle) {
|
|
211
|
-
try {
|
|
212
|
-
seed = await getChaosSeed(page);
|
|
213
|
-
} catch {
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
await page.evaluate(() => {
|
|
217
|
-
const win = globalThis;
|
|
218
|
-
if (win.chaosUtils) {
|
|
219
|
-
win.chaosUtils.stop();
|
|
220
|
-
}
|
|
221
|
-
}).catch(() => {
|
|
222
|
-
});
|
|
223
|
-
if (handle) {
|
|
224
|
-
await handle.dispose(seed);
|
|
225
|
-
delete page[TRACE_HANDLE_KEY];
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
async function getChaosLog(page) {
|
|
229
|
-
return page.evaluate(() => {
|
|
230
|
-
const win = globalThis;
|
|
231
|
-
if (win.chaosUtils) {
|
|
232
|
-
return win.chaosUtils.getLog();
|
|
233
|
-
}
|
|
234
|
-
return [];
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
async function getChaosSeed(page) {
|
|
238
|
-
return page.evaluate(() => {
|
|
239
|
-
const win = globalThis;
|
|
240
|
-
if (win.chaosUtils) {
|
|
241
|
-
return win.chaosUtils.getSeed();
|
|
242
|
-
}
|
|
243
|
-
return null;
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
export {
|
|
248
|
-
injectSWChaos,
|
|
249
|
-
removeSWChaos,
|
|
250
|
-
getSWChaosLog,
|
|
251
|
-
getSWChaosLogFromSW,
|
|
252
|
-
injectChaos,
|
|
253
|
-
removeChaos,
|
|
254
|
-
getChaosLog,
|
|
255
|
-
getChaosSeed
|
|
256
|
-
};
|