@ricsam/isolate-playwright 0.1.12 → 0.1.14
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 +254 -15
- package/dist/cjs/client.cjs +5 -318
- package/dist/cjs/client.cjs.map +3 -3
- package/dist/cjs/handler.cjs +1406 -0
- package/dist/cjs/handler.cjs.map +10 -0
- package/dist/cjs/index.cjs +793 -576
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/types.cjs +14 -1
- package/dist/cjs/types.cjs.map +4 -3
- package/dist/mjs/client.mjs +8 -317
- package/dist/mjs/client.mjs.map +3 -3
- package/dist/mjs/handler.mjs +1378 -0
- package/dist/mjs/handler.mjs.map +10 -0
- package/dist/mjs/index.mjs +802 -576
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/types.mjs +6 -1
- package/dist/mjs/types.mjs.map +4 -3
- package/dist/types/client.d.ts +3 -13
- package/dist/types/handler.d.ts +44 -0
- package/dist/types/index.d.ts +7 -72
- package/dist/types/types.d.ts +65 -11
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -43,450 +43,150 @@ var __export = (target, all) => {
|
|
|
43
43
|
var exports_src = {};
|
|
44
44
|
__export(exports_src, {
|
|
45
45
|
setupPlaywright: () => setupPlaywright,
|
|
46
|
-
|
|
46
|
+
getDefaultPlaywrightHandlerMetadata: () => import_handler.getDefaultPlaywrightHandlerMetadata,
|
|
47
|
+
defaultPlaywrightHandler: () => import_handler.defaultPlaywrightHandler,
|
|
48
|
+
createPlaywrightHandler: () => import_handler.createPlaywrightHandler,
|
|
49
|
+
DEFAULT_PLAYWRIGHT_HANDLER_META: () => import_types.DEFAULT_PLAYWRIGHT_HANDLER_META
|
|
47
50
|
});
|
|
48
51
|
module.exports = __toCommonJS(exports_src);
|
|
49
52
|
var import_isolated_vm = __toESM(require("isolated-vm"));
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (roleOptions) {
|
|
55
|
-
delete roleOptions.nth;
|
|
56
|
-
delete roleOptions.filter;
|
|
57
|
-
if (roleOptions.name && typeof roleOptions.name === "object" && roleOptions.name.$regex) {
|
|
58
|
-
roleOptions.name = new RegExp(roleOptions.name.$regex, roleOptions.name.$flags);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
let locator;
|
|
62
|
-
switch (selectorType) {
|
|
63
|
-
case "css":
|
|
64
|
-
locator = page.locator(selectorValue);
|
|
65
|
-
break;
|
|
66
|
-
case "role":
|
|
67
|
-
locator = page.getByRole(selectorValue, roleOptions && Object.keys(roleOptions).length > 0 ? roleOptions : undefined);
|
|
68
|
-
break;
|
|
69
|
-
case "text":
|
|
70
|
-
locator = page.getByText(selectorValue);
|
|
71
|
-
break;
|
|
72
|
-
case "label":
|
|
73
|
-
locator = page.getByLabel(selectorValue);
|
|
74
|
-
break;
|
|
75
|
-
case "placeholder":
|
|
76
|
-
locator = page.getByPlaceholder(selectorValue);
|
|
77
|
-
break;
|
|
78
|
-
case "testId":
|
|
79
|
-
locator = page.getByTestId(selectorValue);
|
|
80
|
-
break;
|
|
81
|
-
case "or": {
|
|
82
|
-
const [firstInfo, secondInfo] = JSON.parse(selectorValue);
|
|
83
|
-
const first = getLocator(page, firstInfo[0], firstInfo[1], firstInfo[2]);
|
|
84
|
-
const second = getLocator(page, secondInfo[0], secondInfo[1], secondInfo[2]);
|
|
85
|
-
locator = first.or(second);
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
default:
|
|
89
|
-
locator = page.locator(selectorValue);
|
|
90
|
-
}
|
|
91
|
-
if (nthIndex !== undefined) {
|
|
92
|
-
locator = locator.nth(nthIndex);
|
|
93
|
-
}
|
|
94
|
-
if (options?.filter) {
|
|
95
|
-
const filterOpts = { ...options.filter };
|
|
96
|
-
if (filterOpts.hasText && typeof filterOpts.hasText === "object" && filterOpts.hasText.$regex) {
|
|
97
|
-
filterOpts.hasText = new RegExp(filterOpts.hasText.$regex, filterOpts.hasText.$flags);
|
|
98
|
-
}
|
|
99
|
-
if (filterOpts.hasNotText && typeof filterOpts.hasNotText === "object" && filterOpts.hasNotText.$regex) {
|
|
100
|
-
filterOpts.hasNotText = new RegExp(filterOpts.hasNotText.$regex, filterOpts.hasNotText.$flags);
|
|
101
|
-
}
|
|
102
|
-
locator = locator.filter(filterOpts);
|
|
103
|
-
}
|
|
104
|
-
return locator;
|
|
105
|
-
}
|
|
106
|
-
async function executeLocatorAction(locator, action, actionArg, timeout) {
|
|
107
|
-
switch (action) {
|
|
108
|
-
case "click":
|
|
109
|
-
await locator.click({ timeout });
|
|
110
|
-
return null;
|
|
111
|
-
case "dblclick":
|
|
112
|
-
await locator.dblclick({ timeout });
|
|
113
|
-
return null;
|
|
114
|
-
case "fill":
|
|
115
|
-
await locator.fill(String(actionArg ?? ""), { timeout });
|
|
116
|
-
return null;
|
|
117
|
-
case "type":
|
|
118
|
-
await locator.pressSequentially(String(actionArg ?? ""), { timeout });
|
|
119
|
-
return null;
|
|
120
|
-
case "check":
|
|
121
|
-
await locator.check({ timeout });
|
|
122
|
-
return null;
|
|
123
|
-
case "uncheck":
|
|
124
|
-
await locator.uncheck({ timeout });
|
|
125
|
-
return null;
|
|
126
|
-
case "selectOption":
|
|
127
|
-
await locator.selectOption(String(actionArg ?? ""), { timeout });
|
|
128
|
-
return null;
|
|
129
|
-
case "clear":
|
|
130
|
-
await locator.clear({ timeout });
|
|
131
|
-
return null;
|
|
132
|
-
case "press":
|
|
133
|
-
await locator.press(String(actionArg ?? ""), { timeout });
|
|
134
|
-
return null;
|
|
135
|
-
case "hover":
|
|
136
|
-
await locator.hover({ timeout });
|
|
137
|
-
return null;
|
|
138
|
-
case "focus":
|
|
139
|
-
await locator.focus({ timeout });
|
|
140
|
-
return null;
|
|
141
|
-
case "getText":
|
|
142
|
-
return await locator.textContent({ timeout });
|
|
143
|
-
case "getValue":
|
|
144
|
-
return await locator.inputValue({ timeout });
|
|
145
|
-
case "isVisible":
|
|
146
|
-
return await locator.isVisible();
|
|
147
|
-
case "isEnabled":
|
|
148
|
-
return await locator.isEnabled();
|
|
149
|
-
case "isChecked":
|
|
150
|
-
return await locator.isChecked();
|
|
151
|
-
case "count":
|
|
152
|
-
return await locator.count();
|
|
153
|
-
case "getAttribute":
|
|
154
|
-
return await locator.getAttribute(String(actionArg ?? ""), { timeout });
|
|
155
|
-
case "isDisabled":
|
|
156
|
-
return await locator.isDisabled();
|
|
157
|
-
case "isHidden":
|
|
158
|
-
return await locator.isHidden();
|
|
159
|
-
case "innerHTML":
|
|
160
|
-
return await locator.innerHTML({ timeout });
|
|
161
|
-
case "innerText":
|
|
162
|
-
return await locator.innerText({ timeout });
|
|
163
|
-
case "allTextContents":
|
|
164
|
-
return await locator.allTextContents();
|
|
165
|
-
case "allInnerTexts":
|
|
166
|
-
return await locator.allInnerTexts();
|
|
167
|
-
case "waitFor": {
|
|
168
|
-
const opts = actionArg && typeof actionArg === "object" ? actionArg : {};
|
|
169
|
-
await locator.waitFor({ state: opts.state, timeout: opts.timeout ?? timeout });
|
|
170
|
-
return null;
|
|
171
|
-
}
|
|
172
|
-
case "boundingBox":
|
|
173
|
-
return await locator.boundingBox({ timeout });
|
|
174
|
-
default:
|
|
175
|
-
throw new Error(`Unknown action: ${action}`);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
async function executeExpectAssertion(locator, matcher, expected, negated, timeout) {
|
|
179
|
-
switch (matcher) {
|
|
180
|
-
case "toBeVisible": {
|
|
181
|
-
const isVisible = await locator.isVisible();
|
|
182
|
-
if (negated) {
|
|
183
|
-
if (isVisible)
|
|
184
|
-
throw new Error("Expected element to not be visible, but it was visible");
|
|
185
|
-
} else {
|
|
186
|
-
if (!isVisible)
|
|
187
|
-
throw new Error("Expected element to be visible, but it was not");
|
|
188
|
-
}
|
|
189
|
-
break;
|
|
190
|
-
}
|
|
191
|
-
case "toContainText": {
|
|
192
|
-
const text = await locator.textContent({ timeout });
|
|
193
|
-
let matches;
|
|
194
|
-
let expectedDisplay;
|
|
195
|
-
if (expected && typeof expected === "object" && expected.$regex) {
|
|
196
|
-
const regex = new RegExp(expected.$regex, expected.$flags);
|
|
197
|
-
matches = regex.test(text ?? "");
|
|
198
|
-
expectedDisplay = String(regex);
|
|
199
|
-
} else {
|
|
200
|
-
matches = text?.includes(String(expected)) ?? false;
|
|
201
|
-
expectedDisplay = String(expected);
|
|
202
|
-
}
|
|
203
|
-
if (negated) {
|
|
204
|
-
if (matches)
|
|
205
|
-
throw new Error(`Expected text to not contain ${expectedDisplay}, but got "${text}"`);
|
|
206
|
-
} else {
|
|
207
|
-
if (!matches)
|
|
208
|
-
throw new Error(`Expected text to contain ${expectedDisplay}, but got "${text}"`);
|
|
209
|
-
}
|
|
210
|
-
break;
|
|
211
|
-
}
|
|
212
|
-
case "toHaveValue": {
|
|
213
|
-
const value = await locator.inputValue({ timeout });
|
|
214
|
-
const matches = value === String(expected);
|
|
215
|
-
if (negated) {
|
|
216
|
-
if (matches)
|
|
217
|
-
throw new Error(`Expected value to not be "${expected}", but it was`);
|
|
218
|
-
} else {
|
|
219
|
-
if (!matches)
|
|
220
|
-
throw new Error(`Expected value to be "${expected}", but got "${value}"`);
|
|
221
|
-
}
|
|
222
|
-
break;
|
|
223
|
-
}
|
|
224
|
-
case "toBeEnabled": {
|
|
225
|
-
const isEnabled = await locator.isEnabled();
|
|
226
|
-
if (negated) {
|
|
227
|
-
if (isEnabled)
|
|
228
|
-
throw new Error("Expected element to be disabled, but it was enabled");
|
|
229
|
-
} else {
|
|
230
|
-
if (!isEnabled)
|
|
231
|
-
throw new Error("Expected element to be enabled, but it was disabled");
|
|
232
|
-
}
|
|
233
|
-
break;
|
|
234
|
-
}
|
|
235
|
-
case "toBeChecked": {
|
|
236
|
-
const isChecked = await locator.isChecked();
|
|
237
|
-
if (negated) {
|
|
238
|
-
if (isChecked)
|
|
239
|
-
throw new Error("Expected element to not be checked, but it was checked");
|
|
240
|
-
} else {
|
|
241
|
-
if (!isChecked)
|
|
242
|
-
throw new Error("Expected element to be checked, but it was not");
|
|
243
|
-
}
|
|
244
|
-
break;
|
|
245
|
-
}
|
|
246
|
-
case "toHaveAttribute": {
|
|
247
|
-
const { name, value } = expected;
|
|
248
|
-
const actual = await locator.getAttribute(name, { timeout });
|
|
249
|
-
if (value instanceof RegExp || value && typeof value === "object" && value.$regex) {
|
|
250
|
-
const regex = value.$regex ? new RegExp(value.$regex, value.$flags) : value;
|
|
251
|
-
const matches = regex.test(actual ?? "");
|
|
252
|
-
if (negated) {
|
|
253
|
-
if (matches)
|
|
254
|
-
throw new Error(`Expected attribute "${name}" to not match ${regex}, but got "${actual}"`);
|
|
255
|
-
} else {
|
|
256
|
-
if (!matches)
|
|
257
|
-
throw new Error(`Expected attribute "${name}" to match ${regex}, but got "${actual}"`);
|
|
258
|
-
}
|
|
259
|
-
} else {
|
|
260
|
-
const matches = actual === String(value);
|
|
261
|
-
if (negated) {
|
|
262
|
-
if (matches)
|
|
263
|
-
throw new Error(`Expected attribute "${name}" to not be "${value}", but it was`);
|
|
264
|
-
} else {
|
|
265
|
-
if (!matches)
|
|
266
|
-
throw new Error(`Expected attribute "${name}" to be "${value}", but got "${actual}"`);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
break;
|
|
270
|
-
}
|
|
271
|
-
case "toHaveText": {
|
|
272
|
-
const text = await locator.textContent({ timeout }) ?? "";
|
|
273
|
-
let matches;
|
|
274
|
-
let expectedDisplay;
|
|
275
|
-
if (expected && typeof expected === "object" && expected.$regex) {
|
|
276
|
-
const regex = new RegExp(expected.$regex, expected.$flags);
|
|
277
|
-
matches = regex.test(text);
|
|
278
|
-
expectedDisplay = String(regex);
|
|
279
|
-
} else {
|
|
280
|
-
matches = text === String(expected);
|
|
281
|
-
expectedDisplay = JSON.stringify(expected);
|
|
282
|
-
}
|
|
283
|
-
if (negated) {
|
|
284
|
-
if (matches)
|
|
285
|
-
throw new Error(`Expected text to not be ${expectedDisplay}, but got "${text}"`);
|
|
286
|
-
} else {
|
|
287
|
-
if (!matches)
|
|
288
|
-
throw new Error(`Expected text to be ${expectedDisplay}, but got "${text}"`);
|
|
289
|
-
}
|
|
290
|
-
break;
|
|
291
|
-
}
|
|
292
|
-
case "toHaveCount": {
|
|
293
|
-
const count = await locator.count();
|
|
294
|
-
const expectedCount = Number(expected);
|
|
295
|
-
if (negated) {
|
|
296
|
-
if (count === expectedCount)
|
|
297
|
-
throw new Error(`Expected count to not be ${expectedCount}, but it was`);
|
|
298
|
-
} else {
|
|
299
|
-
if (count !== expectedCount)
|
|
300
|
-
throw new Error(`Expected count to be ${expectedCount}, but got ${count}`);
|
|
301
|
-
}
|
|
302
|
-
break;
|
|
303
|
-
}
|
|
304
|
-
case "toBeHidden": {
|
|
305
|
-
const isHidden = await locator.isHidden();
|
|
306
|
-
if (negated) {
|
|
307
|
-
if (isHidden)
|
|
308
|
-
throw new Error("Expected element to not be hidden, but it was hidden");
|
|
309
|
-
} else {
|
|
310
|
-
if (!isHidden)
|
|
311
|
-
throw new Error("Expected element to be hidden, but it was not");
|
|
312
|
-
}
|
|
313
|
-
break;
|
|
314
|
-
}
|
|
315
|
-
case "toBeDisabled": {
|
|
316
|
-
const isDisabled = await locator.isDisabled();
|
|
317
|
-
if (negated) {
|
|
318
|
-
if (isDisabled)
|
|
319
|
-
throw new Error("Expected element to not be disabled, but it was disabled");
|
|
320
|
-
} else {
|
|
321
|
-
if (!isDisabled)
|
|
322
|
-
throw new Error("Expected element to be disabled, but it was not");
|
|
323
|
-
}
|
|
324
|
-
break;
|
|
325
|
-
}
|
|
326
|
-
case "toBeFocused": {
|
|
327
|
-
const isFocused = await locator.evaluate((el) => document.activeElement === el).catch(() => false);
|
|
328
|
-
if (negated) {
|
|
329
|
-
if (isFocused)
|
|
330
|
-
throw new Error("Expected element to not be focused, but it was focused");
|
|
331
|
-
} else {
|
|
332
|
-
if (!isFocused)
|
|
333
|
-
throw new Error("Expected element to be focused, but it was not");
|
|
334
|
-
}
|
|
335
|
-
break;
|
|
336
|
-
}
|
|
337
|
-
case "toBeEmpty": {
|
|
338
|
-
const text = await locator.textContent({ timeout });
|
|
339
|
-
const value = await locator.inputValue({ timeout }).catch(() => null);
|
|
340
|
-
const isEmpty = value !== null ? value === "" : (text ?? "") === "";
|
|
341
|
-
if (negated) {
|
|
342
|
-
if (isEmpty)
|
|
343
|
-
throw new Error("Expected element to not be empty, but it was");
|
|
344
|
-
} else {
|
|
345
|
-
if (!isEmpty)
|
|
346
|
-
throw new Error("Expected element to be empty, but it was not");
|
|
347
|
-
}
|
|
348
|
-
break;
|
|
349
|
-
}
|
|
350
|
-
default:
|
|
351
|
-
throw new Error(`Unknown matcher: ${matcher}`);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
function createPlaywrightHandler(page, options) {
|
|
355
|
-
const timeout = options?.timeout ?? 30000;
|
|
53
|
+
var import_types = require("./types.cjs");
|
|
54
|
+
var import_handler = require("./handler.cjs");
|
|
55
|
+
var import_handler2 = require("./handler.cjs");
|
|
56
|
+
function wrapHandlerWithPredicateSupport(handler, evaluatePredicate, defaultTimeout) {
|
|
356
57
|
return async (op) => {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
case "content":
|
|
375
|
-
return { ok: true, value: await page.content() };
|
|
376
|
-
case "waitForSelector": {
|
|
377
|
-
const [selector, optionsJson] = op.args;
|
|
378
|
-
const opts = optionsJson ? JSON.parse(optionsJson) : {};
|
|
379
|
-
await page.waitForSelector(selector, { timeout, ...opts });
|
|
380
|
-
return { ok: true };
|
|
381
|
-
}
|
|
382
|
-
case "waitForTimeout": {
|
|
383
|
-
const [ms] = op.args;
|
|
384
|
-
await page.waitForTimeout(ms);
|
|
385
|
-
return { ok: true };
|
|
386
|
-
}
|
|
387
|
-
case "waitForLoadState": {
|
|
388
|
-
const [state] = op.args;
|
|
389
|
-
await page.waitForLoadState(state ?? "load", { timeout });
|
|
390
|
-
return { ok: true };
|
|
391
|
-
}
|
|
392
|
-
case "evaluate": {
|
|
393
|
-
const [script, arg] = op.args;
|
|
394
|
-
if (op.args.length > 1) {
|
|
395
|
-
const fn = new Function("return (" + script + ")")();
|
|
396
|
-
const result2 = await page.evaluate(fn, arg);
|
|
397
|
-
return { ok: true, value: result2 };
|
|
398
|
-
}
|
|
399
|
-
const result = await page.evaluate(script);
|
|
400
|
-
return { ok: true, value: result };
|
|
401
|
-
}
|
|
402
|
-
case "locatorAction": {
|
|
403
|
-
const [selectorType, selectorValue, roleOptions, action, actionArg] = op.args;
|
|
404
|
-
const locator = getLocator(page, selectorType, selectorValue, roleOptions);
|
|
405
|
-
const result = await executeLocatorAction(locator, action, actionArg, timeout);
|
|
406
|
-
return { ok: true, value: result };
|
|
407
|
-
}
|
|
408
|
-
case "expectLocator": {
|
|
409
|
-
const [selectorType, selectorValue, roleOptions, matcher, expected, negated, customTimeout] = op.args;
|
|
410
|
-
const locator = getLocator(page, selectorType, selectorValue, roleOptions);
|
|
411
|
-
const effectiveTimeout = customTimeout ?? timeout;
|
|
412
|
-
await executeExpectAssertion(locator, matcher, expected, negated ?? false, effectiveTimeout);
|
|
413
|
-
return { ok: true };
|
|
414
|
-
}
|
|
415
|
-
case "request": {
|
|
416
|
-
const [url, method, data, headers] = op.args;
|
|
417
|
-
const requestOptions = {
|
|
418
|
-
timeout
|
|
419
|
-
};
|
|
420
|
-
if (headers) {
|
|
421
|
-
requestOptions.headers = headers;
|
|
58
|
+
switch (op.type) {
|
|
59
|
+
case "waitForURLPredicate": {
|
|
60
|
+
const [predicateId, customTimeout, waitUntil] = op.args;
|
|
61
|
+
const effectiveTimeout = customTimeout ?? defaultTimeout;
|
|
62
|
+
const startTime = Date.now();
|
|
63
|
+
const pollInterval = 100;
|
|
64
|
+
while (true) {
|
|
65
|
+
const urlResult = await handler({ type: "url", args: [], pageId: op.pageId, contextId: op.contextId });
|
|
66
|
+
if (urlResult.ok) {
|
|
67
|
+
try {
|
|
68
|
+
if (evaluatePredicate(predicateId, urlResult.value)) {
|
|
69
|
+
return { ok: true };
|
|
70
|
+
}
|
|
71
|
+
} catch (e) {
|
|
72
|
+
const error = e;
|
|
73
|
+
return { ok: false, error: { name: error.name, message: error.message } };
|
|
74
|
+
}
|
|
422
75
|
}
|
|
423
|
-
if (
|
|
424
|
-
|
|
76
|
+
if (effectiveTimeout > 0 && Date.now() - startTime >= effectiveTimeout) {
|
|
77
|
+
return { ok: false, error: { name: "Error", message: `Timeout ${effectiveTimeout}ms exceeded waiting for URL` } };
|
|
425
78
|
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
79
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
case "waitForResponsePredicateFinish": {
|
|
83
|
+
const [initialListenerId, predicateId, customTimeout] = op.args;
|
|
84
|
+
const effectiveTimeout = customTimeout ?? defaultTimeout;
|
|
85
|
+
const broadMatcher = { type: "regex", value: { $regex: ".*", $flags: "" } };
|
|
86
|
+
const startTime = Date.now();
|
|
87
|
+
let currentListenerId = initialListenerId;
|
|
88
|
+
while (true) {
|
|
89
|
+
const finishResult = await handler({
|
|
90
|
+
type: "waitForResponseFinish",
|
|
91
|
+
args: [currentListenerId],
|
|
92
|
+
pageId: op.pageId,
|
|
93
|
+
contextId: op.contextId
|
|
429
94
|
});
|
|
430
|
-
|
|
431
|
-
|
|
95
|
+
if (!finishResult.ok)
|
|
96
|
+
return finishResult;
|
|
97
|
+
const responseData = finishResult.value;
|
|
432
98
|
try {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
body: null
|
|
99
|
+
const serialized = {
|
|
100
|
+
method: "",
|
|
101
|
+
headers: Object.entries(responseData.headers || {}),
|
|
102
|
+
url: responseData.url,
|
|
103
|
+
status: responseData.status,
|
|
104
|
+
statusText: responseData.statusText,
|
|
105
|
+
body: responseData.text || ""
|
|
106
|
+
};
|
|
107
|
+
if (evaluatePredicate(predicateId, serialized)) {
|
|
108
|
+
return finishResult;
|
|
444
109
|
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
110
|
+
} catch (e) {
|
|
111
|
+
const error = e;
|
|
112
|
+
return { ok: false, error: { name: error.name, message: error.message } };
|
|
113
|
+
}
|
|
114
|
+
if (effectiveTimeout > 0 && Date.now() - startTime >= effectiveTimeout) {
|
|
115
|
+
return { ok: false, error: { name: "Error", message: `Timeout ${effectiveTimeout}ms exceeded waiting for response` } };
|
|
116
|
+
}
|
|
117
|
+
const remainingTimeout = effectiveTimeout > 0 ? Math.max(1, effectiveTimeout - (Date.now() - startTime)) : effectiveTimeout;
|
|
118
|
+
const nextStartResult = await handler({
|
|
119
|
+
type: "waitForResponseStart",
|
|
120
|
+
args: [broadMatcher, remainingTimeout],
|
|
121
|
+
pageId: op.pageId,
|
|
122
|
+
contextId: op.contextId
|
|
452
123
|
});
|
|
453
|
-
|
|
124
|
+
if (!nextStartResult.ok)
|
|
125
|
+
return nextStartResult;
|
|
126
|
+
currentListenerId = nextStartResult.value.listenerId;
|
|
454
127
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
128
|
+
}
|
|
129
|
+
case "waitForRequestPredicateFinish": {
|
|
130
|
+
const [initialListenerId, predicateId, customTimeout] = op.args;
|
|
131
|
+
const effectiveTimeout = customTimeout ?? defaultTimeout;
|
|
132
|
+
const broadMatcher = { type: "regex", value: { $regex: ".*", $flags: "" } };
|
|
133
|
+
const startTime = Date.now();
|
|
134
|
+
let currentListenerId = initialListenerId;
|
|
135
|
+
while (true) {
|
|
136
|
+
const finishResult = await handler({
|
|
137
|
+
type: "waitForRequestFinish",
|
|
138
|
+
args: [currentListenerId],
|
|
139
|
+
pageId: op.pageId,
|
|
140
|
+
contextId: op.contextId
|
|
460
141
|
});
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
142
|
+
if (!finishResult.ok)
|
|
143
|
+
return finishResult;
|
|
144
|
+
const requestData = finishResult.value;
|
|
145
|
+
try {
|
|
146
|
+
const serialized = {
|
|
147
|
+
method: requestData.method,
|
|
148
|
+
headers: Object.entries(requestData.headers || {}),
|
|
149
|
+
url: requestData.url,
|
|
150
|
+
body: requestData.postData || ""
|
|
151
|
+
};
|
|
152
|
+
if (evaluatePredicate(predicateId, serialized)) {
|
|
153
|
+
return finishResult;
|
|
154
|
+
}
|
|
155
|
+
} catch (e) {
|
|
156
|
+
const error = e;
|
|
157
|
+
return { ok: false, error: { name: error.name, message: error.message } };
|
|
158
|
+
}
|
|
159
|
+
if (effectiveTimeout > 0 && Date.now() - startTime >= effectiveTimeout) {
|
|
160
|
+
return { ok: false, error: { name: "Error", message: `Timeout ${effectiveTimeout}ms exceeded waiting for request` } };
|
|
161
|
+
}
|
|
162
|
+
const remainingTimeout = effectiveTimeout > 0 ? Math.max(1, effectiveTimeout - (Date.now() - startTime)) : effectiveTimeout;
|
|
163
|
+
const nextStartResult = await handler({
|
|
164
|
+
type: "waitForRequestStart",
|
|
165
|
+
args: [broadMatcher, remainingTimeout],
|
|
166
|
+
pageId: op.pageId,
|
|
167
|
+
contextId: op.contextId
|
|
468
168
|
});
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
await page.context().clearCookies();
|
|
473
|
-
return { ok: true };
|
|
169
|
+
if (!nextStartResult.ok)
|
|
170
|
+
return nextStartResult;
|
|
171
|
+
currentListenerId = nextStartResult.value.listenerId;
|
|
474
172
|
}
|
|
475
|
-
default:
|
|
476
|
-
return { ok: false, error: { name: "Error", message: `Unknown operation: ${op.type}` } };
|
|
477
173
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
return { ok: false, error: { name: error.name, message: error.message } };
|
|
174
|
+
default:
|
|
175
|
+
return handler(op);
|
|
481
176
|
}
|
|
482
177
|
};
|
|
483
178
|
}
|
|
484
179
|
async function setupPlaywright(context, options) {
|
|
485
180
|
const timeout = options.timeout ?? 30000;
|
|
486
|
-
const
|
|
181
|
+
const explicitPage = "page" in options ? options.page : undefined;
|
|
487
182
|
const handler = "handler" in options ? options.handler : undefined;
|
|
488
|
-
const
|
|
489
|
-
|
|
183
|
+
const handlerMetadata = handler ? import_handler2.getDefaultPlaywrightHandlerMetadata(handler) : undefined;
|
|
184
|
+
const page = explicitPage ?? handlerMetadata?.page;
|
|
185
|
+
const createPage = "createPage" in options ? options.createPage : undefined;
|
|
186
|
+
const createContext = "createContext" in options ? options.createContext : undefined;
|
|
187
|
+
const readFile = "readFile" in options ? options.readFile : undefined;
|
|
188
|
+
const writeFile = "writeFile" in options ? options.writeFile : undefined;
|
|
189
|
+
if (!handler && !page) {
|
|
490
190
|
throw new Error("Either page or handler must be provided to setupPlaywright");
|
|
491
191
|
}
|
|
492
192
|
const browserConsoleLogs = [];
|
|
@@ -565,15 +265,10 @@ async function setupPlaywright(context, options) {
|
|
|
565
265
|
page.on("response", responseHandler);
|
|
566
266
|
page.on("console", consoleHandler);
|
|
567
267
|
}
|
|
568
|
-
global.setSync("__Playwright_handler_ref", new import_isolated_vm.default.Reference(async (opJson) => {
|
|
569
|
-
const op = JSON.parse(opJson);
|
|
570
|
-
const result = await effectiveHandler(op);
|
|
571
|
-
return JSON.stringify(result);
|
|
572
|
-
}));
|
|
573
268
|
context.evalSync(`
|
|
574
269
|
(function() {
|
|
575
|
-
globalThis.
|
|
576
|
-
const op = JSON.stringify({ type, args });
|
|
270
|
+
globalThis.__pw_invoke_sync = function(type, args, options) {
|
|
271
|
+
const op = JSON.stringify({ type, args, pageId: options?.pageId, contextId: options?.contextId });
|
|
577
272
|
const resultJson = __Playwright_handler_ref.applySyncPromise(undefined, [op]);
|
|
578
273
|
const result = JSON.parse(resultJson);
|
|
579
274
|
if (result.ok) {
|
|
@@ -584,215 +279,607 @@ async function setupPlaywright(context, options) {
|
|
|
584
279
|
throw error;
|
|
585
280
|
}
|
|
586
281
|
};
|
|
282
|
+
globalThis.__pw_invoke = async function(type, args, options) {
|
|
283
|
+
return globalThis.__pw_invoke_sync(type, args, options);
|
|
284
|
+
};
|
|
587
285
|
})();
|
|
588
286
|
`);
|
|
589
287
|
context.evalSync(`
|
|
590
288
|
(function() {
|
|
591
|
-
|
|
592
|
-
|
|
289
|
+
const __pw_predicates = new Map();
|
|
290
|
+
let __pw_next_id = 0;
|
|
291
|
+
globalThis.__pw_register_predicate = function(fn) {
|
|
292
|
+
const id = __pw_next_id++;
|
|
293
|
+
__pw_predicates.set(id, fn);
|
|
294
|
+
return id;
|
|
295
|
+
};
|
|
296
|
+
globalThis.__pw_unregister_predicate = function(id) {
|
|
297
|
+
__pw_predicates.delete(id);
|
|
298
|
+
};
|
|
299
|
+
globalThis.__pw_evaluate_predicate = function(id, data) {
|
|
300
|
+
const fn = __pw_predicates.get(id);
|
|
301
|
+
if (!fn) throw new Error('Predicate not found: ' + id);
|
|
302
|
+
const result = fn(data);
|
|
303
|
+
if (result && typeof result === 'object' && typeof result.then === 'function') {
|
|
304
|
+
throw new Error('Async predicates are not supported. Use a synchronous predicate function.');
|
|
305
|
+
}
|
|
306
|
+
return !!result;
|
|
307
|
+
};
|
|
308
|
+
})();
|
|
309
|
+
`);
|
|
310
|
+
const evaluatePredicateRef = context.global.getSync("__pw_evaluate_predicate", { reference: true });
|
|
311
|
+
const evaluatePredicateFn = (predicateId, data) => {
|
|
312
|
+
return evaluatePredicateRef.applySync(undefined, [new import_isolated_vm.default.ExternalCopy(predicateId).copyInto(), new import_isolated_vm.default.ExternalCopy(data).copyInto()]);
|
|
313
|
+
};
|
|
314
|
+
let effectiveHandler;
|
|
315
|
+
if (handler && handlerMetadata?.page) {
|
|
316
|
+
effectiveHandler = import_handler2.createPlaywrightHandler(handlerMetadata.page, {
|
|
317
|
+
...handlerMetadata.options,
|
|
318
|
+
evaluatePredicate: evaluatePredicateFn
|
|
319
|
+
});
|
|
320
|
+
} else if (handler) {
|
|
321
|
+
effectiveHandler = wrapHandlerWithPredicateSupport(handler, evaluatePredicateFn, timeout);
|
|
322
|
+
} else if (page) {
|
|
323
|
+
effectiveHandler = import_handler2.createPlaywrightHandler(page, {
|
|
324
|
+
timeout,
|
|
325
|
+
readFile,
|
|
326
|
+
writeFile,
|
|
327
|
+
createPage,
|
|
328
|
+
createContext,
|
|
329
|
+
evaluatePredicate: evaluatePredicateFn
|
|
330
|
+
});
|
|
331
|
+
} else {
|
|
332
|
+
throw new Error("Either page or handler must be provided to setupPlaywright");
|
|
333
|
+
}
|
|
334
|
+
global.setSync("__Playwright_handler_ref", new import_isolated_vm.default.Reference(async (opJson) => {
|
|
335
|
+
const op = JSON.parse(opJson);
|
|
336
|
+
const result = await effectiveHandler(op);
|
|
337
|
+
return JSON.stringify(result);
|
|
338
|
+
}));
|
|
339
|
+
context.evalSync(`
|
|
340
|
+
(function() {
|
|
341
|
+
// IsolatePage class - represents a page with a specific pageId
|
|
342
|
+
class IsolatePage {
|
|
343
|
+
#pageId; #contextId;
|
|
344
|
+
constructor(pageId, contextId) {
|
|
345
|
+
this.#pageId = pageId;
|
|
346
|
+
this.#contextId = contextId;
|
|
347
|
+
}
|
|
348
|
+
get __isPage() { return true; }
|
|
349
|
+
get __pageId() { return this.#pageId; }
|
|
350
|
+
get __contextId() { return this.#contextId; }
|
|
351
|
+
|
|
593
352
|
async goto(url, options) {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
__pw_currentUrl = resolvedUrl || url;
|
|
597
|
-
return result;
|
|
598
|
-
},
|
|
353
|
+
await __pw_invoke("goto", [url, options?.waitUntil || null], { pageId: this.#pageId });
|
|
354
|
+
}
|
|
599
355
|
async reload() {
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
}
|
|
605
|
-
url() {
|
|
606
|
-
return __pw_currentUrl;
|
|
607
|
-
},
|
|
608
|
-
async title() {
|
|
609
|
-
return __pw_invoke("title", []);
|
|
610
|
-
},
|
|
611
|
-
async content() {
|
|
612
|
-
return __pw_invoke("content", []);
|
|
613
|
-
},
|
|
356
|
+
await __pw_invoke("reload", [], { pageId: this.#pageId });
|
|
357
|
+
}
|
|
358
|
+
url() { return __pw_invoke_sync("url", [], { pageId: this.#pageId }); }
|
|
359
|
+
async title() { return __pw_invoke("title", [], { pageId: this.#pageId }); }
|
|
360
|
+
async content() { return __pw_invoke("content", [], { pageId: this.#pageId }); }
|
|
614
361
|
async waitForSelector(selector, options) {
|
|
615
|
-
return __pw_invoke("waitForSelector", [selector, options ? JSON.stringify(options) : null]);
|
|
616
|
-
}
|
|
617
|
-
async waitForTimeout(ms) {
|
|
618
|
-
|
|
619
|
-
},
|
|
620
|
-
async waitForLoadState(state) {
|
|
621
|
-
return __pw_invoke("waitForLoadState", [state || null]);
|
|
622
|
-
},
|
|
362
|
+
return __pw_invoke("waitForSelector", [selector, options ? JSON.stringify(options) : null], { pageId: this.#pageId });
|
|
363
|
+
}
|
|
364
|
+
async waitForTimeout(ms) { return __pw_invoke("waitForTimeout", [ms], { pageId: this.#pageId }); }
|
|
365
|
+
async waitForLoadState(state) { return __pw_invoke("waitForLoadState", [state || null], { pageId: this.#pageId }); }
|
|
623
366
|
async evaluate(script, arg) {
|
|
624
367
|
const hasArg = arguments.length > 1;
|
|
625
368
|
if (hasArg) {
|
|
626
369
|
const serialized = typeof script === "function" ? script.toString() : script;
|
|
627
|
-
return __pw_invoke("evaluate", [serialized, arg]);
|
|
370
|
+
return __pw_invoke("evaluate", [serialized, arg], { pageId: this.#pageId });
|
|
628
371
|
}
|
|
629
372
|
const serialized = typeof script === "function" ? "(" + script.toString() + ")()" : script;
|
|
630
|
-
return __pw_invoke("evaluate", [serialized]);
|
|
631
|
-
}
|
|
632
|
-
locator(selector) { return new Locator("css", selector, null); }
|
|
373
|
+
return __pw_invoke("evaluate", [serialized], { pageId: this.#pageId });
|
|
374
|
+
}
|
|
375
|
+
locator(selector) { return new Locator("css", selector, null, this.#pageId); }
|
|
633
376
|
getByRole(role, options) {
|
|
634
377
|
if (options) {
|
|
635
378
|
const serialized = { ...options };
|
|
636
|
-
// Use duck-typing RegExp detection (instanceof fails across isolated-vm boundary)
|
|
637
379
|
const name = options.name;
|
|
638
380
|
if (name && typeof name === 'object' && typeof name.source === 'string' && typeof name.flags === 'string') {
|
|
639
381
|
serialized.name = { $regex: name.source, $flags: name.flags };
|
|
640
382
|
}
|
|
641
|
-
return new Locator("role", role, JSON.stringify(serialized));
|
|
383
|
+
return new Locator("role", role, JSON.stringify(serialized), this.#pageId);
|
|
642
384
|
}
|
|
643
|
-
return new Locator("role", role, null);
|
|
644
|
-
}
|
|
645
|
-
getByText(text) { return new Locator("text", text, null); }
|
|
646
|
-
getByLabel(label) { return new Locator("label", label, null); }
|
|
647
|
-
getByPlaceholder(p) { return new Locator("placeholder", p, null); }
|
|
648
|
-
getByTestId(id) { return new Locator("testId", id, null); }
|
|
385
|
+
return new Locator("role", role, null, this.#pageId);
|
|
386
|
+
}
|
|
387
|
+
getByText(text) { return new Locator("text", text, null, this.#pageId); }
|
|
388
|
+
getByLabel(label) { return new Locator("label", label, null, this.#pageId); }
|
|
389
|
+
getByPlaceholder(p) { return new Locator("placeholder", p, null, this.#pageId); }
|
|
390
|
+
getByTestId(id) { return new Locator("testId", id, null, this.#pageId); }
|
|
391
|
+
getByAltText(alt) { return new Locator("altText", alt, null, this.#pageId); }
|
|
392
|
+
getByTitle(title) { return new Locator("title", title, null, this.#pageId); }
|
|
393
|
+
frameLocator(selector) {
|
|
394
|
+
const pageId = this.#pageId;
|
|
395
|
+
return {
|
|
396
|
+
locator(innerSelector) { return new Locator("frame", JSON.stringify([["css", selector, null], ["css", innerSelector, null]]), null, pageId); },
|
|
397
|
+
getByRole(role, options) { return new Locator("frame", JSON.stringify([["css", selector, null], ["role", role, options ? JSON.stringify(options) : null]]), null, pageId); },
|
|
398
|
+
getByText(text) { return new Locator("frame", JSON.stringify([["css", selector, null], ["text", text, null]]), null, pageId); },
|
|
399
|
+
getByLabel(label) { return new Locator("frame", JSON.stringify([["css", selector, null], ["label", label, null]]), null, pageId); },
|
|
400
|
+
getByPlaceholder(placeholder) { return new Locator("frame", JSON.stringify([["css", selector, null], ["placeholder", placeholder, null]]), null, pageId); },
|
|
401
|
+
getByTestId(testId) { return new Locator("frame", JSON.stringify([["css", selector, null], ["testId", testId, null]]), null, pageId); },
|
|
402
|
+
getByAltText(alt) { return new Locator("frame", JSON.stringify([["css", selector, null], ["altText", alt, null]]), null, pageId); },
|
|
403
|
+
getByTitle(title) { return new Locator("frame", JSON.stringify([["css", selector, null], ["title", title, null]]), null, pageId); },
|
|
404
|
+
};
|
|
405
|
+
}
|
|
649
406
|
async goBack(options) {
|
|
650
|
-
await __pw_invoke("goBack", [options?.waitUntil || null]);
|
|
651
|
-
|
|
652
|
-
if (resolvedUrl) __pw_currentUrl = resolvedUrl;
|
|
653
|
-
},
|
|
407
|
+
await __pw_invoke("goBack", [options?.waitUntil || null], { pageId: this.#pageId });
|
|
408
|
+
}
|
|
654
409
|
async goForward(options) {
|
|
655
|
-
await __pw_invoke("goForward", [options?.waitUntil || null]);
|
|
656
|
-
|
|
657
|
-
if (resolvedUrl) __pw_currentUrl = resolvedUrl;
|
|
658
|
-
},
|
|
410
|
+
await __pw_invoke("goForward", [options?.waitUntil || null], { pageId: this.#pageId });
|
|
411
|
+
}
|
|
659
412
|
async waitForURL(url, options) {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
413
|
+
if (typeof url === 'function') {
|
|
414
|
+
const predicateId = __pw_register_predicate(url);
|
|
415
|
+
try {
|
|
416
|
+
await __pw_invoke("waitForURLPredicate", [predicateId, options?.timeout || null, options?.waitUntil || null], { pageId: this.#pageId });
|
|
417
|
+
} finally {
|
|
418
|
+
__pw_unregister_predicate(predicateId);
|
|
419
|
+
}
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
let serializedUrl;
|
|
423
|
+
if (typeof url === 'string') {
|
|
424
|
+
serializedUrl = { type: 'string', value: url };
|
|
425
|
+
} else if (url && typeof url === 'object' && typeof url.source === 'string' && typeof url.flags === 'string') {
|
|
426
|
+
serializedUrl = { type: 'regex', value: { $regex: url.source, $flags: url.flags } };
|
|
427
|
+
} else {
|
|
428
|
+
serializedUrl = url;
|
|
429
|
+
}
|
|
430
|
+
return __pw_invoke("waitForURL", [serializedUrl, options?.timeout || null, options?.waitUntil || null], { pageId: this.#pageId });
|
|
431
|
+
}
|
|
432
|
+
waitForRequest(urlOrPredicate, options) {
|
|
433
|
+
if (typeof urlOrPredicate === 'function') {
|
|
434
|
+
const userPredicate = urlOrPredicate;
|
|
435
|
+
const wrappedPredicate = (data) => {
|
|
436
|
+
const requestLike = {
|
|
437
|
+
url: () => data.url,
|
|
438
|
+
method: () => data.method,
|
|
439
|
+
headers: () => Object.fromEntries(data.headers),
|
|
440
|
+
headersArray: () => data.headers.map(h => ({ name: h[0], value: h[1] })),
|
|
441
|
+
postData: () => data.body || null,
|
|
442
|
+
};
|
|
443
|
+
return userPredicate(requestLike);
|
|
444
|
+
};
|
|
445
|
+
const predicateId = __pw_register_predicate(wrappedPredicate);
|
|
446
|
+
const pageId = this.#pageId;
|
|
447
|
+
// Start listening immediately (before the user triggers the request)
|
|
448
|
+
const broadMatcher = { type: 'regex', value: { $regex: '.*', $flags: '' } };
|
|
449
|
+
const startResult = __pw_invoke_sync("waitForRequestStart", [broadMatcher, options?.timeout || null], { pageId });
|
|
450
|
+
const listenerId = startResult.listenerId;
|
|
451
|
+
return {
|
|
452
|
+
then(resolve, reject) {
|
|
453
|
+
try {
|
|
454
|
+
const r = __pw_invoke_sync("waitForRequestPredicateFinish", [listenerId, predicateId, options?.timeout || null], { pageId });
|
|
455
|
+
resolve({ url: () => r.url, method: () => r.method, headers: () => r.headers, postData: () => r.postData });
|
|
456
|
+
} catch(e) { reject(e); } finally { __pw_unregister_predicate(predicateId); }
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
let serializedMatcher;
|
|
461
|
+
if (typeof urlOrPredicate === 'string') {
|
|
462
|
+
serializedMatcher = { type: 'string', value: urlOrPredicate };
|
|
463
|
+
} else if (urlOrPredicate && typeof urlOrPredicate === 'object'
|
|
464
|
+
&& typeof urlOrPredicate.source === 'string'
|
|
465
|
+
&& typeof urlOrPredicate.flags === 'string') {
|
|
466
|
+
serializedMatcher = { type: 'regex', value: { $regex: urlOrPredicate.source, $flags: urlOrPredicate.flags } };
|
|
467
|
+
} else {
|
|
468
|
+
throw new Error('waitForRequest requires a URL string, RegExp, or predicate function');
|
|
469
|
+
}
|
|
470
|
+
const startResult = __pw_invoke_sync("waitForRequestStart", [serializedMatcher, options?.timeout || null], { pageId: this.#pageId });
|
|
471
|
+
const listenerId = startResult.listenerId;
|
|
472
|
+
const pageId = this.#pageId;
|
|
663
473
|
return {
|
|
664
|
-
|
|
665
|
-
|
|
474
|
+
then(resolve, reject) {
|
|
475
|
+
try {
|
|
476
|
+
const r = __pw_invoke_sync("waitForRequestFinish", [listenerId], { pageId });
|
|
477
|
+
resolve({ url: () => r.url, method: () => r.method, headers: () => r.headers, postData: () => r.postData });
|
|
478
|
+
} catch(e) { reject(e); }
|
|
666
479
|
}
|
|
667
480
|
};
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
481
|
+
}
|
|
482
|
+
waitForResponse(urlOrPredicate, options) {
|
|
483
|
+
if (typeof urlOrPredicate === 'function') {
|
|
484
|
+
const userPredicate = urlOrPredicate;
|
|
485
|
+
const wrappedPredicate = (data) => {
|
|
486
|
+
const responseLike = {
|
|
487
|
+
url: () => data.url,
|
|
488
|
+
status: () => data.status,
|
|
489
|
+
statusText: () => data.statusText,
|
|
490
|
+
headers: () => Object.fromEntries(data.headers),
|
|
491
|
+
headersArray: () => data.headers.map(h => ({ name: h[0], value: h[1] })),
|
|
492
|
+
ok: () => data.status >= 200 && data.status < 300,
|
|
493
|
+
};
|
|
494
|
+
return userPredicate(responseLike);
|
|
495
|
+
};
|
|
496
|
+
const predicateId = __pw_register_predicate(wrappedPredicate);
|
|
497
|
+
const pageId = this.#pageId;
|
|
498
|
+
// Start listening immediately (before the user triggers the response)
|
|
499
|
+
const broadMatcher = { type: 'regex', value: { $regex: '.*', $flags: '' } };
|
|
500
|
+
const startResult = __pw_invoke_sync("waitForResponseStart", [broadMatcher, options?.timeout || null], { pageId });
|
|
501
|
+
const listenerId = startResult.listenerId;
|
|
674
502
|
return {
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
503
|
+
then(resolve, reject) {
|
|
504
|
+
try {
|
|
505
|
+
const r = __pw_invoke_sync("waitForResponsePredicateFinish", [listenerId, predicateId, options?.timeout || null], { pageId });
|
|
506
|
+
resolve({
|
|
507
|
+
url: () => r.url, status: () => r.status, statusText: () => r.statusText,
|
|
508
|
+
headers: () => r.headers, headersArray: () => r.headersArray,
|
|
509
|
+
ok: () => r.ok, json: async () => r.json, text: async () => r.text, body: async () => r.body,
|
|
510
|
+
});
|
|
511
|
+
} catch(e) { reject(e); } finally { __pw_unregister_predicate(predicateId); }
|
|
512
|
+
}
|
|
681
513
|
};
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
514
|
+
}
|
|
515
|
+
let serializedMatcher;
|
|
516
|
+
if (typeof urlOrPredicate === 'string') {
|
|
517
|
+
serializedMatcher = { type: 'string', value: urlOrPredicate };
|
|
518
|
+
} else if (urlOrPredicate && typeof urlOrPredicate === 'object'
|
|
519
|
+
&& typeof urlOrPredicate.source === 'string'
|
|
520
|
+
&& typeof urlOrPredicate.flags === 'string') {
|
|
521
|
+
serializedMatcher = { type: 'regex', value: { $regex: urlOrPredicate.source, $flags: urlOrPredicate.flags } };
|
|
522
|
+
} else {
|
|
523
|
+
throw new Error('waitForResponse requires a URL string, RegExp, or predicate function');
|
|
524
|
+
}
|
|
525
|
+
const startResult = __pw_invoke_sync("waitForResponseStart", [serializedMatcher, options?.timeout || null], { pageId: this.#pageId });
|
|
526
|
+
const listenerId = startResult.listenerId;
|
|
527
|
+
const pageId = this.#pageId;
|
|
528
|
+
return {
|
|
529
|
+
then(resolve, reject) {
|
|
530
|
+
try {
|
|
531
|
+
const r = __pw_invoke_sync("waitForResponseFinish", [listenerId], { pageId });
|
|
532
|
+
resolve({
|
|
533
|
+
url: () => r.url, status: () => r.status, statusText: () => r.statusText,
|
|
534
|
+
headers: () => r.headers, headersArray: () => r.headersArray,
|
|
535
|
+
ok: () => r.ok, json: async () => r.json, text: async () => r.text, body: async () => r.body,
|
|
536
|
+
});
|
|
537
|
+
} catch(e) { reject(e); }
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
context() {
|
|
542
|
+
const contextId = this.#contextId;
|
|
543
|
+
return new IsolateContext(contextId);
|
|
544
|
+
}
|
|
545
|
+
async click(selector) { return this.locator(selector).click(); }
|
|
546
|
+
async fill(selector, value) { return this.locator(selector).fill(value); }
|
|
547
|
+
async textContent(selector) { return this.locator(selector).textContent(); }
|
|
548
|
+
async innerText(selector) { return this.locator(selector).innerText(); }
|
|
549
|
+
async innerHTML(selector) { return this.locator(selector).innerHTML(); }
|
|
550
|
+
async getAttribute(selector, name) { return this.locator(selector).getAttribute(name); }
|
|
551
|
+
async inputValue(selector) { return this.locator(selector).inputValue(); }
|
|
552
|
+
async isVisible(selector) { return this.locator(selector).isVisible(); }
|
|
553
|
+
async isEnabled(selector) { return this.locator(selector).isEnabled(); }
|
|
554
|
+
async isChecked(selector) { return this.locator(selector).isChecked(); }
|
|
555
|
+
async isHidden(selector) { return this.locator(selector).isHidden(); }
|
|
556
|
+
async isDisabled(selector) { return this.locator(selector).isDisabled(); }
|
|
557
|
+
async screenshot(options) { return __pw_invoke("screenshot", [options || {}], { pageId: this.#pageId }); }
|
|
558
|
+
async setViewportSize(size) { return __pw_invoke("setViewportSize", [size], { pageId: this.#pageId }); }
|
|
559
|
+
async viewportSize() { return __pw_invoke("viewportSize", [], { pageId: this.#pageId }); }
|
|
560
|
+
async emulateMedia(options) { return __pw_invoke("emulateMedia", [options], { pageId: this.#pageId }); }
|
|
561
|
+
async setExtraHTTPHeaders(headers) { return __pw_invoke("setExtraHTTPHeaders", [headers], { pageId: this.#pageId }); }
|
|
562
|
+
async bringToFront() { return __pw_invoke("bringToFront", [], { pageId: this.#pageId }); }
|
|
563
|
+
async close() { return __pw_invoke("close", [], { pageId: this.#pageId }); }
|
|
564
|
+
async isClosed() { return __pw_invoke("isClosed", [], { pageId: this.#pageId }); }
|
|
565
|
+
async pdf(options) { return __pw_invoke("pdf", [options || {}], { pageId: this.#pageId }); }
|
|
566
|
+
async pause() { return __pw_invoke("pause", [], { pageId: this.#pageId }); }
|
|
567
|
+
async frames() { return __pw_invoke("frames", [], { pageId: this.#pageId }); }
|
|
568
|
+
async mainFrame() { return __pw_invoke("mainFrame", [], { pageId: this.#pageId }); }
|
|
569
|
+
get keyboard() {
|
|
570
|
+
const pageId = this.#pageId;
|
|
571
|
+
return {
|
|
572
|
+
async type(text, options) { return __pw_invoke("keyboardType", [text, options], { pageId }); },
|
|
573
|
+
async press(key, options) { return __pw_invoke("keyboardPress", [key, options], { pageId }); },
|
|
574
|
+
async down(key) { return __pw_invoke("keyboardDown", [key], { pageId }); },
|
|
575
|
+
async up(key) { return __pw_invoke("keyboardUp", [key], { pageId }); },
|
|
576
|
+
async insertText(text) { return __pw_invoke("keyboardInsertText", [text], { pageId }); }
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
get mouse() {
|
|
580
|
+
const pageId = this.#pageId;
|
|
581
|
+
return {
|
|
582
|
+
async move(x, y, options) { return __pw_invoke("mouseMove", [x, y, options], { pageId }); },
|
|
583
|
+
async click(x, y, options) { return __pw_invoke("mouseClick", [x, y, options], { pageId }); },
|
|
584
|
+
async down(options) { return __pw_invoke("mouseDown", [options], { pageId }); },
|
|
585
|
+
async up(options) { return __pw_invoke("mouseUp", [options], { pageId }); },
|
|
586
|
+
async wheel(deltaX, deltaY) { return __pw_invoke("mouseWheel", [deltaX, deltaY], { pageId }); }
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
get request() {
|
|
590
|
+
const pageId = this.#pageId;
|
|
591
|
+
return {
|
|
592
|
+
async fetch(url, options) {
|
|
593
|
+
const result = await __pw_invoke("request", [url, options?.method || "GET", options?.data, options?.headers], { pageId });
|
|
594
|
+
return {
|
|
595
|
+
status: () => result.status,
|
|
596
|
+
ok: () => result.ok,
|
|
597
|
+
headers: () => result.headers,
|
|
598
|
+
json: async () => result.json,
|
|
599
|
+
text: async () => result.text,
|
|
600
|
+
body: async () => result.body,
|
|
601
|
+
};
|
|
602
|
+
},
|
|
603
|
+
async get(url, options) { return this.fetch(url, { ...options, method: "GET" }); },
|
|
604
|
+
async post(url, options) { return this.fetch(url, { ...options, method: "POST" }); },
|
|
605
|
+
async put(url, options) { return this.fetch(url, { ...options, method: "PUT" }); },
|
|
606
|
+
async delete(url, options) { return this.fetch(url, { ...options, method: "DELETE" }); },
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
globalThis.IsolatePage = IsolatePage;
|
|
611
|
+
|
|
612
|
+
// IsolateContext class - represents a browser context with a specific contextId
|
|
613
|
+
class IsolateContext {
|
|
614
|
+
#contextId;
|
|
615
|
+
constructor(contextId) { this.#contextId = contextId; }
|
|
616
|
+
get __contextId() { return this.#contextId; }
|
|
617
|
+
|
|
618
|
+
async newPage() {
|
|
619
|
+
const result = await __pw_invoke("newPage", [], { contextId: this.#contextId });
|
|
620
|
+
return new IsolatePage(result.pageId, this.#contextId);
|
|
621
|
+
}
|
|
622
|
+
async close() { return __pw_invoke("closeContext", [], { contextId: this.#contextId }); }
|
|
623
|
+
async clearCookies() { return __pw_invoke("clearCookies", [], { contextId: this.#contextId }); }
|
|
624
|
+
async addCookies(cookies) { return __pw_invoke("addCookies", [cookies], { contextId: this.#contextId }); }
|
|
625
|
+
async cookies(urls) { return __pw_invoke("cookies", [urls], { contextId: this.#contextId }); }
|
|
626
|
+
}
|
|
627
|
+
globalThis.IsolateContext = IsolateContext;
|
|
628
|
+
|
|
629
|
+
// browser global - for creating new contexts
|
|
630
|
+
globalThis.browser = {
|
|
631
|
+
async newContext(options) {
|
|
632
|
+
const result = await __pw_invoke("newContext", [options || null]);
|
|
633
|
+
return new IsolateContext(result.contextId);
|
|
634
|
+
}
|
|
696
635
|
};
|
|
636
|
+
|
|
637
|
+
// context global - represents the default context
|
|
638
|
+
globalThis.context = new IsolateContext("ctx_0");
|
|
639
|
+
|
|
640
|
+
// page global - represents the default page
|
|
641
|
+
globalThis.page = new IsolatePage("page_0", "ctx_0");
|
|
697
642
|
})();
|
|
698
643
|
`);
|
|
699
644
|
context.evalSync(`
|
|
700
645
|
(function() {
|
|
646
|
+
// Helper to serialize options including RegExp
|
|
647
|
+
function serializeOptions(options) {
|
|
648
|
+
if (!options) return null;
|
|
649
|
+
const serialized = { ...options };
|
|
650
|
+
if (options.name && typeof options.name === 'object' && typeof options.name.source === 'string' && typeof options.name.flags === 'string') {
|
|
651
|
+
serialized.name = { $regex: options.name.source, $flags: options.name.flags };
|
|
652
|
+
}
|
|
653
|
+
return JSON.stringify(serialized);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
const INPUT_FILES_VALIDATION_ERROR =
|
|
657
|
+
"setInputFiles() expects a file path string, an array of file path strings, " +
|
|
658
|
+
"a single inline file object ({ name, mimeType, buffer }), or an array of inline file objects.";
|
|
659
|
+
|
|
660
|
+
function isInlineFileObject(value) {
|
|
661
|
+
return !!value
|
|
662
|
+
&& typeof value === 'object'
|
|
663
|
+
&& typeof value.name === 'string'
|
|
664
|
+
&& typeof value.mimeType === 'string'
|
|
665
|
+
&& 'buffer' in value;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
function encodeInlineFileBuffer(buffer) {
|
|
669
|
+
if (typeof buffer === 'string') {
|
|
670
|
+
return buffer;
|
|
671
|
+
}
|
|
672
|
+
let bytes;
|
|
673
|
+
if (buffer instanceof ArrayBuffer) {
|
|
674
|
+
bytes = new Uint8Array(buffer);
|
|
675
|
+
} else if (ArrayBuffer.isView(buffer)) {
|
|
676
|
+
bytes = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
677
|
+
} else {
|
|
678
|
+
throw new Error(
|
|
679
|
+
"setInputFiles() inline file buffer must be a base64 string, ArrayBuffer, or TypedArray."
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
let binary = '';
|
|
683
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
684
|
+
binary += String.fromCharCode(bytes[i]);
|
|
685
|
+
}
|
|
686
|
+
return btoa(binary);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
function serializeInlineFile(file) {
|
|
690
|
+
return {
|
|
691
|
+
name: file.name,
|
|
692
|
+
mimeType: file.mimeType,
|
|
693
|
+
buffer: encodeInlineFileBuffer(file.buffer),
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function normalizeSetInputFilesArg(files) {
|
|
698
|
+
if (typeof files === 'string') {
|
|
699
|
+
return files;
|
|
700
|
+
}
|
|
701
|
+
if (isInlineFileObject(files)) {
|
|
702
|
+
return serializeInlineFile(files);
|
|
703
|
+
}
|
|
704
|
+
if (!Array.isArray(files)) {
|
|
705
|
+
throw new Error(INPUT_FILES_VALIDATION_ERROR);
|
|
706
|
+
}
|
|
707
|
+
if (files.length === 0) {
|
|
708
|
+
return [];
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
let hasPaths = false;
|
|
712
|
+
let hasInline = false;
|
|
713
|
+
const inlineFiles = [];
|
|
714
|
+
|
|
715
|
+
for (const file of files) {
|
|
716
|
+
if (typeof file === 'string') {
|
|
717
|
+
hasPaths = true;
|
|
718
|
+
continue;
|
|
719
|
+
}
|
|
720
|
+
if (isInlineFileObject(file)) {
|
|
721
|
+
hasInline = true;
|
|
722
|
+
inlineFiles.push(serializeInlineFile(file));
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
throw new Error(INPUT_FILES_VALIDATION_ERROR);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
if (hasPaths && hasInline) {
|
|
729
|
+
throw new Error(
|
|
730
|
+
"setInputFiles() does not support mixing file paths and inline file objects in the same array."
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
return hasInline ? inlineFiles : files;
|
|
734
|
+
}
|
|
735
|
+
|
|
701
736
|
class Locator {
|
|
702
|
-
#type; #value; #options;
|
|
703
|
-
constructor(type, value, options) {
|
|
737
|
+
#type; #value; #options; #pageId;
|
|
738
|
+
constructor(type, value, options, pageId) {
|
|
704
739
|
this.#type = type;
|
|
705
740
|
this.#value = value;
|
|
706
741
|
this.#options = options;
|
|
742
|
+
this.#pageId = pageId || "page_0";
|
|
707
743
|
}
|
|
708
744
|
|
|
709
745
|
_getInfo() { return [this.#type, this.#value, this.#options]; }
|
|
746
|
+
_getPageId() { return this.#pageId; }
|
|
747
|
+
|
|
748
|
+
// Helper to create a chained locator
|
|
749
|
+
_chain(childType, childValue, childOptions) {
|
|
750
|
+
const parentInfo = this._getInfo();
|
|
751
|
+
const childInfo = [childType, childValue, childOptions];
|
|
752
|
+
return new Locator("chained", JSON.stringify([parentInfo, childInfo]), null, this.#pageId);
|
|
753
|
+
}
|
|
710
754
|
|
|
711
755
|
async click() {
|
|
712
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "click", null]);
|
|
756
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "click", null], { pageId: this.#pageId });
|
|
713
757
|
}
|
|
714
758
|
async dblclick() {
|
|
715
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "dblclick", null]);
|
|
759
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "dblclick", null], { pageId: this.#pageId });
|
|
716
760
|
}
|
|
717
761
|
async fill(text) {
|
|
718
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "fill", text]);
|
|
762
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "fill", text], { pageId: this.#pageId });
|
|
719
763
|
}
|
|
720
764
|
async type(text) {
|
|
721
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "type", text]);
|
|
765
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "type", text], { pageId: this.#pageId });
|
|
722
766
|
}
|
|
723
767
|
async check() {
|
|
724
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "check", null]);
|
|
768
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "check", null], { pageId: this.#pageId });
|
|
725
769
|
}
|
|
726
770
|
async uncheck() {
|
|
727
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "uncheck", null]);
|
|
771
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "uncheck", null], { pageId: this.#pageId });
|
|
728
772
|
}
|
|
729
773
|
async selectOption(value) {
|
|
730
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "selectOption", value]);
|
|
774
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "selectOption", value], { pageId: this.#pageId });
|
|
731
775
|
}
|
|
732
776
|
async clear() {
|
|
733
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "clear", null]);
|
|
777
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "clear", null], { pageId: this.#pageId });
|
|
734
778
|
}
|
|
735
779
|
async press(key) {
|
|
736
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "press", key]);
|
|
780
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "press", key], { pageId: this.#pageId });
|
|
737
781
|
}
|
|
738
782
|
async hover() {
|
|
739
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "hover", null]);
|
|
783
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "hover", null], { pageId: this.#pageId });
|
|
740
784
|
}
|
|
741
785
|
async focus() {
|
|
742
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "focus", null]);
|
|
786
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "focus", null], { pageId: this.#pageId });
|
|
743
787
|
}
|
|
744
788
|
async textContent() {
|
|
745
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "getText", null]);
|
|
789
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "getText", null], { pageId: this.#pageId });
|
|
746
790
|
}
|
|
747
791
|
async inputValue() {
|
|
748
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "getValue", null]);
|
|
792
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "getValue", null], { pageId: this.#pageId });
|
|
749
793
|
}
|
|
750
794
|
async isVisible() {
|
|
751
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "isVisible", null]);
|
|
795
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "isVisible", null], { pageId: this.#pageId });
|
|
752
796
|
}
|
|
753
797
|
async isEnabled() {
|
|
754
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "isEnabled", null]);
|
|
798
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "isEnabled", null], { pageId: this.#pageId });
|
|
755
799
|
}
|
|
756
800
|
async isChecked() {
|
|
757
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "isChecked", null]);
|
|
801
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "isChecked", null], { pageId: this.#pageId });
|
|
758
802
|
}
|
|
759
803
|
async count() {
|
|
760
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "count", null]);
|
|
804
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "count", null], { pageId: this.#pageId });
|
|
761
805
|
}
|
|
762
806
|
async getAttribute(name) {
|
|
763
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "getAttribute", name]);
|
|
807
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "getAttribute", name], { pageId: this.#pageId });
|
|
764
808
|
}
|
|
765
809
|
async isDisabled() {
|
|
766
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "isDisabled", null]);
|
|
810
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "isDisabled", null], { pageId: this.#pageId });
|
|
767
811
|
}
|
|
768
812
|
async isHidden() {
|
|
769
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "isHidden", null]);
|
|
813
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "isHidden", null], { pageId: this.#pageId });
|
|
770
814
|
}
|
|
771
815
|
async innerHTML() {
|
|
772
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "innerHTML", null]);
|
|
816
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "innerHTML", null], { pageId: this.#pageId });
|
|
773
817
|
}
|
|
774
818
|
async innerText() {
|
|
775
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "innerText", null]);
|
|
819
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "innerText", null], { pageId: this.#pageId });
|
|
776
820
|
}
|
|
777
821
|
async allTextContents() {
|
|
778
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "allTextContents", null]);
|
|
822
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "allTextContents", null], { pageId: this.#pageId });
|
|
779
823
|
}
|
|
780
824
|
async allInnerTexts() {
|
|
781
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "allInnerTexts", null]);
|
|
825
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "allInnerTexts", null], { pageId: this.#pageId });
|
|
782
826
|
}
|
|
783
827
|
async waitFor(options) {
|
|
784
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "waitFor", options || {}]);
|
|
828
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "waitFor", options || {}], { pageId: this.#pageId });
|
|
785
829
|
}
|
|
786
830
|
async boundingBox() {
|
|
787
|
-
return __pw_invoke("locatorAction", [...this._getInfo(), "boundingBox", null]);
|
|
831
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "boundingBox", null], { pageId: this.#pageId });
|
|
832
|
+
}
|
|
833
|
+
async setInputFiles(files) {
|
|
834
|
+
const serializedFiles = normalizeSetInputFilesArg(files);
|
|
835
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "setInputFiles", serializedFiles], { pageId: this.#pageId });
|
|
836
|
+
}
|
|
837
|
+
async screenshot(options) {
|
|
838
|
+
const base64 = await __pw_invoke("locatorAction", [...this._getInfo(), "screenshot", options || {}], { pageId: this.#pageId });
|
|
839
|
+
return base64;
|
|
840
|
+
}
|
|
841
|
+
async dragTo(target) {
|
|
842
|
+
const targetInfo = target._getInfo();
|
|
843
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "dragTo", targetInfo], { pageId: this.#pageId });
|
|
844
|
+
}
|
|
845
|
+
async scrollIntoViewIfNeeded() {
|
|
846
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "scrollIntoViewIfNeeded", null], { pageId: this.#pageId });
|
|
847
|
+
}
|
|
848
|
+
async highlight() {
|
|
849
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "highlight", null], { pageId: this.#pageId });
|
|
850
|
+
}
|
|
851
|
+
async evaluate(fn, arg) {
|
|
852
|
+
const fnString = typeof fn === 'function' ? fn.toString() : fn;
|
|
853
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "evaluate", [fnString, arg]], { pageId: this.#pageId });
|
|
854
|
+
}
|
|
855
|
+
async evaluateAll(fn, arg) {
|
|
856
|
+
const fnString = typeof fn === 'function' ? fn.toString() : fn;
|
|
857
|
+
return __pw_invoke("locatorAction", [...this._getInfo(), "evaluateAll", [fnString, arg]], { pageId: this.#pageId });
|
|
788
858
|
}
|
|
789
859
|
locator(selector) {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
860
|
+
return this._chain("css", selector, null);
|
|
861
|
+
}
|
|
862
|
+
// Chaining: getBy* methods within a locator
|
|
863
|
+
getByRole(role, options) {
|
|
864
|
+
return this._chain("role", role, serializeOptions(options));
|
|
865
|
+
}
|
|
866
|
+
getByText(text) {
|
|
867
|
+
return this._chain("text", text, null);
|
|
868
|
+
}
|
|
869
|
+
getByLabel(label) {
|
|
870
|
+
return this._chain("label", label, null);
|
|
871
|
+
}
|
|
872
|
+
getByPlaceholder(placeholder) {
|
|
873
|
+
return this._chain("placeholder", placeholder, null);
|
|
874
|
+
}
|
|
875
|
+
getByTestId(testId) {
|
|
876
|
+
return this._chain("testId", testId, null);
|
|
877
|
+
}
|
|
878
|
+
getByAltText(altText) {
|
|
879
|
+
return this._chain("altText", altText, null);
|
|
880
|
+
}
|
|
881
|
+
getByTitle(title) {
|
|
882
|
+
return this._chain("title", title, null);
|
|
796
883
|
}
|
|
797
884
|
async all() {
|
|
798
885
|
const n = await this.count();
|
|
@@ -804,7 +891,7 @@ async function setupPlaywright(context, options) {
|
|
|
804
891
|
}
|
|
805
892
|
nth(index) {
|
|
806
893
|
const existingOpts = this.#options ? JSON.parse(this.#options) : {};
|
|
807
|
-
return new Locator(this.#type, this.#value, JSON.stringify({ ...existingOpts, nth: index }));
|
|
894
|
+
return new Locator(this.#type, this.#value, JSON.stringify({ ...existingOpts, nth: index }), this.#pageId);
|
|
808
895
|
}
|
|
809
896
|
first() {
|
|
810
897
|
return this.nth(0);
|
|
@@ -824,13 +911,28 @@ async function setupPlaywright(context, options) {
|
|
|
824
911
|
if (hasNotText && typeof hasNotText === 'object' && typeof hasNotText.source === 'string' && typeof hasNotText.flags === 'string') {
|
|
825
912
|
serializedFilter.hasNotText = { $regex: hasNotText.source, $flags: hasNotText.flags };
|
|
826
913
|
}
|
|
827
|
-
|
|
914
|
+
// Serialize has/hasNot locators using duck-typing
|
|
915
|
+
const has = options.has;
|
|
916
|
+
if (has && typeof has === 'object' && typeof has._getInfo === 'function') {
|
|
917
|
+
serializedFilter.has = { $locator: has._getInfo() };
|
|
918
|
+
}
|
|
919
|
+
const hasNot = options.hasNot;
|
|
920
|
+
if (hasNot && typeof hasNot === 'object' && typeof hasNot._getInfo === 'function') {
|
|
921
|
+
serializedFilter.hasNot = { $locator: hasNot._getInfo() };
|
|
922
|
+
}
|
|
923
|
+
return new Locator(this.#type, this.#value, JSON.stringify({ ...existingOpts, filter: serializedFilter }), this.#pageId);
|
|
828
924
|
}
|
|
829
925
|
or(other) {
|
|
830
926
|
// Create a composite locator that matches either this or other
|
|
831
927
|
const thisInfo = this._getInfo();
|
|
832
928
|
const otherInfo = other._getInfo();
|
|
833
|
-
return new Locator("or", JSON.stringify([thisInfo, otherInfo]), null);
|
|
929
|
+
return new Locator("or", JSON.stringify([thisInfo, otherInfo]), null, this.#pageId);
|
|
930
|
+
}
|
|
931
|
+
and(other) {
|
|
932
|
+
// Create a composite locator that matches both this and other
|
|
933
|
+
const thisInfo = this._getInfo();
|
|
934
|
+
const otherInfo = other._getInfo();
|
|
935
|
+
return new Locator("and", JSON.stringify([thisInfo, otherInfo]), null, this.#pageId);
|
|
834
936
|
}
|
|
835
937
|
}
|
|
836
938
|
globalThis.Locator = Locator;
|
|
@@ -841,84 +943,157 @@ async function setupPlaywright(context, options) {
|
|
|
841
943
|
// Helper to create locator matchers
|
|
842
944
|
function createLocatorMatchers(locator, baseMatchers) {
|
|
843
945
|
const info = locator._getInfo();
|
|
946
|
+
const pageId = locator._getPageId ? locator._getPageId() : "page_0";
|
|
947
|
+
|
|
948
|
+
// Helper for serializing regex values
|
|
949
|
+
function serializeExpected(expected) {
|
|
950
|
+
if (expected instanceof RegExp) {
|
|
951
|
+
return { $regex: expected.source, $flags: expected.flags };
|
|
952
|
+
}
|
|
953
|
+
return expected;
|
|
954
|
+
}
|
|
844
955
|
|
|
845
956
|
const locatorMatchers = {
|
|
846
957
|
async toBeVisible(options) {
|
|
847
|
-
return __pw_invoke("expectLocator", [...info, "toBeVisible", null, false, options?.timeout]);
|
|
958
|
+
return __pw_invoke("expectLocator", [...info, "toBeVisible", null, false, options?.timeout], { pageId });
|
|
848
959
|
},
|
|
849
960
|
async toContainText(expected, options) {
|
|
850
|
-
|
|
851
|
-
return __pw_invoke("expectLocator", [...info, "toContainText", serialized, false, options?.timeout]);
|
|
961
|
+
return __pw_invoke("expectLocator", [...info, "toContainText", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
852
962
|
},
|
|
853
963
|
async toHaveValue(expected, options) {
|
|
854
|
-
return __pw_invoke("expectLocator", [...info, "toHaveValue", expected, false, options?.timeout]);
|
|
964
|
+
return __pw_invoke("expectLocator", [...info, "toHaveValue", expected, false, options?.timeout], { pageId });
|
|
855
965
|
},
|
|
856
966
|
async toBeEnabled(options) {
|
|
857
|
-
return __pw_invoke("expectLocator", [...info, "toBeEnabled", null, false, options?.timeout]);
|
|
967
|
+
return __pw_invoke("expectLocator", [...info, "toBeEnabled", null, false, options?.timeout], { pageId });
|
|
858
968
|
},
|
|
859
969
|
async toBeChecked(options) {
|
|
860
|
-
return __pw_invoke("expectLocator", [...info, "toBeChecked", null, false, options?.timeout]);
|
|
970
|
+
return __pw_invoke("expectLocator", [...info, "toBeChecked", null, false, options?.timeout], { pageId });
|
|
861
971
|
},
|
|
862
972
|
async toHaveAttribute(name, value, options) {
|
|
863
|
-
return __pw_invoke("expectLocator", [...info, "toHaveAttribute", { name, value }, false, options?.timeout]);
|
|
973
|
+
return __pw_invoke("expectLocator", [...info, "toHaveAttribute", { name, value: serializeExpected(value) }, false, options?.timeout], { pageId });
|
|
864
974
|
},
|
|
865
975
|
async toHaveText(expected, options) {
|
|
866
|
-
|
|
867
|
-
return __pw_invoke("expectLocator", [...info, "toHaveText", serialized, false, options?.timeout]);
|
|
976
|
+
return __pw_invoke("expectLocator", [...info, "toHaveText", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
868
977
|
},
|
|
869
978
|
async toHaveCount(count, options) {
|
|
870
|
-
return __pw_invoke("expectLocator", [...info, "toHaveCount", count, false, options?.timeout]);
|
|
979
|
+
return __pw_invoke("expectLocator", [...info, "toHaveCount", count, false, options?.timeout], { pageId });
|
|
871
980
|
},
|
|
872
981
|
async toBeHidden(options) {
|
|
873
|
-
return __pw_invoke("expectLocator", [...info, "toBeHidden", null, false, options?.timeout]);
|
|
982
|
+
return __pw_invoke("expectLocator", [...info, "toBeHidden", null, false, options?.timeout], { pageId });
|
|
874
983
|
},
|
|
875
984
|
async toBeDisabled(options) {
|
|
876
|
-
return __pw_invoke("expectLocator", [...info, "toBeDisabled", null, false, options?.timeout]);
|
|
985
|
+
return __pw_invoke("expectLocator", [...info, "toBeDisabled", null, false, options?.timeout], { pageId });
|
|
877
986
|
},
|
|
878
987
|
async toBeFocused(options) {
|
|
879
|
-
return __pw_invoke("expectLocator", [...info, "toBeFocused", null, false, options?.timeout]);
|
|
988
|
+
return __pw_invoke("expectLocator", [...info, "toBeFocused", null, false, options?.timeout], { pageId });
|
|
880
989
|
},
|
|
881
990
|
async toBeEmpty(options) {
|
|
882
|
-
return __pw_invoke("expectLocator", [...info, "toBeEmpty", null, false, options?.timeout]);
|
|
991
|
+
return __pw_invoke("expectLocator", [...info, "toBeEmpty", null, false, options?.timeout], { pageId });
|
|
992
|
+
},
|
|
993
|
+
// New matchers
|
|
994
|
+
async toBeAttached(options) {
|
|
995
|
+
return __pw_invoke("expectLocator", [...info, "toBeAttached", null, false, options?.timeout], { pageId });
|
|
996
|
+
},
|
|
997
|
+
async toBeEditable(options) {
|
|
998
|
+
return __pw_invoke("expectLocator", [...info, "toBeEditable", null, false, options?.timeout], { pageId });
|
|
999
|
+
},
|
|
1000
|
+
async toHaveClass(expected, options) {
|
|
1001
|
+
return __pw_invoke("expectLocator", [...info, "toHaveClass", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
1002
|
+
},
|
|
1003
|
+
async toContainClass(expected, options) {
|
|
1004
|
+
return __pw_invoke("expectLocator", [...info, "toContainClass", expected, false, options?.timeout], { pageId });
|
|
1005
|
+
},
|
|
1006
|
+
async toHaveId(expected, options) {
|
|
1007
|
+
return __pw_invoke("expectLocator", [...info, "toHaveId", expected, false, options?.timeout], { pageId });
|
|
1008
|
+
},
|
|
1009
|
+
async toBeInViewport(options) {
|
|
1010
|
+
return __pw_invoke("expectLocator", [...info, "toBeInViewport", null, false, options?.timeout], { pageId });
|
|
1011
|
+
},
|
|
1012
|
+
async toHaveCSS(name, value, options) {
|
|
1013
|
+
return __pw_invoke("expectLocator", [...info, "toHaveCSS", { name, value: serializeExpected(value) }, false, options?.timeout], { pageId });
|
|
1014
|
+
},
|
|
1015
|
+
async toHaveJSProperty(name, value, options) {
|
|
1016
|
+
return __pw_invoke("expectLocator", [...info, "toHaveJSProperty", { name, value }, false, options?.timeout], { pageId });
|
|
1017
|
+
},
|
|
1018
|
+
async toHaveAccessibleName(expected, options) {
|
|
1019
|
+
return __pw_invoke("expectLocator", [...info, "toHaveAccessibleName", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
1020
|
+
},
|
|
1021
|
+
async toHaveAccessibleDescription(expected, options) {
|
|
1022
|
+
return __pw_invoke("expectLocator", [...info, "toHaveAccessibleDescription", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
1023
|
+
},
|
|
1024
|
+
async toHaveRole(expected, options) {
|
|
1025
|
+
return __pw_invoke("expectLocator", [...info, "toHaveRole", expected, false, options?.timeout], { pageId });
|
|
883
1026
|
},
|
|
884
1027
|
not: {
|
|
885
1028
|
async toBeVisible(options) {
|
|
886
|
-
return __pw_invoke("expectLocator", [...info, "toBeVisible", null, true, options?.timeout]);
|
|
1029
|
+
return __pw_invoke("expectLocator", [...info, "toBeVisible", null, true, options?.timeout], { pageId });
|
|
887
1030
|
},
|
|
888
1031
|
async toContainText(expected, options) {
|
|
889
|
-
|
|
890
|
-
return __pw_invoke("expectLocator", [...info, "toContainText", serialized, true, options?.timeout]);
|
|
1032
|
+
return __pw_invoke("expectLocator", [...info, "toContainText", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
891
1033
|
},
|
|
892
1034
|
async toHaveValue(expected, options) {
|
|
893
|
-
return __pw_invoke("expectLocator", [...info, "toHaveValue", expected, true, options?.timeout]);
|
|
1035
|
+
return __pw_invoke("expectLocator", [...info, "toHaveValue", expected, true, options?.timeout], { pageId });
|
|
894
1036
|
},
|
|
895
1037
|
async toBeEnabled(options) {
|
|
896
|
-
return __pw_invoke("expectLocator", [...info, "toBeEnabled", null, true, options?.timeout]);
|
|
1038
|
+
return __pw_invoke("expectLocator", [...info, "toBeEnabled", null, true, options?.timeout], { pageId });
|
|
897
1039
|
},
|
|
898
1040
|
async toBeChecked(options) {
|
|
899
|
-
return __pw_invoke("expectLocator", [...info, "toBeChecked", null, true, options?.timeout]);
|
|
1041
|
+
return __pw_invoke("expectLocator", [...info, "toBeChecked", null, true, options?.timeout], { pageId });
|
|
900
1042
|
},
|
|
901
1043
|
async toHaveAttribute(name, value, options) {
|
|
902
|
-
return __pw_invoke("expectLocator", [...info, "toHaveAttribute", { name, value }, true, options?.timeout]);
|
|
1044
|
+
return __pw_invoke("expectLocator", [...info, "toHaveAttribute", { name, value: serializeExpected(value) }, true, options?.timeout], { pageId });
|
|
903
1045
|
},
|
|
904
1046
|
async toHaveText(expected, options) {
|
|
905
|
-
|
|
906
|
-
return __pw_invoke("expectLocator", [...info, "toHaveText", serialized, true, options?.timeout]);
|
|
1047
|
+
return __pw_invoke("expectLocator", [...info, "toHaveText", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
907
1048
|
},
|
|
908
1049
|
async toHaveCount(count, options) {
|
|
909
|
-
return __pw_invoke("expectLocator", [...info, "toHaveCount", count, true, options?.timeout]);
|
|
1050
|
+
return __pw_invoke("expectLocator", [...info, "toHaveCount", count, true, options?.timeout], { pageId });
|
|
910
1051
|
},
|
|
911
1052
|
async toBeHidden(options) {
|
|
912
|
-
return __pw_invoke("expectLocator", [...info, "toBeHidden", null, true, options?.timeout]);
|
|
1053
|
+
return __pw_invoke("expectLocator", [...info, "toBeHidden", null, true, options?.timeout], { pageId });
|
|
913
1054
|
},
|
|
914
1055
|
async toBeDisabled(options) {
|
|
915
|
-
return __pw_invoke("expectLocator", [...info, "toBeDisabled", null, true, options?.timeout]);
|
|
1056
|
+
return __pw_invoke("expectLocator", [...info, "toBeDisabled", null, true, options?.timeout], { pageId });
|
|
916
1057
|
},
|
|
917
1058
|
async toBeFocused(options) {
|
|
918
|
-
return __pw_invoke("expectLocator", [...info, "toBeFocused", null, true, options?.timeout]);
|
|
1059
|
+
return __pw_invoke("expectLocator", [...info, "toBeFocused", null, true, options?.timeout], { pageId });
|
|
919
1060
|
},
|
|
920
1061
|
async toBeEmpty(options) {
|
|
921
|
-
return __pw_invoke("expectLocator", [...info, "toBeEmpty", null, true, options?.timeout]);
|
|
1062
|
+
return __pw_invoke("expectLocator", [...info, "toBeEmpty", null, true, options?.timeout], { pageId });
|
|
1063
|
+
},
|
|
1064
|
+
// New negated matchers
|
|
1065
|
+
async toBeAttached(options) {
|
|
1066
|
+
return __pw_invoke("expectLocator", [...info, "toBeAttached", null, true, options?.timeout], { pageId });
|
|
1067
|
+
},
|
|
1068
|
+
async toBeEditable(options) {
|
|
1069
|
+
return __pw_invoke("expectLocator", [...info, "toBeEditable", null, true, options?.timeout], { pageId });
|
|
1070
|
+
},
|
|
1071
|
+
async toHaveClass(expected, options) {
|
|
1072
|
+
return __pw_invoke("expectLocator", [...info, "toHaveClass", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
1073
|
+
},
|
|
1074
|
+
async toContainClass(expected, options) {
|
|
1075
|
+
return __pw_invoke("expectLocator", [...info, "toContainClass", expected, true, options?.timeout], { pageId });
|
|
1076
|
+
},
|
|
1077
|
+
async toHaveId(expected, options) {
|
|
1078
|
+
return __pw_invoke("expectLocator", [...info, "toHaveId", expected, true, options?.timeout], { pageId });
|
|
1079
|
+
},
|
|
1080
|
+
async toBeInViewport(options) {
|
|
1081
|
+
return __pw_invoke("expectLocator", [...info, "toBeInViewport", null, true, options?.timeout], { pageId });
|
|
1082
|
+
},
|
|
1083
|
+
async toHaveCSS(name, value, options) {
|
|
1084
|
+
return __pw_invoke("expectLocator", [...info, "toHaveCSS", { name, value: serializeExpected(value) }, true, options?.timeout], { pageId });
|
|
1085
|
+
},
|
|
1086
|
+
async toHaveJSProperty(name, value, options) {
|
|
1087
|
+
return __pw_invoke("expectLocator", [...info, "toHaveJSProperty", { name, value }, true, options?.timeout], { pageId });
|
|
1088
|
+
},
|
|
1089
|
+
async toHaveAccessibleName(expected, options) {
|
|
1090
|
+
return __pw_invoke("expectLocator", [...info, "toHaveAccessibleName", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
1091
|
+
},
|
|
1092
|
+
async toHaveAccessibleDescription(expected, options) {
|
|
1093
|
+
return __pw_invoke("expectLocator", [...info, "toHaveAccessibleDescription", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
1094
|
+
},
|
|
1095
|
+
async toHaveRole(expected, options) {
|
|
1096
|
+
return __pw_invoke("expectLocator", [...info, "toHaveRole", expected, true, options?.timeout], { pageId });
|
|
922
1097
|
},
|
|
923
1098
|
}
|
|
924
1099
|
};
|
|
@@ -934,6 +1109,44 @@ async function setupPlaywright(context, options) {
|
|
|
934
1109
|
return locatorMatchers;
|
|
935
1110
|
}
|
|
936
1111
|
|
|
1112
|
+
// Helper to create page matchers
|
|
1113
|
+
function createPageMatchers(page, baseMatchers) {
|
|
1114
|
+
const pageId = page.__pageId || "page_0";
|
|
1115
|
+
|
|
1116
|
+
function serializeExpected(expected) {
|
|
1117
|
+
if (expected instanceof RegExp) {
|
|
1118
|
+
return { $regex: expected.source, $flags: expected.flags };
|
|
1119
|
+
}
|
|
1120
|
+
return expected;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
const pageMatchers = {
|
|
1124
|
+
async toHaveURL(expected, options) {
|
|
1125
|
+
return __pw_invoke("expectPage", ["toHaveURL", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
1126
|
+
},
|
|
1127
|
+
async toHaveTitle(expected, options) {
|
|
1128
|
+
return __pw_invoke("expectPage", ["toHaveTitle", serializeExpected(expected), false, options?.timeout], { pageId });
|
|
1129
|
+
},
|
|
1130
|
+
not: {
|
|
1131
|
+
async toHaveURL(expected, options) {
|
|
1132
|
+
return __pw_invoke("expectPage", ["toHaveURL", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
1133
|
+
},
|
|
1134
|
+
async toHaveTitle(expected, options) {
|
|
1135
|
+
return __pw_invoke("expectPage", ["toHaveTitle", serializeExpected(expected), true, options?.timeout], { pageId });
|
|
1136
|
+
},
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
1139
|
+
|
|
1140
|
+
if (baseMatchers) {
|
|
1141
|
+
return {
|
|
1142
|
+
...baseMatchers,
|
|
1143
|
+
...pageMatchers,
|
|
1144
|
+
not: { ...baseMatchers.not, ...pageMatchers.not }
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
return pageMatchers;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
937
1150
|
// Only extend expect if test-environment already defined it
|
|
938
1151
|
if (typeof globalThis.expect === 'function') {
|
|
939
1152
|
const originalExpect = globalThis.expect;
|
|
@@ -943,6 +1156,10 @@ async function setupPlaywright(context, options) {
|
|
|
943
1156
|
if (actual && actual.constructor && actual.constructor.name === 'Locator') {
|
|
944
1157
|
return createLocatorMatchers(actual, baseMatchers);
|
|
945
1158
|
}
|
|
1159
|
+
// If actual is the page object (IsolatePage), add page-specific matchers
|
|
1160
|
+
if (actual && actual.__isPage === true) {
|
|
1161
|
+
return createPageMatchers(actual, baseMatchers);
|
|
1162
|
+
}
|
|
946
1163
|
return baseMatchers;
|
|
947
1164
|
};
|
|
948
1165
|
}
|
|
@@ -977,4 +1194,4 @@ async function setupPlaywright(context, options) {
|
|
|
977
1194
|
};
|
|
978
1195
|
}
|
|
979
1196
|
|
|
980
|
-
//# debugId=
|
|
1197
|
+
//# debugId=2C9A0105748F8D9364756E2164756E21
|