@playwright-repl/browser-extension 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +176 -0
- package/dist/background.js +162567 -0
- package/dist/background.js.map +1 -0
- package/dist/content/recorder.js +479 -0
- package/dist/content/trace-loader.js +12 -0
- package/dist/devtools/console.html +17 -0
- package/dist/devtools/console.js +44 -0
- package/dist/devtools/console.js.map +1 -0
- package/dist/devtools/devtools.html +8 -0
- package/dist/devtools/devtools.js +7 -0
- package/dist/devtools/devtools.js.map +1 -0
- package/dist/icons/dramaturg_icon_128.png +0 -0
- package/dist/icons/dramaturg_icon_16.png +0 -0
- package/dist/icons/dramaturg_icon_32.png +0 -0
- package/dist/icons/dramaturg_icon_48.png +0 -0
- package/dist/index.css +1353 -0
- package/dist/index.js +12462 -0
- package/dist/index.js.map +1 -0
- package/dist/index2.js +27328 -0
- package/dist/index2.js.map +1 -0
- package/dist/manifest.json +49 -0
- package/dist/modulepreload-polyfill.js +30 -0
- package/dist/modulepreload-polyfill.js.map +1 -0
- package/dist/offscreen/offscreen.html +6 -0
- package/dist/offscreen/offscreen.js +151 -0
- package/dist/offscreen/offscreen.js.map +1 -0
- package/dist/panel/panel.html +16 -0
- package/dist/panel/panel.js +2258 -0
- package/dist/panel/panel.js.map +1 -0
- package/dist/preferences/preferences.html +14 -0
- package/dist/preferences/preferences.js +102 -0
- package/dist/preferences/preferences.js.map +1 -0
- package/dist/settings.js +13 -0
- package/dist/settings.js.map +1 -0
- package/dist/sw-debugger-core.js +1139 -0
- package/dist/sw-debugger-core.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,1139 @@
|
|
|
1
|
+
async function verifyText(page, text) {
|
|
2
|
+
if (await page.getByText(text).filter({ visible: true }).count() === 0)
|
|
3
|
+
throw new Error("Text not found: " + text);
|
|
4
|
+
}
|
|
5
|
+
async function verifyElement(page, role, name) {
|
|
6
|
+
if (await page.getByRole(role, { name }).count() === 0)
|
|
7
|
+
throw new Error("Element not found: " + role + ' "' + name + '"');
|
|
8
|
+
}
|
|
9
|
+
async function verifyValue(page, ref, expected) {
|
|
10
|
+
const el = page.locator('[aria-ref="' + ref + '"]');
|
|
11
|
+
const v = await el.inputValue();
|
|
12
|
+
if (v !== expected)
|
|
13
|
+
throw new Error('Expected "' + expected + '", got "' + v + '"');
|
|
14
|
+
}
|
|
15
|
+
async function verifyList(page, ref, items) {
|
|
16
|
+
const loc = page.locator('[aria-ref="' + ref + '"]');
|
|
17
|
+
for (const item of items) {
|
|
18
|
+
if (await loc.getByText(item).count() === 0)
|
|
19
|
+
throw new Error("Item not found: " + item);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function verifyTitle(page, text) {
|
|
23
|
+
const title = await page.title();
|
|
24
|
+
if (!title.includes(text))
|
|
25
|
+
throw new Error('Title "' + title + '" does not contain "' + text + '"');
|
|
26
|
+
}
|
|
27
|
+
async function verifyUrl(page, text) {
|
|
28
|
+
const url = page.url();
|
|
29
|
+
if (!url.includes(text))
|
|
30
|
+
throw new Error('URL "' + url + '" does not contain "' + text + '"');
|
|
31
|
+
}
|
|
32
|
+
async function waitForText(page, text) {
|
|
33
|
+
await page.getByText(text).first().waitFor({ state: "visible", timeout: 1e4 });
|
|
34
|
+
}
|
|
35
|
+
async function verifyNoText(page, text) {
|
|
36
|
+
if (await page.getByText(text).filter({ visible: true }).count() > 0)
|
|
37
|
+
throw new Error("Text still visible: " + text);
|
|
38
|
+
}
|
|
39
|
+
async function verifyNoElement(page, role, name) {
|
|
40
|
+
if (await page.getByRole(role, { name }).count() > 0)
|
|
41
|
+
throw new Error("Element still exists: " + role + ' "' + name + '"');
|
|
42
|
+
}
|
|
43
|
+
async function verifyVisible(page, role, name) {
|
|
44
|
+
if (!await page.getByRole(role, { name }).isVisible())
|
|
45
|
+
throw new Error("Element not visible: " + role + ' "' + name + '"');
|
|
46
|
+
}
|
|
47
|
+
async function verifyInputValue(page, label, expected) {
|
|
48
|
+
let loc = page.getByLabel(label);
|
|
49
|
+
if (await loc.count() === 0) loc = page.getByRole("spinbutton", { name: label });
|
|
50
|
+
if (await loc.count() === 0) loc = page.getByRole("textbox", { name: label });
|
|
51
|
+
if (await loc.count() === 0) loc = page.getByRole("combobox", { name: label });
|
|
52
|
+
if (await loc.count() > 0) {
|
|
53
|
+
const el = loc.first();
|
|
54
|
+
const inputType = await el.evaluate((e) => e instanceof HTMLInputElement ? e.type : "");
|
|
55
|
+
if (inputType === "checkbox") {
|
|
56
|
+
const isChecked = await el.isChecked();
|
|
57
|
+
const expectChecked = ["checked", "true", "yes", "1"].includes(expected.toLowerCase());
|
|
58
|
+
if (isChecked !== expectChecked)
|
|
59
|
+
throw new Error('Expected "' + label + '" to be ' + expected + ", but was " + (isChecked ? "checked" : "unchecked"));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const value = await el.inputValue();
|
|
63
|
+
if (String(value) !== String(expected))
|
|
64
|
+
throw new Error('Expected "' + expected + '", got "' + value + '" for "' + label + '"');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const group = page.getByRole("group", { name: label });
|
|
68
|
+
if (await group.count() > 0) {
|
|
69
|
+
const checkedRadio = group.locator("input[type=radio]:checked");
|
|
70
|
+
if (await checkedRadio.count() === 0)
|
|
71
|
+
throw new Error('No radio button selected in group "' + label + '"');
|
|
72
|
+
const value = await checkedRadio.evaluate((e) => {
|
|
73
|
+
const lbl = document.querySelector('label[for="' + e.id + '"]');
|
|
74
|
+
return lbl ? lbl.textContent.trim() : e.value;
|
|
75
|
+
});
|
|
76
|
+
if (value !== expected)
|
|
77
|
+
throw new Error('Expected "' + expected + '" selected, got "' + value + '" in group "' + label + '"');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
throw new Error("Element not found for label: " + label);
|
|
81
|
+
}
|
|
82
|
+
async function actionByText(page, text, action, nth, exact) {
|
|
83
|
+
let loc = page.getByText(text, { exact: true });
|
|
84
|
+
if (!exact) {
|
|
85
|
+
if (await loc.count() === 0) loc = page.getByRole("button", { name: text });
|
|
86
|
+
if (await loc.count() === 0) loc = page.getByRole("link", { name: text });
|
|
87
|
+
if (await loc.count() === 0) loc = page.getByRole("textbox", { name: text });
|
|
88
|
+
if (await loc.count() === 0) loc = page.getByRole("combobox", { name: text });
|
|
89
|
+
if (await loc.count() === 0) loc = page.getByPlaceholder(text);
|
|
90
|
+
if (await loc.count() === 0) loc = page.getByText(text);
|
|
91
|
+
}
|
|
92
|
+
if (nth !== void 0) loc = loc.filter({ visible: true }).nth(nth);
|
|
93
|
+
await loc[action]();
|
|
94
|
+
}
|
|
95
|
+
async function fillByText(page, text, value, nth, exact) {
|
|
96
|
+
let loc = page.getByLabel(text);
|
|
97
|
+
if (!exact) {
|
|
98
|
+
if (await loc.count() === 0) loc = page.getByPlaceholder(text);
|
|
99
|
+
if (await loc.count() === 0) loc = page.getByRole("textbox", { name: text });
|
|
100
|
+
}
|
|
101
|
+
if (nth !== void 0) loc = loc.filter({ visible: true }).nth(nth);
|
|
102
|
+
await loc.fill(value);
|
|
103
|
+
}
|
|
104
|
+
async function selectByText(page, text, value, nth, exact) {
|
|
105
|
+
let loc = page.getByLabel(text);
|
|
106
|
+
if (!exact) {
|
|
107
|
+
if (await loc.count() === 0) loc = page.getByRole("combobox", { name: text });
|
|
108
|
+
}
|
|
109
|
+
if (nth !== void 0) loc = loc.filter({ visible: true }).nth(nth);
|
|
110
|
+
await loc.selectOption(value);
|
|
111
|
+
}
|
|
112
|
+
async function checkByText(page, text, nth, exact) {
|
|
113
|
+
if (!exact) {
|
|
114
|
+
const item = page.getByRole("listitem").filter({ hasText: text });
|
|
115
|
+
if (await item.count() > 0) {
|
|
116
|
+
const target = nth !== void 0 ? item.filter({ visible: true }).nth(nth) : item;
|
|
117
|
+
await target.getByRole("checkbox").check();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
let loc = page.getByLabel(text);
|
|
122
|
+
if (!exact) {
|
|
123
|
+
if (await loc.count() === 0) loc = page.getByRole("checkbox", { name: text });
|
|
124
|
+
}
|
|
125
|
+
if (nth !== void 0) loc = loc.filter({ visible: true }).nth(nth);
|
|
126
|
+
await loc.check();
|
|
127
|
+
}
|
|
128
|
+
async function uncheckByText(page, text, nth, exact) {
|
|
129
|
+
if (!exact) {
|
|
130
|
+
const item = page.getByRole("listitem").filter({ hasText: text });
|
|
131
|
+
if (await item.count() > 0) {
|
|
132
|
+
const target = nth !== void 0 ? item.filter({ visible: true }).nth(nth) : item;
|
|
133
|
+
await target.getByRole("checkbox").uncheck();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
let loc = page.getByLabel(text);
|
|
138
|
+
if (!exact) {
|
|
139
|
+
if (await loc.count() === 0) loc = page.getByRole("checkbox", { name: text });
|
|
140
|
+
}
|
|
141
|
+
if (nth !== void 0) loc = loc.filter({ visible: true }).nth(nth);
|
|
142
|
+
await loc.uncheck();
|
|
143
|
+
}
|
|
144
|
+
async function actionByRole(page, role, name, action, nth, inRole, inText) {
|
|
145
|
+
let loc = page.getByRole(role, { name, exact: true });
|
|
146
|
+
if (inRole !== void 0 && inText !== void 0) {
|
|
147
|
+
const cr = { list: "listitem" }[inRole] || inRole;
|
|
148
|
+
loc = page.getByRole(cr).filter({ hasText: inText }).getByRole(role, { name, exact: true });
|
|
149
|
+
}
|
|
150
|
+
if (nth !== void 0) loc = loc.nth(nth);
|
|
151
|
+
await loc[action]();
|
|
152
|
+
}
|
|
153
|
+
async function fillByRole(page, role, name, value, nth, inRole, inText) {
|
|
154
|
+
let loc = page.getByRole(role, { name, exact: true });
|
|
155
|
+
if (inRole !== void 0 && inText !== void 0) {
|
|
156
|
+
const cr = { list: "listitem" }[inRole] || inRole;
|
|
157
|
+
loc = page.getByRole(cr).filter({ hasText: inText }).getByRole(role, { name, exact: true });
|
|
158
|
+
}
|
|
159
|
+
if (nth !== void 0) loc = loc.nth(nth);
|
|
160
|
+
await loc.fill(value);
|
|
161
|
+
}
|
|
162
|
+
async function selectByRole(page, role, name, value, nth, inRole, inText) {
|
|
163
|
+
let loc = page.getByRole(role, { name, exact: true });
|
|
164
|
+
if (inRole !== void 0 && inText !== void 0) {
|
|
165
|
+
const cr = { list: "listitem" }[inRole] || inRole;
|
|
166
|
+
loc = page.getByRole(cr).filter({ hasText: inText }).getByRole(role, { name, exact: true });
|
|
167
|
+
}
|
|
168
|
+
if (nth !== void 0) loc = loc.nth(nth);
|
|
169
|
+
await loc.selectOption(value);
|
|
170
|
+
}
|
|
171
|
+
async function highlightByText(page, text, nth, exact) {
|
|
172
|
+
let loc = exact ? page.getByText(text, { exact: true }) : page.getByText(text);
|
|
173
|
+
const count = await loc.count();
|
|
174
|
+
if (nth !== void 0) loc = loc.filter({ visible: true }).nth(nth);
|
|
175
|
+
await loc.highlight();
|
|
176
|
+
return nth !== void 0 ? "Highlighted 1 of " + count : "Highlighted " + count + " element" + (count !== 1 ? "s" : "");
|
|
177
|
+
}
|
|
178
|
+
async function highlightByRole(page, role, name, nth) {
|
|
179
|
+
let loc = page.getByRole(role, { name, exact: true });
|
|
180
|
+
const count = await loc.count();
|
|
181
|
+
if (nth !== void 0) loc = loc.nth(nth);
|
|
182
|
+
await loc.highlight();
|
|
183
|
+
return nth !== void 0 ? "Highlighted 1 of " + count : "Highlighted " + count + " element" + (count !== 1 ? "s" : "");
|
|
184
|
+
}
|
|
185
|
+
async function highlightBySelector(page, selector, nth) {
|
|
186
|
+
let loc = page.locator(selector);
|
|
187
|
+
const count = await loc.count();
|
|
188
|
+
if (nth !== void 0) loc = loc.filter({ visible: true }).nth(nth);
|
|
189
|
+
await loc.highlight();
|
|
190
|
+
return nth !== void 0 ? "Highlighted 1 of " + count : "Highlighted " + count + " element" + (count !== 1 ? "s" : "");
|
|
191
|
+
}
|
|
192
|
+
async function highlightByRef(page, ref) {
|
|
193
|
+
const loc = page.locator("aria-ref=" + ref);
|
|
194
|
+
await loc.highlight();
|
|
195
|
+
return "Highlighted";
|
|
196
|
+
}
|
|
197
|
+
async function clearHighlight(page) {
|
|
198
|
+
await page.locator("#__pw_clear__").highlight().catch(() => {
|
|
199
|
+
});
|
|
200
|
+
return "Cleared";
|
|
201
|
+
}
|
|
202
|
+
async function chainAction(page, selector, action, value) {
|
|
203
|
+
const loc = page.locator(selector);
|
|
204
|
+
if (value !== void 0) await loc[action](value);
|
|
205
|
+
else await loc[action]();
|
|
206
|
+
return "Done";
|
|
207
|
+
}
|
|
208
|
+
async function goBack(page) {
|
|
209
|
+
await page.goBack();
|
|
210
|
+
return page.url();
|
|
211
|
+
}
|
|
212
|
+
async function goForward(page) {
|
|
213
|
+
await page.goForward();
|
|
214
|
+
return page.url();
|
|
215
|
+
}
|
|
216
|
+
async function gotoUrl(page, url) {
|
|
217
|
+
await page.goto(url);
|
|
218
|
+
return "Navigated to " + url;
|
|
219
|
+
}
|
|
220
|
+
async function reloadPage(page) {
|
|
221
|
+
await page.reload();
|
|
222
|
+
return "Reloaded";
|
|
223
|
+
}
|
|
224
|
+
async function waitMs(page, ms) {
|
|
225
|
+
await page.waitForTimeout(ms);
|
|
226
|
+
return "Waited " + ms + "ms";
|
|
227
|
+
}
|
|
228
|
+
async function getTitle(page) {
|
|
229
|
+
return await page.title();
|
|
230
|
+
}
|
|
231
|
+
async function getUrl(page) {
|
|
232
|
+
return page.url();
|
|
233
|
+
}
|
|
234
|
+
async function evalCode(page, code) {
|
|
235
|
+
const result = await page.evaluate(code);
|
|
236
|
+
return result !== void 0 ? JSON.stringify(result) : "undefined";
|
|
237
|
+
}
|
|
238
|
+
async function runCode(page, code) {
|
|
239
|
+
const AsyncFunction = runCode.constructor;
|
|
240
|
+
const trimmed = code.trim();
|
|
241
|
+
const isFnExpr = /^(async\s*)?\(|^(async\s+)?function\b/.test(trimmed);
|
|
242
|
+
const body = isFnExpr ? `return (${trimmed})(page)` : `return ${trimmed}`;
|
|
243
|
+
const fn = new AsyncFunction("page", body);
|
|
244
|
+
const result = await fn(page);
|
|
245
|
+
return result != null && typeof result !== "object" ? String(result) : "Done";
|
|
246
|
+
}
|
|
247
|
+
async function takeScreenshot(page, fullPage) {
|
|
248
|
+
const data = await page.screenshot({ type: "jpeg", fullPage: !!fullPage });
|
|
249
|
+
return { __image: data.toString("base64"), mimeType: "image/jpeg" };
|
|
250
|
+
}
|
|
251
|
+
async function takeSnapshot(page) {
|
|
252
|
+
if (typeof page.ariaSnapshot === "function") {
|
|
253
|
+
return await page.ariaSnapshot({ mode: "ai" });
|
|
254
|
+
}
|
|
255
|
+
if (typeof page._snapshotForAI === "function") {
|
|
256
|
+
const result = await page._snapshotForAI();
|
|
257
|
+
return result.full ?? String(result);
|
|
258
|
+
}
|
|
259
|
+
const title = await page.title();
|
|
260
|
+
const url = page.url();
|
|
261
|
+
return "Title: " + title + "\nURL: " + url;
|
|
262
|
+
}
|
|
263
|
+
async function refAction(page, ref, action, value) {
|
|
264
|
+
const loc = page.locator("aria-ref=" + ref);
|
|
265
|
+
if (await loc.count() === 0) throw new Error("Element " + ref + " not found. Run snapshot first.");
|
|
266
|
+
if (value !== void 0) await loc[action](value);
|
|
267
|
+
else await loc[action]();
|
|
268
|
+
return "Done";
|
|
269
|
+
}
|
|
270
|
+
async function pressKey(page, target, key) {
|
|
271
|
+
if (!target || target === key) {
|
|
272
|
+
await page.keyboard.press(target);
|
|
273
|
+
return "Pressed " + target;
|
|
274
|
+
}
|
|
275
|
+
const isRef = /^e\d+$/.test(target);
|
|
276
|
+
if (isRef) {
|
|
277
|
+
await page.locator("aria-ref=" + target).press(key);
|
|
278
|
+
return "Pressed " + key;
|
|
279
|
+
}
|
|
280
|
+
let loc = page.getByText(target, { exact: true });
|
|
281
|
+
if (await loc.count() === 0) loc = page.getByRole("textbox", { name: target });
|
|
282
|
+
if (await loc.count() === 0) loc = page.getByRole("combobox", { name: target });
|
|
283
|
+
if (await loc.count() === 0) loc = page.getByPlaceholder(target);
|
|
284
|
+
if (await loc.count() === 0) loc = page.getByText(target);
|
|
285
|
+
await loc.press(key);
|
|
286
|
+
return "Pressed " + key;
|
|
287
|
+
}
|
|
288
|
+
async function pressKeyByRole(page, role, name, key, nth, inRole, inText) {
|
|
289
|
+
let loc = page.getByRole(role, { name, exact: true });
|
|
290
|
+
if (inRole !== void 0 && inText !== void 0) {
|
|
291
|
+
const cr = { list: "listitem" }[inRole] || inRole;
|
|
292
|
+
loc = page.getByRole(cr).filter({ hasText: inText }).getByRole(role, { name, exact: true });
|
|
293
|
+
}
|
|
294
|
+
if (nth !== void 0) loc = loc.nth(nth);
|
|
295
|
+
await loc.press(key);
|
|
296
|
+
return "Pressed " + key;
|
|
297
|
+
}
|
|
298
|
+
async function typeText(page, text) {
|
|
299
|
+
await page.keyboard.type(text);
|
|
300
|
+
return "Typed";
|
|
301
|
+
}
|
|
302
|
+
async function localStorageGet(page, key) {
|
|
303
|
+
return await page.evaluate((k) => localStorage.getItem(k), key);
|
|
304
|
+
}
|
|
305
|
+
async function localStorageSet(page, key, value) {
|
|
306
|
+
await page.evaluate(([k, v]) => localStorage.setItem(k, v), [key, value]);
|
|
307
|
+
return "Set";
|
|
308
|
+
}
|
|
309
|
+
async function localStorageDelete(page, key) {
|
|
310
|
+
await page.evaluate((k) => localStorage.removeItem(k), key);
|
|
311
|
+
return "Deleted";
|
|
312
|
+
}
|
|
313
|
+
async function localStorageClear(page) {
|
|
314
|
+
await page.evaluate(() => localStorage.clear());
|
|
315
|
+
return "Cleared";
|
|
316
|
+
}
|
|
317
|
+
async function localStorageList(page) {
|
|
318
|
+
const items = await page.evaluate(() => {
|
|
319
|
+
const result = {};
|
|
320
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
321
|
+
const k = localStorage.key(i);
|
|
322
|
+
result[k] = localStorage.getItem(k);
|
|
323
|
+
}
|
|
324
|
+
return result;
|
|
325
|
+
});
|
|
326
|
+
return JSON.stringify(items, null, 2);
|
|
327
|
+
}
|
|
328
|
+
async function sessionStorageGet(page, key) {
|
|
329
|
+
return await page.evaluate((k) => sessionStorage.getItem(k), key);
|
|
330
|
+
}
|
|
331
|
+
async function sessionStorageSet(page, key, value) {
|
|
332
|
+
await page.evaluate(([k, v]) => sessionStorage.setItem(k, v), [key, value]);
|
|
333
|
+
return "Set";
|
|
334
|
+
}
|
|
335
|
+
async function sessionStorageDelete(page, key) {
|
|
336
|
+
await page.evaluate((k) => sessionStorage.removeItem(k), key);
|
|
337
|
+
return "Deleted";
|
|
338
|
+
}
|
|
339
|
+
async function sessionStorageClear(page) {
|
|
340
|
+
await page.evaluate(() => sessionStorage.clear());
|
|
341
|
+
return "Cleared";
|
|
342
|
+
}
|
|
343
|
+
async function sessionStorageList(page) {
|
|
344
|
+
const items = await page.evaluate(() => {
|
|
345
|
+
const result = {};
|
|
346
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
347
|
+
const k = sessionStorage.key(i);
|
|
348
|
+
result[k] = sessionStorage.getItem(k);
|
|
349
|
+
}
|
|
350
|
+
return result;
|
|
351
|
+
});
|
|
352
|
+
return JSON.stringify(items, null, 2);
|
|
353
|
+
}
|
|
354
|
+
async function cookieList(page) {
|
|
355
|
+
const cookies = await page.context().cookies();
|
|
356
|
+
return JSON.stringify(cookies, null, 2);
|
|
357
|
+
}
|
|
358
|
+
async function cookieGet(page, name) {
|
|
359
|
+
const cookies = await page.context().cookies();
|
|
360
|
+
const c = cookies.find((c2) => c2.name === name);
|
|
361
|
+
return c ? JSON.stringify(c, null, 2) : "Cookie not found: " + name;
|
|
362
|
+
}
|
|
363
|
+
async function cookieSet(page, name, value) {
|
|
364
|
+
const url = page.url();
|
|
365
|
+
await page.context().addCookies([{ name, value, url }]);
|
|
366
|
+
return "Cookie set: " + name;
|
|
367
|
+
}
|
|
368
|
+
async function cookieDelete(page, name) {
|
|
369
|
+
await page.context().clearCookies({ name });
|
|
370
|
+
return "Cookie deleted: " + name;
|
|
371
|
+
}
|
|
372
|
+
async function cookieClear(page) {
|
|
373
|
+
await page.context().clearCookies();
|
|
374
|
+
return "Cleared";
|
|
375
|
+
}
|
|
376
|
+
async function dragDrop(page, source, target) {
|
|
377
|
+
const srcLoc = /^e\d+$/.test(source) ? page.locator("aria-ref=" + source) : page.getByText(source);
|
|
378
|
+
const tgtLoc = /^e\d+$/.test(target) ? page.locator("aria-ref=" + target) : page.getByText(target);
|
|
379
|
+
await srcLoc.dragTo(tgtLoc);
|
|
380
|
+
return "Dragged";
|
|
381
|
+
}
|
|
382
|
+
async function resizeViewport(page, width, height) {
|
|
383
|
+
await page.setViewportSize({ width: parseInt(width), height: parseInt(height) });
|
|
384
|
+
return "Resized to " + width + "x" + height;
|
|
385
|
+
}
|
|
386
|
+
async function takePdf(page) {
|
|
387
|
+
const data = await page.pdf();
|
|
388
|
+
return { __image: data.toString("base64"), mimeType: "application/pdf" };
|
|
389
|
+
}
|
|
390
|
+
async function getConsoleMessages(_page, clear) {
|
|
391
|
+
if (clear) {
|
|
392
|
+
globalThis.__consoleMessages = [];
|
|
393
|
+
return "Console cleared";
|
|
394
|
+
}
|
|
395
|
+
const msgs = globalThis.__consoleMessages || [];
|
|
396
|
+
return msgs.length === 0 ? "No console messages (listening...)" : msgs.join("\n");
|
|
397
|
+
}
|
|
398
|
+
async function getNetworkRequests(_page, clear, includeStatic) {
|
|
399
|
+
if (clear) {
|
|
400
|
+
globalThis.__networkRequests = [];
|
|
401
|
+
return "Network log cleared";
|
|
402
|
+
}
|
|
403
|
+
let reqs = globalThis.__networkRequests || [];
|
|
404
|
+
if (!includeStatic) {
|
|
405
|
+
const skip = /* @__PURE__ */ new Set(["stylesheet", "image", "font", "media", "other"]);
|
|
406
|
+
reqs = reqs.filter((r) => !skip.has(r.type));
|
|
407
|
+
}
|
|
408
|
+
return reqs.length === 0 ? "No network requests (listening...)" : reqs.map((r) => r.status + " " + r.method + " " + r.url).join("\n");
|
|
409
|
+
}
|
|
410
|
+
async function setDialogAccept(_page) {
|
|
411
|
+
globalThis.__dialogMode = "accept";
|
|
412
|
+
return "Dialogs will be auto-accepted";
|
|
413
|
+
}
|
|
414
|
+
async function setDialogDismiss(_page) {
|
|
415
|
+
globalThis.__dialogMode = "dismiss";
|
|
416
|
+
return "Dialogs will be auto-dismissed";
|
|
417
|
+
}
|
|
418
|
+
async function addRoute(page, pattern) {
|
|
419
|
+
if (!globalThis.__activeRoutes) globalThis.__activeRoutes = [];
|
|
420
|
+
const handler = (route) => route.abort();
|
|
421
|
+
await page.route(pattern, handler);
|
|
422
|
+
globalThis.__activeRoutes.push({ pattern, handler });
|
|
423
|
+
return "Route added (blocked): " + pattern;
|
|
424
|
+
}
|
|
425
|
+
async function listRoutes(_page) {
|
|
426
|
+
const routes = globalThis.__activeRoutes || [];
|
|
427
|
+
return routes.length === 0 ? "No active routes" : routes.map((r) => r.pattern).join("\n");
|
|
428
|
+
}
|
|
429
|
+
async function removeRoute(page, pattern) {
|
|
430
|
+
if (!globalThis.__activeRoutes || globalThis.__activeRoutes.length === 0)
|
|
431
|
+
return "No routes to remove";
|
|
432
|
+
const idx = globalThis.__activeRoutes.findIndex((r) => r.pattern === pattern);
|
|
433
|
+
if (idx === -1) return "Route not found: " + pattern;
|
|
434
|
+
await page.unroute(pattern, globalThis.__activeRoutes[idx].handler);
|
|
435
|
+
globalThis.__activeRoutes.splice(idx, 1);
|
|
436
|
+
return "Route removed: " + pattern;
|
|
437
|
+
}
|
|
438
|
+
async function tabList(_page) {
|
|
439
|
+
const activeTabId = globalThis.activeTabId;
|
|
440
|
+
const windowId = activeTabId ? (await chrome.tabs.get(activeTabId)).windowId : void 0;
|
|
441
|
+
const tabs = await chrome.tabs.query(windowId !== void 0 ? { windowId } : {});
|
|
442
|
+
return JSON.stringify(tabs.map((tab, i) => ({
|
|
443
|
+
index: i,
|
|
444
|
+
title: tab.title || "",
|
|
445
|
+
url: tab.url || "",
|
|
446
|
+
current: tab.id === activeTabId
|
|
447
|
+
})), null, 2);
|
|
448
|
+
}
|
|
449
|
+
async function tabNew(_page, url) {
|
|
450
|
+
const tabUrl = url || "about:blank";
|
|
451
|
+
const activeTabId = globalThis.activeTabId;
|
|
452
|
+
const windowId = activeTabId ? (await chrome.tabs.get(activeTabId)).windowId : void 0;
|
|
453
|
+
await chrome.tabs.create(windowId !== void 0 ? { url: tabUrl, windowId } : { url: tabUrl });
|
|
454
|
+
return "Opened new tab" + (url ? ": " + url : "");
|
|
455
|
+
}
|
|
456
|
+
async function tabClose(_page, index) {
|
|
457
|
+
const activeTabId = globalThis.activeTabId;
|
|
458
|
+
const windowId = activeTabId ? (await chrome.tabs.get(activeTabId)).windowId : void 0;
|
|
459
|
+
const tabs = await chrome.tabs.query(windowId !== void 0 ? { windowId } : {});
|
|
460
|
+
const tab = index !== void 0 ? tabs[index] : tabs.find((t) => t.id === activeTabId);
|
|
461
|
+
if (!tab?.id) throw new Error("Tab " + (index !== void 0 ? index : "current") + " not found");
|
|
462
|
+
const url = tab.url || "";
|
|
463
|
+
await chrome.tabs.remove(tab.id);
|
|
464
|
+
return "Closed: " + url;
|
|
465
|
+
}
|
|
466
|
+
async function tabSelect(_page, index) {
|
|
467
|
+
const activeTabId = globalThis.activeTabId;
|
|
468
|
+
const windowId = activeTabId ? (await chrome.tabs.get(activeTabId)).windowId : void 0;
|
|
469
|
+
const tabs = await chrome.tabs.query(windowId !== void 0 ? { windowId } : {});
|
|
470
|
+
const tab = tabs[index];
|
|
471
|
+
if (!tab?.id) throw new Error("Tab " + index + " not found");
|
|
472
|
+
const res = await globalThis.attachToTab(tab.id);
|
|
473
|
+
if (!res.ok) throw new Error(res.error || "Attach failed");
|
|
474
|
+
return "Selected tab " + index + ": " + (res.url || "");
|
|
475
|
+
}
|
|
476
|
+
const COMMANDS = {
|
|
477
|
+
"check": { desc: "Check a checkbox", usage: "check <text> | check <ref>" },
|
|
478
|
+
"clear": { desc: "Clear the console" },
|
|
479
|
+
"click": {
|
|
480
|
+
desc: "Click an element",
|
|
481
|
+
usage: "click <text> | click <ref>",
|
|
482
|
+
examples: ['click "Submit"', "click e5", 'click "Submit" --button right']
|
|
483
|
+
},
|
|
484
|
+
"cookie-clear": { desc: "Clear cookies" },
|
|
485
|
+
"cookie-delete": { desc: "Delete cookie", usage: "cookie-delete <name>" },
|
|
486
|
+
"cookie-get": { desc: "Get cookie", usage: "cookie-get <name>" },
|
|
487
|
+
"cookie-list": { desc: "List cookies" },
|
|
488
|
+
"console": { desc: "Show console messages", usage: "console [--clear]" },
|
|
489
|
+
"cookie-set": { desc: "Set cookie", usage: "cookie-set <name> <value>" },
|
|
490
|
+
"dblclick": { desc: "Double-click", usage: "dblclick <text> | dblclick <ref>" },
|
|
491
|
+
"dialog-accept": { desc: "Auto-accept dialogs" },
|
|
492
|
+
"dialog-dismiss": { desc: "Auto-dismiss dialogs" },
|
|
493
|
+
"drag": { desc: "Drag and drop", usage: "drag <source> <target>" },
|
|
494
|
+
"eval": {
|
|
495
|
+
desc: "Evaluate JavaScript",
|
|
496
|
+
usage: "eval <expression>",
|
|
497
|
+
examples: ["eval document.title"]
|
|
498
|
+
},
|
|
499
|
+
"export": { desc: "Export as Playwright test" },
|
|
500
|
+
"fill": {
|
|
501
|
+
desc: "Fill a form field",
|
|
502
|
+
usage: "fill <text|ref> <value>",
|
|
503
|
+
examples: ['fill "Email" "user@test.com"', 'fill e3 "hello"']
|
|
504
|
+
},
|
|
505
|
+
"go-back": { desc: "Go back" },
|
|
506
|
+
"go-forward": { desc: "Go forward" },
|
|
507
|
+
"goto": {
|
|
508
|
+
desc: "Navigate to a URL",
|
|
509
|
+
usage: "goto <url>",
|
|
510
|
+
examples: ["goto https://example.com"]
|
|
511
|
+
},
|
|
512
|
+
"help": {
|
|
513
|
+
desc: "Show available commands",
|
|
514
|
+
usage: "help [command]",
|
|
515
|
+
examples: ["help", "help click"]
|
|
516
|
+
},
|
|
517
|
+
"highlight": {
|
|
518
|
+
desc: "Highlight element on page",
|
|
519
|
+
usage: "highlight <text|selector>",
|
|
520
|
+
examples: ['highlight "Submit"', "highlight .btn-primary"]
|
|
521
|
+
},
|
|
522
|
+
"history": { desc: "Show command history" },
|
|
523
|
+
"history clear": { desc: "Clear command history" },
|
|
524
|
+
"hover": { desc: "Hover over element", usage: "hover <text> | hover <ref>" },
|
|
525
|
+
"locator": {
|
|
526
|
+
desc: "Generate Playwright locator for a ref",
|
|
527
|
+
usage: "locator <ref>",
|
|
528
|
+
examples: ["locator e5"]
|
|
529
|
+
},
|
|
530
|
+
"localstorage-clear": { desc: "Clear localStorage" },
|
|
531
|
+
"localstorage-delete": { desc: "Delete localStorage", usage: "localstorage-delete <key>" },
|
|
532
|
+
"localstorage-get": { desc: "Get localStorage", usage: "localstorage-get <key>" },
|
|
533
|
+
"localstorage-list": { desc: "List localStorage" },
|
|
534
|
+
"localstorage-set": { desc: "Set localStorage", usage: "localstorage-set <key> <value>" },
|
|
535
|
+
"network": { desc: "Show network requests", usage: "network [--clear] [--includeStatic]" },
|
|
536
|
+
"open": { desc: "Open the browser" },
|
|
537
|
+
"pdf": { desc: "Save page as PDF", usage: "pdf" },
|
|
538
|
+
"press": {
|
|
539
|
+
desc: "Press a keyboard key",
|
|
540
|
+
usage: "press <key> | press <ref> <key>",
|
|
541
|
+
examples: ["press Enter", "press e5 Tab"]
|
|
542
|
+
},
|
|
543
|
+
"reload": { desc: "Reload page" },
|
|
544
|
+
"resize": { desc: "Resize viewport", usage: "resize <width> <height>" },
|
|
545
|
+
"route": { desc: "Block requests by pattern", usage: "route <pattern>" },
|
|
546
|
+
"route-list": { desc: "List active routes" },
|
|
547
|
+
"run-code": { desc: "Run Playwright code", usage: "run-code <code>" },
|
|
548
|
+
"screenshot": { desc: "Take a screenshot", usage: "screenshot [--filename <file>] [--fullPage]" },
|
|
549
|
+
"select": {
|
|
550
|
+
desc: "Select dropdown option",
|
|
551
|
+
usage: "select <text|ref> <value>",
|
|
552
|
+
examples: ['select "Country" "US"']
|
|
553
|
+
},
|
|
554
|
+
"sessionstorage-clear": { desc: "Clear sessionStorage" },
|
|
555
|
+
"sessionstorage-delete": { desc: "Delete sessionStorage", usage: "sessionstorage-delete <key>" },
|
|
556
|
+
"sessionstorage-get": { desc: "Get sessionStorage", usage: "sessionstorage-get <key>" },
|
|
557
|
+
"sessionstorage-list": { desc: "List sessionStorage" },
|
|
558
|
+
"sessionstorage-set": { desc: "Set sessionStorage", usage: "sessionstorage-set <key> <value>" },
|
|
559
|
+
"snapshot": { desc: "Accessibility snapshot", usage: "snapshot [--filename <file>]" },
|
|
560
|
+
"tab-close": { desc: "Close tab", usage: "tab-close [index]" },
|
|
561
|
+
"tab-list": { desc: "List tabs" },
|
|
562
|
+
"tab-new": { desc: "New tab", usage: "tab-new [url]" },
|
|
563
|
+
"tab-select": { desc: "Select tab", usage: "tab-select <index>" },
|
|
564
|
+
"type": {
|
|
565
|
+
desc: "Type text key by key",
|
|
566
|
+
usage: "type <text>",
|
|
567
|
+
examples: ['type "hello world"']
|
|
568
|
+
},
|
|
569
|
+
"uncheck": { desc: "Uncheck a checkbox", usage: "uncheck <text> | uncheck <ref>" },
|
|
570
|
+
"unroute": { desc: "Remove a route", usage: "unroute <pattern>" },
|
|
571
|
+
"verify": {
|
|
572
|
+
desc: "Assert page state",
|
|
573
|
+
usage: "verify <type> <args>",
|
|
574
|
+
examples: ['verify title "My Page"', 'verify text "Hello"', 'verify element button "Submit"']
|
|
575
|
+
},
|
|
576
|
+
"verify-element": { desc: "Verify element exists by role", usage: "verify-element <role> <name>" },
|
|
577
|
+
"verify-no-element": { desc: "Verify element not exists", usage: "verify-no-element <role> <name>" },
|
|
578
|
+
"verify-no-text": { desc: "Verify text not visible", usage: "verify-no-text <text>" },
|
|
579
|
+
"verify-text": { desc: "Verify text visible", usage: "verify-text <text>" },
|
|
580
|
+
"verify-title": { desc: "Verify page title", usage: "verify-title <text>" },
|
|
581
|
+
"verify-url": { desc: "Verify page URL", usage: "verify-url <text>" },
|
|
582
|
+
"verify-value": { desc: "Verify input / checkbox / radio value", usage: "verify-value <ref|text> <value>" },
|
|
583
|
+
"verify-visible": { desc: "Verify element is visible by role", usage: "verify-visible <role> <name>" },
|
|
584
|
+
"tracing-start": { desc: "Start performance trace recording", usage: "tracing-start" },
|
|
585
|
+
"tracing-stop": { desc: "Stop tracing and save trace file", usage: "tracing-stop" },
|
|
586
|
+
"video-start": { desc: "Start recording the active tab", usage: "video-start" },
|
|
587
|
+
"video-stop": { desc: "Stop recording and save video", usage: "video-stop" },
|
|
588
|
+
"wait-for-text": {
|
|
589
|
+
desc: "Wait until text appears",
|
|
590
|
+
usage: "wait-for-text <text>",
|
|
591
|
+
examples: ['wait-for-text "Loading complete"']
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
const COMMAND_NAMES = Object.keys(COMMANDS);
|
|
595
|
+
const CATEGORIES = {
|
|
596
|
+
"Navigation": ["goto", "open", "go-back", "go-forward", "reload"],
|
|
597
|
+
"Interaction": ["click", "dblclick", "fill", "type", "press", "hover", "select", "check", "uncheck", "drag"],
|
|
598
|
+
"Verification": ["verify", "verify-text", "verify-no-text", "verify-title", "verify-url", "verify-element", "verify-no-element", "verify-value", "verify-visible", "wait-for-text"],
|
|
599
|
+
"Inspection": ["snapshot", "locator", "screenshot", "pdf", "video-start", "video-stop", "tracing-start", "tracing-stop", "eval", "run-code", "console", "network"],
|
|
600
|
+
"Tabs": ["tab-list", "tab-new", "tab-close", "tab-select"],
|
|
601
|
+
"Cookies": ["cookie-list", "cookie-get", "cookie-set", "cookie-delete", "cookie-clear"],
|
|
602
|
+
"LocalStorage": ["localstorage-list", "localstorage-get", "localstorage-set", "localstorage-delete", "localstorage-clear"],
|
|
603
|
+
"SessionStorage": ["sessionstorage-list", "sessionstorage-get", "sessionstorage-set", "sessionstorage-delete", "sessionstorage-clear"],
|
|
604
|
+
"Other": ["highlight", "export", "resize", "dialog-accept", "dialog-dismiss", "route", "route-list", "unroute"]
|
|
605
|
+
};
|
|
606
|
+
const JS_CATEGORIES = {
|
|
607
|
+
"Navigation": ["page.goto(url)", "page.goBack()", "page.reload()", "..."],
|
|
608
|
+
"Locators": ["page.getByRole(role)", "page.getByText(text)", "page.locator(sel)", "page.getByTestId(id)", "..."],
|
|
609
|
+
"Actions": [".click()", ".fill(value)", ".press(key)", ".hover()", ".selectOption(value)", "..."],
|
|
610
|
+
"Query": [".textContent()", ".getAttribute(name)", ".isVisible()", ".count()", "..."],
|
|
611
|
+
"Assertions": ["expect(loc).toBeVisible()", ".toHaveText()", ".toHaveValue()", "expect(page).toHaveTitle()", ".toHaveURL()", "..."],
|
|
612
|
+
"Wait": ["page.waitForSelector(sel)", "page.waitForLoadState()", "page.waitForURL(url)"],
|
|
613
|
+
"Evaluate": ["page.evaluate(() => expr)"],
|
|
614
|
+
"Other": ["page.screenshot()", "page.keyboard.press(key)", "page.mouse.click(x, y)", "..."]
|
|
615
|
+
};
|
|
616
|
+
function isDirect(result) {
|
|
617
|
+
return "jsExpr" in result;
|
|
618
|
+
}
|
|
619
|
+
function ser(v) {
|
|
620
|
+
if (v === void 0) return "undefined";
|
|
621
|
+
return JSON.stringify(v);
|
|
622
|
+
}
|
|
623
|
+
function call(fn, ...args) {
|
|
624
|
+
return `await (${fn.toString()})(page, ${args.map(ser).join(", ")})`;
|
|
625
|
+
}
|
|
626
|
+
const BOOLEAN_OPTIONS = /* @__PURE__ */ new Set([
|
|
627
|
+
"headed",
|
|
628
|
+
"persistent",
|
|
629
|
+
"extension",
|
|
630
|
+
"submit",
|
|
631
|
+
"clear",
|
|
632
|
+
"fullPage",
|
|
633
|
+
"includeStatic",
|
|
634
|
+
"exact"
|
|
635
|
+
]);
|
|
636
|
+
function tokenize(line) {
|
|
637
|
+
const tokens = [];
|
|
638
|
+
let current = "";
|
|
639
|
+
let inQuote = null;
|
|
640
|
+
for (let i = 0; i < line.length; i++) {
|
|
641
|
+
const ch = line[i];
|
|
642
|
+
if (inQuote) {
|
|
643
|
+
if (ch === inQuote) {
|
|
644
|
+
inQuote = null;
|
|
645
|
+
} else {
|
|
646
|
+
current += ch;
|
|
647
|
+
}
|
|
648
|
+
} else if (ch === '"' || ch === "'") {
|
|
649
|
+
inQuote = ch;
|
|
650
|
+
} else if (ch === " " || ch === " ") {
|
|
651
|
+
if (current) {
|
|
652
|
+
tokens.push(current);
|
|
653
|
+
current = "";
|
|
654
|
+
}
|
|
655
|
+
} else {
|
|
656
|
+
current += ch;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (current) tokens.push(current);
|
|
660
|
+
return tokens;
|
|
661
|
+
}
|
|
662
|
+
const RAW_COMMANDS = /* @__PURE__ */ new Set(["run-code", "eval"]);
|
|
663
|
+
function parseInput(line) {
|
|
664
|
+
const tokens = tokenize(line);
|
|
665
|
+
if (tokens.length === 0) return null;
|
|
666
|
+
tokens[0] = tokens[0].toLowerCase();
|
|
667
|
+
if (RAW_COMMANDS.has(tokens[0])) {
|
|
668
|
+
const cmdLen = line.match(/^\s*\S+/)[0].length;
|
|
669
|
+
const rest = line.slice(cmdLen).trim();
|
|
670
|
+
return rest ? { _: [tokens[0], rest] } : { _: [tokens[0]] };
|
|
671
|
+
}
|
|
672
|
+
const positional = [];
|
|
673
|
+
const opts = {};
|
|
674
|
+
let i = 0;
|
|
675
|
+
while (i < tokens.length) {
|
|
676
|
+
if (tokens[i].startsWith("--")) {
|
|
677
|
+
const key = tokens[i].slice(2);
|
|
678
|
+
if (BOOLEAN_OPTIONS.has(key)) {
|
|
679
|
+
opts[key] = true;
|
|
680
|
+
i++;
|
|
681
|
+
} else if (key === "in" && i + 2 < tokens.length && !tokens[i + 1].startsWith("--") && !tokens[i + 2].startsWith("--")) {
|
|
682
|
+
opts["in-role"] = tokens[i + 1];
|
|
683
|
+
opts["in-text"] = tokens[i + 2];
|
|
684
|
+
i += 3;
|
|
685
|
+
} else if (i + 1 < tokens.length && !tokens[i + 1].startsWith("--")) {
|
|
686
|
+
opts[key] = tokens[i + 1];
|
|
687
|
+
i += 2;
|
|
688
|
+
} else {
|
|
689
|
+
opts[key] = true;
|
|
690
|
+
i++;
|
|
691
|
+
}
|
|
692
|
+
} else {
|
|
693
|
+
positional.push(tokens[i]);
|
|
694
|
+
i++;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
return { _: positional, ...opts };
|
|
698
|
+
}
|
|
699
|
+
function resolveArgs(args) {
|
|
700
|
+
const cmdName = args._[0];
|
|
701
|
+
if (cmdName === "verify") {
|
|
702
|
+
const subType = args._[1];
|
|
703
|
+
const rest = args._.slice(2);
|
|
704
|
+
if (subType === "title" && rest.length > 0)
|
|
705
|
+
return { jsExpr: call(verifyTitle, rest.join(" ")) };
|
|
706
|
+
if (subType === "url" && rest.length > 0)
|
|
707
|
+
return { jsExpr: call(verifyUrl, rest.join(" ")) };
|
|
708
|
+
if (subType === "text" && rest.length > 0)
|
|
709
|
+
return { jsExpr: call(verifyText, rest.join(" ")) };
|
|
710
|
+
if (subType === "no-text" && rest.length > 0)
|
|
711
|
+
return { jsExpr: call(verifyNoText, rest.join(" ")) };
|
|
712
|
+
if (subType === "element" && rest.length >= 2)
|
|
713
|
+
return { jsExpr: call(verifyElement, rest[0], rest.slice(1).join(" ")) };
|
|
714
|
+
if (subType === "no-element" && rest.length >= 2)
|
|
715
|
+
return { jsExpr: call(verifyNoElement, rest[0], rest.slice(1).join(" ")) };
|
|
716
|
+
if (subType === "value" && rest.length >= 2)
|
|
717
|
+
return { jsExpr: call(verifyValue, rest[0], rest.slice(1).join(" ")) };
|
|
718
|
+
if (subType === "list" && rest.length >= 2)
|
|
719
|
+
return { jsExpr: call(verifyList, rest[0], rest.slice(1)) };
|
|
720
|
+
}
|
|
721
|
+
const TEXT_VERIFY_CMDS = /* @__PURE__ */ new Set(["verify-text", "verify-no-text", "verify-title", "verify-url"]);
|
|
722
|
+
const ELEMENT_VERIFY_CMDS = /* @__PURE__ */ new Set(["verify-element", "verify-no-element", "verify-visible"]);
|
|
723
|
+
const verifyFns = {
|
|
724
|
+
"verify-text": verifyText,
|
|
725
|
+
"verify-element": verifyElement,
|
|
726
|
+
"verify-visible": verifyVisible,
|
|
727
|
+
"verify-value": verifyValue,
|
|
728
|
+
"verify-list": verifyList,
|
|
729
|
+
"verify-title": verifyTitle,
|
|
730
|
+
"verify-url": verifyUrl,
|
|
731
|
+
"verify-no-text": verifyNoText,
|
|
732
|
+
"verify-no-element": verifyNoElement
|
|
733
|
+
};
|
|
734
|
+
if (verifyFns[cmdName]) {
|
|
735
|
+
const pos = args._.slice(1);
|
|
736
|
+
const fn = verifyFns[cmdName];
|
|
737
|
+
if (TEXT_VERIFY_CMDS.has(cmdName)) {
|
|
738
|
+
const text = pos.join(" ");
|
|
739
|
+
if (text) return { jsExpr: call(fn, text) };
|
|
740
|
+
} else if (ELEMENT_VERIFY_CMDS.has(cmdName)) {
|
|
741
|
+
if (pos[0] && pos.length >= 2) return { jsExpr: call(fn, pos[0], pos.slice(1).join(" ")) };
|
|
742
|
+
} else if (cmdName === "verify-value" && pos[0] && pos.length >= 2) {
|
|
743
|
+
const isRef = /^e\d+$/.test(pos[0]);
|
|
744
|
+
const valueFn = isRef ? verifyValue : verifyInputValue;
|
|
745
|
+
return { jsExpr: call(valueFn, pos[0], pos.slice(1).join(" ")) };
|
|
746
|
+
} else if (pos[0] && pos.length >= 2) {
|
|
747
|
+
const rest = cmdName === "verify-list" ? pos.slice(1) : pos.slice(1).join(" ");
|
|
748
|
+
return { jsExpr: call(fn, pos[0], rest) };
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
if (cmdName === "wait-for-text") {
|
|
752
|
+
const text = args._.slice(1).join(" ");
|
|
753
|
+
if (text) return { jsExpr: call(waitForText, text) };
|
|
754
|
+
}
|
|
755
|
+
if (cmdName === "goto" || cmdName === "open") {
|
|
756
|
+
const url = args._[1];
|
|
757
|
+
if (!url) return args;
|
|
758
|
+
return { jsExpr: call(gotoUrl, url) };
|
|
759
|
+
}
|
|
760
|
+
if (cmdName === "reload")
|
|
761
|
+
return { jsExpr: call(reloadPage) };
|
|
762
|
+
if (cmdName === "go-back")
|
|
763
|
+
return { jsExpr: call(goBack) };
|
|
764
|
+
if (cmdName === "go-forward")
|
|
765
|
+
return { jsExpr: call(goForward) };
|
|
766
|
+
if (cmdName === "title")
|
|
767
|
+
return { jsExpr: call(getTitle) };
|
|
768
|
+
if (cmdName === "url")
|
|
769
|
+
return { jsExpr: call(getUrl) };
|
|
770
|
+
if (cmdName === "wait") {
|
|
771
|
+
const ms = parseInt(args._[1]) || 1e3;
|
|
772
|
+
return { jsExpr: call(waitMs, ms) };
|
|
773
|
+
}
|
|
774
|
+
if (cmdName === "eval") {
|
|
775
|
+
const code = args._[1] || "";
|
|
776
|
+
return { jsExpr: call(evalCode, code) };
|
|
777
|
+
}
|
|
778
|
+
if (cmdName === "run-code") {
|
|
779
|
+
const code = args._[1] || "";
|
|
780
|
+
return { jsExpr: call(runCode, code) };
|
|
781
|
+
}
|
|
782
|
+
if (cmdName === "screenshot")
|
|
783
|
+
return { jsExpr: `JSON.stringify(await (${takeScreenshot.toString()})(page, ${!!args.fullPage}))` };
|
|
784
|
+
if (cmdName === "pdf")
|
|
785
|
+
return { jsExpr: `JSON.stringify(await (${takePdf.toString()})(page))` };
|
|
786
|
+
if (cmdName === "snapshot")
|
|
787
|
+
return { jsExpr: call(takeSnapshot) };
|
|
788
|
+
if (cmdName === "highlight") {
|
|
789
|
+
if (args.clear) return { jsExpr: call(clearHighlight) };
|
|
790
|
+
const loc = args._[1];
|
|
791
|
+
if (loc) {
|
|
792
|
+
if (/^e\d+$/.test(loc)) return { jsExpr: call(highlightByRef, loc) };
|
|
793
|
+
const nth = args.nth !== void 0 ? parseInt(String(args.nth), 10) : void 0;
|
|
794
|
+
const exact = args.exact ? true : void 0;
|
|
795
|
+
const isSelector = /[.#[\]>:=]/.test(loc);
|
|
796
|
+
if (!isSelector && args._.length >= 3 && /^[a-z]+$/.test(loc)) {
|
|
797
|
+
const name = args._.slice(2).join(" ");
|
|
798
|
+
return { jsExpr: call(highlightByRole, loc, name, nth) };
|
|
799
|
+
}
|
|
800
|
+
return isSelector ? { jsExpr: call(highlightBySelector, loc, nth) } : { jsExpr: call(highlightByText, loc, nth, exact) };
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
const LOCATOR_ACTIONS = {
|
|
804
|
+
click: "click",
|
|
805
|
+
dblclick: "dblclick",
|
|
806
|
+
hover: "hover",
|
|
807
|
+
check: "check",
|
|
808
|
+
uncheck: "uncheck",
|
|
809
|
+
fill: "fill",
|
|
810
|
+
select: "selectOption"
|
|
811
|
+
};
|
|
812
|
+
if (LOCATOR_ACTIONS[cmdName] && args._.some((a) => a.includes(">>"))) {
|
|
813
|
+
const action = LOCATOR_ACTIONS[cmdName];
|
|
814
|
+
const positional = args._.slice(1);
|
|
815
|
+
let lastChainIdx = -1;
|
|
816
|
+
for (let i = 0; i < positional.length; i++) {
|
|
817
|
+
if (positional[i] === ">>" || positional[i].includes(">>")) lastChainIdx = i;
|
|
818
|
+
}
|
|
819
|
+
const selectorEnd = positional[lastChainIdx] !== ">>" && positional[lastChainIdx]?.includes(">>") ? lastChainIdx : lastChainIdx + 1;
|
|
820
|
+
const selector = positional.slice(0, selectorEnd + 1).join(" ");
|
|
821
|
+
const rest = positional.slice(selectorEnd + 1).join(" ");
|
|
822
|
+
return { jsExpr: call(chainAction, selector, action, rest || void 0) };
|
|
823
|
+
}
|
|
824
|
+
const ROLE_ACTIONS = {
|
|
825
|
+
click: "click",
|
|
826
|
+
dblclick: "dblclick",
|
|
827
|
+
hover: "hover",
|
|
828
|
+
check: "check",
|
|
829
|
+
uncheck: "uncheck"
|
|
830
|
+
};
|
|
831
|
+
if (args._.length >= 3 && args._[1] && /^[a-z]+$/.test(args._[1]) && !args._.some((a) => a.includes(">>"))) {
|
|
832
|
+
const role = args._[1];
|
|
833
|
+
const nth = args.nth !== void 0 ? parseInt(String(args.nth), 10) : void 0;
|
|
834
|
+
const inRole = args["in-role"] !== void 0 ? String(args["in-role"]) : void 0;
|
|
835
|
+
const inText = args["in-text"] !== void 0 ? String(args["in-text"]) : void 0;
|
|
836
|
+
if (ROLE_ACTIONS[cmdName]) {
|
|
837
|
+
const name = args._.slice(2).join(" ");
|
|
838
|
+
return { jsExpr: call(actionByRole, role, name, ROLE_ACTIONS[cmdName], nth, inRole, inText) };
|
|
839
|
+
}
|
|
840
|
+
if (cmdName === "fill") {
|
|
841
|
+
return { jsExpr: call(fillByRole, role, args._[2], args._.slice(3).join(" ") || "", nth, inRole, inText) };
|
|
842
|
+
}
|
|
843
|
+
if (cmdName === "select") {
|
|
844
|
+
return { jsExpr: call(selectByRole, role, args._[2], args._.slice(3).join(" ") || "", nth, inRole, inText) };
|
|
845
|
+
}
|
|
846
|
+
if (cmdName === "press") {
|
|
847
|
+
const key = args._.slice(3).join(" ") || "";
|
|
848
|
+
return { jsExpr: call(pressKeyByRole, role, args._[2], key, nth, inRole, inText) };
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
const textFns = {
|
|
852
|
+
click: actionByText,
|
|
853
|
+
dblclick: actionByText,
|
|
854
|
+
hover: actionByText,
|
|
855
|
+
fill: fillByText,
|
|
856
|
+
select: selectByText,
|
|
857
|
+
check: checkByText,
|
|
858
|
+
uncheck: uncheckByText
|
|
859
|
+
};
|
|
860
|
+
if (textFns[cmdName] && args._[1] && !/^e\d+$/.test(args._[1]) && !args._.some((a) => a.includes(">>"))) {
|
|
861
|
+
const textArg = args._[1];
|
|
862
|
+
const extraArgs = args._.slice(2);
|
|
863
|
+
const fn = textFns[cmdName];
|
|
864
|
+
const nth = args.nth !== void 0 ? parseInt(String(args.nth), 10) : void 0;
|
|
865
|
+
const exact = args.exact ? true : void 0;
|
|
866
|
+
if (fn === actionByText)
|
|
867
|
+
return { jsExpr: call(fn, textArg, cmdName, nth, exact) };
|
|
868
|
+
if (cmdName === "fill" || cmdName === "select")
|
|
869
|
+
return { jsExpr: call(fn, textArg, extraArgs[0] || "", nth, exact) };
|
|
870
|
+
return { jsExpr: call(fn, textArg, nth, exact) };
|
|
871
|
+
}
|
|
872
|
+
const REF_ACTIONS = {
|
|
873
|
+
click: "click",
|
|
874
|
+
dblclick: "dblclick",
|
|
875
|
+
hover: "hover",
|
|
876
|
+
check: "check",
|
|
877
|
+
uncheck: "uncheck",
|
|
878
|
+
fill: "fill",
|
|
879
|
+
select: "selectOption",
|
|
880
|
+
type: "fill"
|
|
881
|
+
};
|
|
882
|
+
if (REF_ACTIONS[cmdName] && args._[1] && /^e\d+$/.test(args._[1])) {
|
|
883
|
+
const ref = args._[1];
|
|
884
|
+
const action = REF_ACTIONS[cmdName];
|
|
885
|
+
const value = args._.slice(2).join(" ") || void 0;
|
|
886
|
+
return { jsExpr: call(refAction, ref, action, value) };
|
|
887
|
+
}
|
|
888
|
+
if (cmdName === "press") {
|
|
889
|
+
const pos = args._.slice(1);
|
|
890
|
+
if (pos.length === 1) {
|
|
891
|
+
return { jsExpr: call(pressKey, pos[0], pos[0]) };
|
|
892
|
+
}
|
|
893
|
+
if (pos.length >= 2) {
|
|
894
|
+
return { jsExpr: call(pressKey, pos[0], pos[1]) };
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
if (cmdName === "type") {
|
|
898
|
+
const text = args._.slice(1).join(" ");
|
|
899
|
+
if (text) return { jsExpr: call(typeText, text) };
|
|
900
|
+
}
|
|
901
|
+
if (cmdName === "localstorage-get")
|
|
902
|
+
return { jsExpr: call(localStorageGet, args._[1]) };
|
|
903
|
+
if (cmdName === "localstorage-set")
|
|
904
|
+
return { jsExpr: call(localStorageSet, args._[1], args._.slice(2).join(" ")) };
|
|
905
|
+
if (cmdName === "localstorage-delete")
|
|
906
|
+
return { jsExpr: call(localStorageDelete, args._[1]) };
|
|
907
|
+
if (cmdName === "localstorage-clear")
|
|
908
|
+
return { jsExpr: call(localStorageClear) };
|
|
909
|
+
if (cmdName === "localstorage-list")
|
|
910
|
+
return { jsExpr: call(localStorageList) };
|
|
911
|
+
if (cmdName === "sessionstorage-get")
|
|
912
|
+
return { jsExpr: call(sessionStorageGet, args._[1]) };
|
|
913
|
+
if (cmdName === "sessionstorage-set")
|
|
914
|
+
return { jsExpr: call(sessionStorageSet, args._[1], args._.slice(2).join(" ")) };
|
|
915
|
+
if (cmdName === "sessionstorage-delete")
|
|
916
|
+
return { jsExpr: call(sessionStorageDelete, args._[1]) };
|
|
917
|
+
if (cmdName === "sessionstorage-clear")
|
|
918
|
+
return { jsExpr: call(sessionStorageClear) };
|
|
919
|
+
if (cmdName === "sessionstorage-list")
|
|
920
|
+
return { jsExpr: call(sessionStorageList) };
|
|
921
|
+
if (cmdName === "cookie-list")
|
|
922
|
+
return { jsExpr: call(cookieList) };
|
|
923
|
+
if (cmdName === "cookie-get")
|
|
924
|
+
return { jsExpr: call(cookieGet, args._[1]) };
|
|
925
|
+
if (cmdName === "cookie-set")
|
|
926
|
+
return { jsExpr: call(cookieSet, args._[1], args._.slice(2).join(" ")) };
|
|
927
|
+
if (cmdName === "cookie-delete")
|
|
928
|
+
return { jsExpr: call(cookieDelete, args._[1]) };
|
|
929
|
+
if (cmdName === "cookie-clear")
|
|
930
|
+
return { jsExpr: call(cookieClear) };
|
|
931
|
+
if (cmdName === "tab-list")
|
|
932
|
+
return { jsExpr: call(tabList) };
|
|
933
|
+
if (cmdName === "tab-new")
|
|
934
|
+
return { jsExpr: call(tabNew, args._[1]) };
|
|
935
|
+
if (cmdName === "tab-close") {
|
|
936
|
+
const idx = args._[1] ? parseInt(args._[1]) : void 0;
|
|
937
|
+
return { jsExpr: call(tabClose, idx) };
|
|
938
|
+
}
|
|
939
|
+
if (cmdName === "tab-select") {
|
|
940
|
+
const idx = args._[1] ? parseInt(args._[1]) : NaN;
|
|
941
|
+
if (isNaN(idx)) return args;
|
|
942
|
+
return { jsExpr: call(tabSelect, idx) };
|
|
943
|
+
}
|
|
944
|
+
if (cmdName === "drag" && args._[1] && args._[2])
|
|
945
|
+
return { jsExpr: call(dragDrop, args._[1], args._[2]) };
|
|
946
|
+
if (cmdName === "resize" && args._[1] && args._[2])
|
|
947
|
+
return { jsExpr: call(resizeViewport, args._[1], args._[2]) };
|
|
948
|
+
if (cmdName === "console")
|
|
949
|
+
return { jsExpr: call(getConsoleMessages, args.clear) };
|
|
950
|
+
if (cmdName === "network")
|
|
951
|
+
return { jsExpr: call(getNetworkRequests, args.clear, args.includeStatic) };
|
|
952
|
+
if (cmdName === "dialog-accept")
|
|
953
|
+
return { jsExpr: call(setDialogAccept) };
|
|
954
|
+
if (cmdName === "dialog-dismiss")
|
|
955
|
+
return { jsExpr: call(setDialogDismiss) };
|
|
956
|
+
if (cmdName === "route" && args._[1])
|
|
957
|
+
return { jsExpr: call(addRoute, args._[1]) };
|
|
958
|
+
if (cmdName === "route-list")
|
|
959
|
+
return { jsExpr: call(listRoutes) };
|
|
960
|
+
if (cmdName === "unroute" && args._[1])
|
|
961
|
+
return { jsExpr: call(removeRoute, args._[1]) };
|
|
962
|
+
return args;
|
|
963
|
+
}
|
|
964
|
+
function parseReplCommand(input) {
|
|
965
|
+
const tokens = tokenize(input.trim());
|
|
966
|
+
if (tokens.length === 0) return { error: "Empty command" };
|
|
967
|
+
const trimmed = input.trim().toLowerCase();
|
|
968
|
+
if (trimmed === "help") {
|
|
969
|
+
const lines = Object.entries(CATEGORIES).map(([cat, cmds]) => ` ${cat}: ${cmds.join(", ")}`).join("\n");
|
|
970
|
+
return { help: `Available commands:
|
|
971
|
+
${lines}
|
|
972
|
+
|
|
973
|
+
Type "help <command>" for details.` };
|
|
974
|
+
}
|
|
975
|
+
if (trimmed.startsWith("help ")) {
|
|
976
|
+
const cmd = trimmed.slice(5).trim();
|
|
977
|
+
if (cmd === "js" || cmd === "javascript") {
|
|
978
|
+
const jsLines = Object.entries(JS_CATEGORIES).map(([cat, methods]) => ` ${cat}: ${methods.join(", ")}`).join("\n");
|
|
979
|
+
return { help: `JavaScript mode — Playwright API:
|
|
980
|
+
Prefix with await for async methods
|
|
981
|
+
|
|
982
|
+
${jsLines}` };
|
|
983
|
+
}
|
|
984
|
+
const info = COMMANDS[cmd];
|
|
985
|
+
if (!info) return { error: `Unknown command: "${cmd}". Type "help" for available commands.` };
|
|
986
|
+
const parts = [`${cmd} — ${info.desc}`];
|
|
987
|
+
if (info.usage) parts.push(`Usage: ${info.usage}`);
|
|
988
|
+
if (info.examples?.length) {
|
|
989
|
+
parts.push("Examples:");
|
|
990
|
+
for (const ex of info.examples) parts.push(` ${ex}`);
|
|
991
|
+
}
|
|
992
|
+
return { help: parts.join("\n") };
|
|
993
|
+
}
|
|
994
|
+
if (trimmed.startsWith("locator ")) {
|
|
995
|
+
const ref = trimmed.slice("locator ".length).trim();
|
|
996
|
+
if (!ref) return { error: "Usage: locator <ref>\nExample: locator e5" };
|
|
997
|
+
return { jsExpr: `(await page.locator(${ser("aria-ref=" + ref)}).normalize()).toString()` };
|
|
998
|
+
}
|
|
999
|
+
const args = parseInput(input);
|
|
1000
|
+
if (!args) return { error: "Empty command" };
|
|
1001
|
+
const resolved = resolveArgs(args);
|
|
1002
|
+
if (isDirect(resolved)) return resolved;
|
|
1003
|
+
const cmdName = args._[0];
|
|
1004
|
+
return { error: `Unknown command: "${cmdName}". Type "help" for commands.` };
|
|
1005
|
+
}
|
|
1006
|
+
const PW_COMMANDS = new Set(COMMAND_NAMES);
|
|
1007
|
+
function resolveConsoleMode(input) {
|
|
1008
|
+
if (input.includes("\n")) return "js";
|
|
1009
|
+
return detectMode(input);
|
|
1010
|
+
}
|
|
1011
|
+
const JS_KEYWORDS = /* @__PURE__ */ new Set(["await", "typeof", "delete", "void", "throw", "new", "yield", "async"]);
|
|
1012
|
+
function detectMode(input) {
|
|
1013
|
+
const firstToken = input.trim().split(/\s+/)[0];
|
|
1014
|
+
if (PW_COMMANDS.has(firstToken.toLowerCase())) return "pw";
|
|
1015
|
+
if (/^[a-z][-a-z]*$/.test(firstToken) && !JS_KEYWORDS.has(firstToken) && input.includes(" ") && !/[.()=;{}[\]+*/<>!&|^~?:`]/.test(input)) return "pw";
|
|
1016
|
+
return "js";
|
|
1017
|
+
}
|
|
1018
|
+
const execute = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1019
|
+
__proto__: null,
|
|
1020
|
+
detectMode,
|
|
1021
|
+
resolveConsoleMode
|
|
1022
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1023
|
+
let swTargetId = null;
|
|
1024
|
+
if (typeof chrome !== "undefined" && chrome.debugger) {
|
|
1025
|
+
chrome.debugger.onDetach.addListener((source) => {
|
|
1026
|
+
if (source.targetId === swTargetId) swTargetId = null;
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
function querySwTarget() {
|
|
1030
|
+
const swUrl = `chrome-extension://${chrome.runtime.id}/background.js`;
|
|
1031
|
+
return new Promise((resolve) => {
|
|
1032
|
+
chrome.debugger.getTargets((targets) => {
|
|
1033
|
+
const sw = targets.find((t) => t.type === "worker" && t.url === swUrl);
|
|
1034
|
+
resolve(sw?.id ?? null);
|
|
1035
|
+
});
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
async function findSwTarget() {
|
|
1039
|
+
await chrome.runtime.sendMessage({ type: "ping" }).catch(() => {
|
|
1040
|
+
});
|
|
1041
|
+
for (let i = 0; i < 10; i++) {
|
|
1042
|
+
const id = await querySwTarget();
|
|
1043
|
+
if (id) return id;
|
|
1044
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
1045
|
+
}
|
|
1046
|
+
return null;
|
|
1047
|
+
}
|
|
1048
|
+
async function ensureAttached() {
|
|
1049
|
+
if (swTargetId) return swTargetId;
|
|
1050
|
+
const targetId = await findSwTarget();
|
|
1051
|
+
if (!targetId) throw new Error("Background worker target not found. Try reloading the extension.");
|
|
1052
|
+
if (swTargetId === targetId) return targetId;
|
|
1053
|
+
await new Promise((resolve, reject) => {
|
|
1054
|
+
chrome.debugger.attach({ targetId }, "1.3", () => {
|
|
1055
|
+
if (chrome.runtime.lastError) {
|
|
1056
|
+
const msg = chrome.runtime.lastError.message ?? "";
|
|
1057
|
+
if (/already attached/i.test(msg)) {
|
|
1058
|
+
swTargetId = targetId;
|
|
1059
|
+
resolve();
|
|
1060
|
+
} else reject(new Error(msg));
|
|
1061
|
+
} else {
|
|
1062
|
+
chrome.debugger.sendCommand({ targetId }, "Runtime.enable", {}, () => {
|
|
1063
|
+
});
|
|
1064
|
+
swTargetId = targetId;
|
|
1065
|
+
resolve();
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
});
|
|
1069
|
+
return targetId;
|
|
1070
|
+
}
|
|
1071
|
+
function getTargetId() {
|
|
1072
|
+
return swTargetId;
|
|
1073
|
+
}
|
|
1074
|
+
async function cdpSendCommand(method, params = {}) {
|
|
1075
|
+
const targetId = await ensureAttached();
|
|
1076
|
+
return new Promise((resolve, reject) => {
|
|
1077
|
+
chrome.debugger.sendCommand({ targetId }, method, params, (result) => {
|
|
1078
|
+
if (chrome.runtime.lastError) {
|
|
1079
|
+
reject(new Error(chrome.runtime.lastError.message));
|
|
1080
|
+
} else {
|
|
1081
|
+
resolve(result);
|
|
1082
|
+
}
|
|
1083
|
+
});
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
async function cdpEval(expression, objectGroup = "console") {
|
|
1087
|
+
const expr = expression.trimStart().startsWith("{") ? `(${expression})` : expression;
|
|
1088
|
+
const targetId = await ensureAttached();
|
|
1089
|
+
const result = await new Promise((resolve, reject) => {
|
|
1090
|
+
chrome.debugger.sendCommand(
|
|
1091
|
+
{ targetId },
|
|
1092
|
+
"Runtime.evaluate",
|
|
1093
|
+
{ expression: expr, awaitPromise: true, returnByValue: false, generatePreview: true, objectGroup, replMode: true },
|
|
1094
|
+
(res) => {
|
|
1095
|
+
if (chrome.runtime.lastError) {
|
|
1096
|
+
swTargetId = null;
|
|
1097
|
+
reject(new Error(chrome.runtime.lastError.message));
|
|
1098
|
+
} else {
|
|
1099
|
+
resolve(res);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
);
|
|
1103
|
+
});
|
|
1104
|
+
if (result?.exceptionDetails) {
|
|
1105
|
+
const msg = result.exceptionDetails.exception?.description ?? result.exceptionDetails.text ?? "Unknown error";
|
|
1106
|
+
throw new Error(msg);
|
|
1107
|
+
}
|
|
1108
|
+
return result?.result;
|
|
1109
|
+
}
|
|
1110
|
+
async function cdpCallFunctionOn(objectId, functionDeclaration, returnByValue = true) {
|
|
1111
|
+
return cdpSendCommand("Runtime.callFunctionOn", {
|
|
1112
|
+
objectId,
|
|
1113
|
+
functionDeclaration,
|
|
1114
|
+
returnByValue
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
async function cdpGetProperties(objectId) {
|
|
1118
|
+
return cdpSendCommand("Runtime.getProperties", {
|
|
1119
|
+
objectId,
|
|
1120
|
+
ownProperties: true,
|
|
1121
|
+
generatePreview: true
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
export {
|
|
1125
|
+
COMMAND_NAMES as C,
|
|
1126
|
+
JS_CATEGORIES as J,
|
|
1127
|
+
cdpCallFunctionOn as a,
|
|
1128
|
+
cdpSendCommand as b,
|
|
1129
|
+
cdpEval as c,
|
|
1130
|
+
detectMode as d,
|
|
1131
|
+
cdpGetProperties as e,
|
|
1132
|
+
CATEGORIES as f,
|
|
1133
|
+
getTargetId as g,
|
|
1134
|
+
COMMANDS as h,
|
|
1135
|
+
execute as i,
|
|
1136
|
+
parseReplCommand as p,
|
|
1137
|
+
resolveConsoleMode as r
|
|
1138
|
+
};
|
|
1139
|
+
//# sourceMappingURL=sw-debugger-core.js.map
|