@ricsam/isolate-playwright 0.1.2 → 0.1.5

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.
@@ -44,418 +44,393 @@ var __export = (target, all) => {
44
44
  var exports_src = {};
45
45
  __export(exports_src, {
46
46
  setupPlaywright: () => setupPlaywright,
47
- runPlaywrightTests: () => runPlaywrightTests,
48
- resetPlaywrightTests: () => resetPlaywrightTests
47
+ createPlaywrightHandler: () => createPlaywrightHandler
49
48
  });
50
49
  module.exports = __toCommonJS(exports_src);
51
50
  var import_isolated_vm = __toESM(require("isolated-vm"));
52
- var KNOWN_ERROR_TYPES = [
53
- "TypeError",
54
- "RangeError",
55
- "SyntaxError",
56
- "ReferenceError",
57
- "URIError",
58
- "EvalError",
59
- "TimeoutError"
60
- ];
61
- function getErrorConstructorName(errorType) {
62
- return KNOWN_ERROR_TYPES.includes(errorType) ? errorType : "Error";
63
- }
64
- function encodeErrorForTransfer(err) {
65
- const errorType = getErrorConstructorName(err.name);
66
- return new Error(`[${errorType}]${err.message}`);
67
- }
68
- var DECODE_ERROR_JS = `
69
- function __decodeError(err) {
70
- if (!(err instanceof Error)) return err;
71
- const match = err.message.match(/^\\[(TypeError|RangeError|SyntaxError|ReferenceError|URIError|EvalError|TimeoutError|Error)\\](.*)$/);
72
- if (match) {
73
- const ErrorType = globalThis[match[1]] || Error;
74
- return new ErrorType(match[2]);
51
+ function getLocator(page, selectorType, selectorValue, optionsJson) {
52
+ const options = optionsJson ? JSON.parse(optionsJson) : undefined;
53
+ const nthIndex = options?.nth;
54
+ const roleOptions = options ? { ...options } : undefined;
55
+ if (roleOptions) {
56
+ delete roleOptions.nth;
75
57
  }
76
- return err;
77
- }
78
- `.trim();
79
- function getLocator(page, selectorType, selectorValue, roleOptionsJson) {
58
+ let locator;
80
59
  switch (selectorType) {
81
60
  case "css":
82
- return page.locator(selectorValue);
83
- case "role": {
84
- const roleOptions = roleOptionsJson ? JSON.parse(roleOptionsJson) : undefined;
85
- return page.getByRole(selectorValue, roleOptions);
86
- }
61
+ locator = page.locator(selectorValue);
62
+ break;
63
+ case "role":
64
+ locator = page.getByRole(selectorValue, roleOptions && Object.keys(roleOptions).length > 0 ? roleOptions : undefined);
65
+ break;
87
66
  case "text":
88
- return page.getByText(selectorValue);
67
+ locator = page.getByText(selectorValue);
68
+ break;
89
69
  case "label":
90
- return page.getByLabel(selectorValue);
70
+ locator = page.getByLabel(selectorValue);
71
+ break;
91
72
  case "placeholder":
92
- return page.getByPlaceholder(selectorValue);
73
+ locator = page.getByPlaceholder(selectorValue);
74
+ break;
93
75
  case "testId":
94
- return page.getByTestId(selectorValue);
76
+ locator = page.getByTestId(selectorValue);
77
+ break;
95
78
  default:
96
- return page.locator(selectorValue);
79
+ locator = page.locator(selectorValue);
80
+ }
81
+ if (nthIndex !== undefined) {
82
+ locator = locator.nth(nthIndex);
97
83
  }
84
+ return locator;
98
85
  }
99
- async function setupPlaywright(context, options) {
100
- const { page, timeout = 30000, baseUrl } = options;
101
- const consoleLogs = [];
102
- const networkRequests = [];
103
- const networkResponses = [];
104
- const global = context.global;
105
- const requestHandler = (request) => {
106
- const info = {
107
- url: request.url(),
108
- method: request.method(),
109
- headers: request.headers(),
110
- postData: request.postData() ?? undefined,
111
- resourceType: request.resourceType(),
112
- timestamp: Date.now()
113
- };
114
- networkRequests.push(info);
115
- options.onNetworkRequest?.(info);
116
- };
117
- const responseHandler = (response) => {
118
- const info = {
119
- url: response.url(),
120
- status: response.status(),
121
- statusText: response.statusText(),
122
- headers: response.headers(),
123
- timestamp: Date.now()
124
- };
125
- networkResponses.push(info);
126
- options.onNetworkResponse?.(info);
127
- };
128
- const consoleHandler = (msg) => {
129
- const entry = {
130
- level: msg.type(),
131
- args: msg.args().map((arg) => String(arg)),
132
- timestamp: Date.now()
133
- };
134
- consoleLogs.push(entry);
135
- options.onConsoleLog?.(entry.level, ...entry.args);
136
- };
137
- page.on("request", requestHandler);
138
- page.on("response", responseHandler);
139
- page.on("console", consoleHandler);
140
- global.setSync("__Playwright_goto_ref", new import_isolated_vm.default.Reference(async (url, waitUntil) => {
141
- try {
142
- const targetUrl = baseUrl && !url.startsWith("http") ? `${baseUrl}${url}` : url;
143
- await page.goto(targetUrl, {
144
- timeout,
145
- waitUntil: waitUntil ?? "load"
146
- });
147
- } catch (err) {
148
- if (err instanceof Error) {
149
- throw encodeErrorForTransfer(err);
150
- }
151
- throw err;
152
- }
153
- }));
154
- global.setSync("__Playwright_reload_ref", new import_isolated_vm.default.Reference(async () => {
155
- try {
156
- await page.reload({ timeout });
157
- } catch (err) {
158
- if (err instanceof Error) {
159
- throw encodeErrorForTransfer(err);
160
- }
161
- throw err;
162
- }
163
- }));
164
- global.setSync("__Playwright_url", new import_isolated_vm.default.Callback(() => {
165
- return page.url();
166
- }));
167
- global.setSync("__Playwright_title_ref", new import_isolated_vm.default.Reference(async () => {
168
- try {
169
- return await page.title();
170
- } catch (err) {
171
- if (err instanceof Error) {
172
- throw encodeErrorForTransfer(err);
173
- }
174
- throw err;
175
- }
176
- }));
177
- global.setSync("__Playwright_content_ref", new import_isolated_vm.default.Reference(async () => {
178
- try {
179
- return await page.content();
180
- } catch (err) {
181
- if (err instanceof Error) {
182
- throw encodeErrorForTransfer(err);
183
- }
184
- throw err;
185
- }
186
- }));
187
- global.setSync("__Playwright_waitForSelector_ref", new import_isolated_vm.default.Reference(async (selector, optionsJson) => {
188
- try {
189
- const opts = optionsJson ? JSON.parse(optionsJson) : {};
190
- await page.waitForSelector(selector, { timeout, ...opts });
191
- } catch (err) {
192
- if (err instanceof Error) {
193
- throw encodeErrorForTransfer(err);
194
- }
195
- throw err;
196
- }
197
- }));
198
- global.setSync("__Playwright_waitForTimeout_ref", new import_isolated_vm.default.Reference(async (ms) => {
199
- try {
200
- await page.waitForTimeout(ms);
201
- } catch (err) {
202
- if (err instanceof Error) {
203
- throw encodeErrorForTransfer(err);
204
- }
205
- throw err;
206
- }
207
- }));
208
- global.setSync("__Playwright_waitForLoadState_ref", new import_isolated_vm.default.Reference(async (state) => {
209
- try {
210
- await page.waitForLoadState(state ?? "load", { timeout });
211
- } catch (err) {
212
- if (err instanceof Error) {
213
- throw encodeErrorForTransfer(err);
214
- }
215
- throw err;
216
- }
217
- }));
218
- global.setSync("__Playwright_evaluate_ref", new import_isolated_vm.default.Reference(async (script) => {
219
- try {
220
- const result = await page.evaluate(script);
221
- return JSON.stringify(result);
222
- } catch (err) {
223
- if (err instanceof Error) {
224
- throw encodeErrorForTransfer(err);
225
- }
226
- throw err;
227
- }
228
- }));
229
- global.setSync("__Playwright_locatorAction_ref", new import_isolated_vm.default.Reference(async (selectorType, selectorValue, roleOptionsJson, action, actionArg) => {
230
- try {
231
- const locator = getLocator(page, selectorType, selectorValue, roleOptionsJson);
232
- switch (action) {
233
- case "click":
234
- await locator.click({ timeout });
235
- return null;
236
- case "dblclick":
237
- await locator.dblclick({ timeout });
238
- return null;
239
- case "fill":
240
- await locator.fill(actionArg ?? "", { timeout });
241
- return null;
242
- case "type":
243
- await locator.pressSequentially(actionArg ?? "", { timeout });
244
- return null;
245
- case "check":
246
- await locator.check({ timeout });
247
- return null;
248
- case "uncheck":
249
- await locator.uncheck({ timeout });
250
- return null;
251
- case "selectOption":
252
- await locator.selectOption(actionArg ?? "", { timeout });
253
- return null;
254
- case "clear":
255
- await locator.clear({ timeout });
256
- return null;
257
- case "press":
258
- await locator.press(actionArg ?? "", { timeout });
259
- return null;
260
- case "hover":
261
- await locator.hover({ timeout });
262
- return null;
263
- case "focus":
264
- await locator.focus({ timeout });
265
- return null;
266
- case "getText":
267
- return await locator.textContent({ timeout });
268
- case "getValue":
269
- return await locator.inputValue({ timeout });
270
- case "isVisible":
271
- return await locator.isVisible();
272
- case "isEnabled":
273
- return await locator.isEnabled();
274
- case "isChecked":
275
- return await locator.isChecked();
276
- case "count":
277
- return await locator.count();
278
- default:
279
- throw new Error(`Unknown action: ${action}`);
280
- }
281
- } catch (err) {
282
- if (err instanceof Error) {
283
- throw encodeErrorForTransfer(err);
284
- }
285
- throw err;
286
- }
287
- }));
288
- global.setSync("__Playwright_expectVisible_ref", new import_isolated_vm.default.Reference(async (selectorType, selectorValue, roleOptionsJson, not) => {
289
- try {
290
- const locator = getLocator(page, selectorType, selectorValue, roleOptionsJson);
86
+ async function executeLocatorAction(locator, action, actionArg, timeout) {
87
+ switch (action) {
88
+ case "click":
89
+ await locator.click({ timeout });
90
+ return null;
91
+ case "dblclick":
92
+ await locator.dblclick({ timeout });
93
+ return null;
94
+ case "fill":
95
+ await locator.fill(String(actionArg ?? ""), { timeout });
96
+ return null;
97
+ case "type":
98
+ await locator.pressSequentially(String(actionArg ?? ""), { timeout });
99
+ return null;
100
+ case "check":
101
+ await locator.check({ timeout });
102
+ return null;
103
+ case "uncheck":
104
+ await locator.uncheck({ timeout });
105
+ return null;
106
+ case "selectOption":
107
+ await locator.selectOption(String(actionArg ?? ""), { timeout });
108
+ return null;
109
+ case "clear":
110
+ await locator.clear({ timeout });
111
+ return null;
112
+ case "press":
113
+ await locator.press(String(actionArg ?? ""), { timeout });
114
+ return null;
115
+ case "hover":
116
+ await locator.hover({ timeout });
117
+ return null;
118
+ case "focus":
119
+ await locator.focus({ timeout });
120
+ return null;
121
+ case "getText":
122
+ return await locator.textContent({ timeout });
123
+ case "getValue":
124
+ return await locator.inputValue({ timeout });
125
+ case "isVisible":
126
+ return await locator.isVisible();
127
+ case "isEnabled":
128
+ return await locator.isEnabled();
129
+ case "isChecked":
130
+ return await locator.isChecked();
131
+ case "count":
132
+ return await locator.count();
133
+ default:
134
+ throw new Error(`Unknown action: ${action}`);
135
+ }
136
+ }
137
+ async function executeExpectAssertion(locator, matcher, expected, negated, timeout) {
138
+ switch (matcher) {
139
+ case "toBeVisible": {
291
140
  const isVisible = await locator.isVisible();
292
- if (not) {
293
- if (isVisible) {
294
- throw new Error(`Expected element to not be visible, but it was visible`);
295
- }
141
+ if (negated) {
142
+ if (isVisible)
143
+ throw new Error("Expected element to not be visible, but it was visible");
296
144
  } else {
297
- if (!isVisible) {
298
- throw new Error(`Expected element to be visible, but it was not`);
299
- }
300
- }
301
- } catch (err) {
302
- if (err instanceof Error) {
303
- throw encodeErrorForTransfer(err);
145
+ if (!isVisible)
146
+ throw new Error("Expected element to be visible, but it was not");
304
147
  }
305
- throw err;
148
+ break;
306
149
  }
307
- }));
308
- global.setSync("__Playwright_expectText_ref", new import_isolated_vm.default.Reference(async (selectorType, selectorValue, roleOptionsJson, expected, not) => {
309
- try {
310
- const locator = getLocator(page, selectorType, selectorValue, roleOptionsJson);
150
+ case "toContainText": {
311
151
  const text = await locator.textContent({ timeout });
312
- const matches = text?.includes(expected) ?? false;
313
- if (not) {
314
- if (matches) {
152
+ const matches = text?.includes(String(expected)) ?? false;
153
+ if (negated) {
154
+ if (matches)
315
155
  throw new Error(`Expected text to not contain "${expected}", but got "${text}"`);
316
- }
317
156
  } else {
318
- if (!matches) {
157
+ if (!matches)
319
158
  throw new Error(`Expected text to contain "${expected}", but got "${text}"`);
320
- }
321
- }
322
- } catch (err) {
323
- if (err instanceof Error) {
324
- throw encodeErrorForTransfer(err);
325
159
  }
326
- throw err;
160
+ break;
327
161
  }
328
- }));
329
- global.setSync("__Playwright_expectValue_ref", new import_isolated_vm.default.Reference(async (selectorType, selectorValue, roleOptionsJson, expected, not) => {
330
- try {
331
- const locator = getLocator(page, selectorType, selectorValue, roleOptionsJson);
162
+ case "toHaveValue": {
332
163
  const value = await locator.inputValue({ timeout });
333
- const matches = value === expected;
334
- if (not) {
335
- if (matches) {
164
+ const matches = value === String(expected);
165
+ if (negated) {
166
+ if (matches)
336
167
  throw new Error(`Expected value to not be "${expected}", but it was`);
337
- }
338
168
  } else {
339
- if (!matches) {
169
+ if (!matches)
340
170
  throw new Error(`Expected value to be "${expected}", but got "${value}"`);
341
- }
342
- }
343
- } catch (err) {
344
- if (err instanceof Error) {
345
- throw encodeErrorForTransfer(err);
346
171
  }
347
- throw err;
172
+ break;
348
173
  }
349
- }));
350
- global.setSync("__Playwright_expectEnabled_ref", new import_isolated_vm.default.Reference(async (selectorType, selectorValue, roleOptionsJson, not) => {
351
- try {
352
- const locator = getLocator(page, selectorType, selectorValue, roleOptionsJson);
174
+ case "toBeEnabled": {
353
175
  const isEnabled = await locator.isEnabled();
354
- if (not) {
355
- if (isEnabled) {
356
- throw new Error(`Expected element to be disabled, but it was enabled`);
357
- }
176
+ if (negated) {
177
+ if (isEnabled)
178
+ throw new Error("Expected element to be disabled, but it was enabled");
358
179
  } else {
359
- if (!isEnabled) {
360
- throw new Error(`Expected element to be enabled, but it was disabled`);
361
- }
180
+ if (!isEnabled)
181
+ throw new Error("Expected element to be enabled, but it was disabled");
362
182
  }
363
- } catch (err) {
364
- if (err instanceof Error) {
365
- throw encodeErrorForTransfer(err);
183
+ break;
184
+ }
185
+ case "toBeChecked": {
186
+ const isChecked = await locator.isChecked();
187
+ if (negated) {
188
+ if (isChecked)
189
+ throw new Error("Expected element to not be checked, but it was checked");
190
+ } else {
191
+ if (!isChecked)
192
+ throw new Error("Expected element to be checked, but it was not");
366
193
  }
367
- throw err;
194
+ break;
368
195
  }
369
- }));
370
- global.setSync("__Playwright_expectChecked_ref", new import_isolated_vm.default.Reference(async (selectorType, selectorValue, roleOptionsJson, not) => {
196
+ default:
197
+ throw new Error(`Unknown matcher: ${matcher}`);
198
+ }
199
+ }
200
+ function createPlaywrightHandler(page, options) {
201
+ const timeout = options?.timeout ?? 30000;
202
+ const baseUrl = options?.baseUrl;
203
+ return async (op) => {
371
204
  try {
372
- const locator = getLocator(page, selectorType, selectorValue, roleOptionsJson);
373
- const isChecked = await locator.isChecked();
374
- if (not) {
375
- if (isChecked) {
376
- throw new Error(`Expected element to not be checked, but it was checked`);
205
+ switch (op.type) {
206
+ case "goto": {
207
+ const [url, waitUntil] = op.args;
208
+ const targetUrl = baseUrl && !url.startsWith("http") ? `${baseUrl}${url}` : url;
209
+ await page.goto(targetUrl, {
210
+ timeout,
211
+ waitUntil: waitUntil ?? "load"
212
+ });
213
+ return { ok: true };
377
214
  }
378
- } else {
379
- if (!isChecked) {
380
- throw new Error(`Expected element to be checked, but it was not`);
215
+ case "reload":
216
+ await page.reload({ timeout });
217
+ return { ok: true };
218
+ case "url":
219
+ return { ok: true, value: page.url() };
220
+ case "title":
221
+ return { ok: true, value: await page.title() };
222
+ case "content":
223
+ return { ok: true, value: await page.content() };
224
+ case "waitForSelector": {
225
+ const [selector, optionsJson] = op.args;
226
+ const opts = optionsJson ? JSON.parse(optionsJson) : {};
227
+ await page.waitForSelector(selector, { timeout, ...opts });
228
+ return { ok: true };
229
+ }
230
+ case "waitForTimeout": {
231
+ const [ms] = op.args;
232
+ await page.waitForTimeout(ms);
233
+ return { ok: true };
234
+ }
235
+ case "waitForLoadState": {
236
+ const [state] = op.args;
237
+ await page.waitForLoadState(state ?? "load", { timeout });
238
+ return { ok: true };
239
+ }
240
+ case "evaluate": {
241
+ const [script] = op.args;
242
+ const result = await page.evaluate(script);
243
+ return { ok: true, value: result };
244
+ }
245
+ case "locatorAction": {
246
+ const [selectorType, selectorValue, roleOptions, action, actionArg] = op.args;
247
+ const locator = getLocator(page, selectorType, selectorValue, roleOptions);
248
+ const result = await executeLocatorAction(locator, action, actionArg, timeout);
249
+ return { ok: true, value: result };
250
+ }
251
+ case "expectLocator": {
252
+ const [selectorType, selectorValue, roleOptions, matcher, expected, negated, customTimeout] = op.args;
253
+ const locator = getLocator(page, selectorType, selectorValue, roleOptions);
254
+ const effectiveTimeout = customTimeout ?? timeout;
255
+ await executeExpectAssertion(locator, matcher, expected, negated ?? false, effectiveTimeout);
256
+ return { ok: true };
257
+ }
258
+ case "request": {
259
+ const [url, method, data, headers] = op.args;
260
+ const targetUrl = baseUrl && !url.startsWith("http") ? `${baseUrl}${url}` : url;
261
+ const requestOptions = {
262
+ timeout
263
+ };
264
+ if (headers) {
265
+ requestOptions.headers = headers;
266
+ }
267
+ if (data !== undefined && data !== null) {
268
+ requestOptions.data = data;
269
+ }
270
+ const response = await page.request.fetch(targetUrl, {
271
+ method,
272
+ ...requestOptions
273
+ });
274
+ const text = await response.text();
275
+ let json = null;
276
+ try {
277
+ json = JSON.parse(text);
278
+ } catch {}
279
+ return {
280
+ ok: true,
281
+ value: {
282
+ status: response.status(),
283
+ ok: response.ok(),
284
+ headers: response.headers(),
285
+ text,
286
+ json,
287
+ body: null
288
+ }
289
+ };
381
290
  }
291
+ default:
292
+ return { ok: false, error: { name: "Error", message: `Unknown operation: ${op.type}` } };
382
293
  }
383
294
  } catch (err) {
384
- if (err instanceof Error) {
385
- throw encodeErrorForTransfer(err);
386
- }
387
- throw err;
295
+ const error = err;
296
+ return { ok: false, error: { name: error.name, message: error.message } };
388
297
  }
298
+ };
299
+ }
300
+ async function setupPlaywright(context, options) {
301
+ const timeout = options.timeout ?? 30000;
302
+ const baseUrl = options.baseUrl;
303
+ const page = "page" in options ? options.page : undefined;
304
+ const handler = "handler" in options ? options.handler : undefined;
305
+ const effectiveHandler = handler ?? (page ? createPlaywrightHandler(page, { timeout, baseUrl }) : undefined);
306
+ if (!effectiveHandler) {
307
+ throw new Error("Either page or handler must be provided to setupPlaywright");
308
+ }
309
+ const browserConsoleLogs = [];
310
+ const networkRequests = [];
311
+ const networkResponses = [];
312
+ const global = context.global;
313
+ let requestHandler;
314
+ let responseHandler;
315
+ let consoleHandler;
316
+ if (page) {
317
+ const onEvent = "onEvent" in options ? options.onEvent : undefined;
318
+ requestHandler = (request) => {
319
+ const info = {
320
+ url: request.url(),
321
+ method: request.method(),
322
+ headers: request.headers(),
323
+ postData: request.postData() ?? undefined,
324
+ resourceType: request.resourceType(),
325
+ timestamp: Date.now()
326
+ };
327
+ networkRequests.push(info);
328
+ if (onEvent) {
329
+ onEvent({
330
+ type: "networkRequest",
331
+ url: info.url,
332
+ method: info.method,
333
+ headers: info.headers,
334
+ postData: info.postData,
335
+ resourceType: info.resourceType,
336
+ timestamp: info.timestamp
337
+ });
338
+ }
339
+ };
340
+ responseHandler = (response) => {
341
+ const info = {
342
+ url: response.url(),
343
+ status: response.status(),
344
+ statusText: response.statusText(),
345
+ headers: response.headers(),
346
+ timestamp: Date.now()
347
+ };
348
+ networkResponses.push(info);
349
+ if (onEvent) {
350
+ onEvent({
351
+ type: "networkResponse",
352
+ url: info.url,
353
+ status: info.status,
354
+ statusText: info.statusText,
355
+ headers: info.headers,
356
+ timestamp: info.timestamp
357
+ });
358
+ }
359
+ };
360
+ consoleHandler = (msg) => {
361
+ const entry = {
362
+ level: msg.type(),
363
+ args: msg.args().map((arg) => String(arg)),
364
+ timestamp: Date.now()
365
+ };
366
+ browserConsoleLogs.push(entry);
367
+ if (onEvent) {
368
+ onEvent({
369
+ type: "browserConsoleLog",
370
+ level: entry.level,
371
+ args: entry.args,
372
+ timestamp: entry.timestamp
373
+ });
374
+ }
375
+ if ("console" in options && options.console) {
376
+ const prefix = `[browser:${entry.level}]`;
377
+ console.log(prefix, ...entry.args);
378
+ }
379
+ };
380
+ page.on("request", requestHandler);
381
+ page.on("response", responseHandler);
382
+ page.on("console", consoleHandler);
383
+ }
384
+ global.setSync("__Playwright_handler_ref", new import_isolated_vm.default.Reference(async (opJson) => {
385
+ const op = JSON.parse(opJson);
386
+ const result = await effectiveHandler(op);
387
+ return JSON.stringify(result);
389
388
  }));
390
- context.evalSync(DECODE_ERROR_JS);
391
389
  context.evalSync(`
392
390
  (function() {
393
- const tests = [];
394
- globalThis.test = (name, fn) => tests.push({ name, fn });
395
-
396
- globalThis.__runPlaywrightTests = async () => {
397
- const results = [];
398
- for (const t of tests) {
399
- const start = Date.now();
400
- try {
401
- await t.fn();
402
- results.push({ name: t.name, passed: true, duration: Date.now() - start });
403
- } catch (err) {
404
- results.push({ name: t.name, passed: false, error: err.message, duration: Date.now() - start });
405
- }
391
+ globalThis.__pw_invoke = async function(type, args) {
392
+ const op = JSON.stringify({ type, args });
393
+ const resultJson = __Playwright_handler_ref.applySyncPromise(undefined, [op]);
394
+ const result = JSON.parse(resultJson);
395
+ if (result.ok) {
396
+ return result.value;
397
+ } else {
398
+ const error = new Error(result.error.message);
399
+ error.name = result.error.name;
400
+ throw error;
406
401
  }
407
- const passed = results.filter(r => r.passed).length;
408
- const failed = results.filter(r => !r.passed).length;
409
- return JSON.stringify({ passed, failed, total: results.length, results });
410
402
  };
411
-
412
- globalThis.__resetPlaywrightTests = () => { tests.length = 0; };
413
403
  })();
414
404
  `);
415
405
  context.evalSync(`
416
406
  (function() {
417
407
  globalThis.page = {
418
408
  async goto(url, options) {
419
- try {
420
- return __Playwright_goto_ref.applySyncPromise(undefined, [url, options?.waitUntil || null]);
421
- } catch (err) { throw __decodeError(err); }
409
+ return __pw_invoke("goto", [url, options?.waitUntil || null]);
422
410
  },
423
411
  async reload() {
424
- try {
425
- return __Playwright_reload_ref.applySyncPromise(undefined, []);
426
- } catch (err) { throw __decodeError(err); }
412
+ return __pw_invoke("reload", []);
413
+ },
414
+ async url() {
415
+ return __pw_invoke("url", []);
427
416
  },
428
- url() { return __Playwright_url(); },
429
417
  async title() {
430
- try {
431
- return __Playwright_title_ref.applySyncPromise(undefined, []);
432
- } catch (err) { throw __decodeError(err); }
418
+ return __pw_invoke("title", []);
433
419
  },
434
420
  async content() {
435
- try {
436
- return __Playwright_content_ref.applySyncPromise(undefined, []);
437
- } catch (err) { throw __decodeError(err); }
421
+ return __pw_invoke("content", []);
438
422
  },
439
423
  async waitForSelector(selector, options) {
440
- try {
441
- return __Playwright_waitForSelector_ref.applySyncPromise(undefined, [selector, options ? JSON.stringify(options) : null]);
442
- } catch (err) { throw __decodeError(err); }
424
+ return __pw_invoke("waitForSelector", [selector, options ? JSON.stringify(options) : null]);
443
425
  },
444
426
  async waitForTimeout(ms) {
445
- try {
446
- return __Playwright_waitForTimeout_ref.applySyncPromise(undefined, [ms]);
447
- } catch (err) { throw __decodeError(err); }
427
+ return __pw_invoke("waitForTimeout", [ms]);
448
428
  },
449
429
  async waitForLoadState(state) {
450
- try {
451
- return __Playwright_waitForLoadState_ref.applySyncPromise(undefined, [state]);
452
- } catch (err) { throw __decodeError(err); }
430
+ return __pw_invoke("waitForLoadState", [state || null]);
453
431
  },
454
432
  async evaluate(script) {
455
- try {
456
- const resultJson = __Playwright_evaluate_ref.applySyncPromise(undefined, [script]);
457
- return resultJson ? JSON.parse(resultJson) : undefined;
458
- } catch (err) { throw __decodeError(err); }
433
+ return __pw_invoke("evaluate", [script]);
459
434
  },
460
435
  locator(selector) { return new Locator("css", selector, null); },
461
436
  getByRole(role, options) { return new Locator("role", role, options ? JSON.stringify(options) : null); },
@@ -463,6 +438,33 @@ async function setupPlaywright(context, options) {
463
438
  getByLabel(label) { return new Locator("label", label, null); },
464
439
  getByPlaceholder(p) { return new Locator("placeholder", p, null); },
465
440
  getByTestId(id) { return new Locator("testId", id, null); },
441
+ async click(selector) { return this.locator(selector).click(); },
442
+ async fill(selector, value) { return this.locator(selector).fill(value); },
443
+ request: {
444
+ async fetch(url, options) {
445
+ const result = await __pw_invoke("request", [url, options?.method || "GET", options?.data, options?.headers]);
446
+ return {
447
+ status: () => result.status,
448
+ ok: () => result.ok,
449
+ headers: () => result.headers,
450
+ json: async () => result.json,
451
+ text: async () => result.text,
452
+ body: async () => result.body,
453
+ };
454
+ },
455
+ async get(url, options) {
456
+ return this.fetch(url, { ...options, method: "GET" });
457
+ },
458
+ async post(url, options) {
459
+ return this.fetch(url, { ...options, method: "POST" });
460
+ },
461
+ async put(url, options) {
462
+ return this.fetch(url, { ...options, method: "PUT" });
463
+ },
464
+ async delete(url, options) {
465
+ return this.fetch(url, { ...options, method: "DELETE" });
466
+ },
467
+ },
466
468
  };
467
469
  })();
468
470
  `);
@@ -479,105 +481,59 @@ async function setupPlaywright(context, options) {
479
481
  _getInfo() { return [this.#type, this.#value, this.#options]; }
480
482
 
481
483
  async click() {
482
- try {
483
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "click", null]);
484
- } catch (err) { throw __decodeError(err); }
484
+ return __pw_invoke("locatorAction", [...this._getInfo(), "click", null]);
485
485
  }
486
-
487
486
  async dblclick() {
488
- try {
489
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "dblclick", null]);
490
- } catch (err) { throw __decodeError(err); }
487
+ return __pw_invoke("locatorAction", [...this._getInfo(), "dblclick", null]);
491
488
  }
492
-
493
489
  async fill(text) {
494
- try {
495
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "fill", text]);
496
- } catch (err) { throw __decodeError(err); }
490
+ return __pw_invoke("locatorAction", [...this._getInfo(), "fill", text]);
497
491
  }
498
-
499
492
  async type(text) {
500
- try {
501
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "type", text]);
502
- } catch (err) { throw __decodeError(err); }
493
+ return __pw_invoke("locatorAction", [...this._getInfo(), "type", text]);
503
494
  }
504
-
505
495
  async check() {
506
- try {
507
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "check", null]);
508
- } catch (err) { throw __decodeError(err); }
496
+ return __pw_invoke("locatorAction", [...this._getInfo(), "check", null]);
509
497
  }
510
-
511
498
  async uncheck() {
512
- try {
513
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "uncheck", null]);
514
- } catch (err) { throw __decodeError(err); }
499
+ return __pw_invoke("locatorAction", [...this._getInfo(), "uncheck", null]);
515
500
  }
516
-
517
501
  async selectOption(value) {
518
- try {
519
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "selectOption", value]);
520
- } catch (err) { throw __decodeError(err); }
502
+ return __pw_invoke("locatorAction", [...this._getInfo(), "selectOption", value]);
521
503
  }
522
-
523
504
  async clear() {
524
- try {
525
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "clear", null]);
526
- } catch (err) { throw __decodeError(err); }
505
+ return __pw_invoke("locatorAction", [...this._getInfo(), "clear", null]);
527
506
  }
528
-
529
507
  async press(key) {
530
- try {
531
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "press", key]);
532
- } catch (err) { throw __decodeError(err); }
508
+ return __pw_invoke("locatorAction", [...this._getInfo(), "press", key]);
533
509
  }
534
-
535
510
  async hover() {
536
- try {
537
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "hover", null]);
538
- } catch (err) { throw __decodeError(err); }
511
+ return __pw_invoke("locatorAction", [...this._getInfo(), "hover", null]);
539
512
  }
540
-
541
513
  async focus() {
542
- try {
543
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "focus", null]);
544
- } catch (err) { throw __decodeError(err); }
514
+ return __pw_invoke("locatorAction", [...this._getInfo(), "focus", null]);
545
515
  }
546
-
547
516
  async textContent() {
548
- try {
549
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "getText", null]);
550
- } catch (err) { throw __decodeError(err); }
517
+ return __pw_invoke("locatorAction", [...this._getInfo(), "getText", null]);
551
518
  }
552
-
553
519
  async inputValue() {
554
- try {
555
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "getValue", null]);
556
- } catch (err) { throw __decodeError(err); }
520
+ return __pw_invoke("locatorAction", [...this._getInfo(), "getValue", null]);
557
521
  }
558
-
559
522
  async isVisible() {
560
- try {
561
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "isVisible", null]);
562
- } catch (err) { throw __decodeError(err); }
523
+ return __pw_invoke("locatorAction", [...this._getInfo(), "isVisible", null]);
563
524
  }
564
-
565
525
  async isEnabled() {
566
- try {
567
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "isEnabled", null]);
568
- } catch (err) { throw __decodeError(err); }
526
+ return __pw_invoke("locatorAction", [...this._getInfo(), "isEnabled", null]);
569
527
  }
570
-
571
528
  async isChecked() {
572
- try {
573
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "isChecked", null]);
574
- } catch (err) { throw __decodeError(err); }
529
+ return __pw_invoke("locatorAction", [...this._getInfo(), "isChecked", null]);
575
530
  }
576
-
577
531
  async count() {
578
- try {
579
- return __Playwright_locatorAction_ref.applySyncPromise(undefined, [...this._getInfo(), "count", null]);
580
- } catch (err) { throw __decodeError(err); }
532
+ return __pw_invoke("locatorAction", [...this._getInfo(), "count", null]);
533
+ }
534
+ nth(index) {
535
+ const existingOpts = this.#options ? JSON.parse(this.#options) : {};
536
+ return new Locator(this.#type, this.#value, JSON.stringify({ ...existingOpts, nth: index }));
581
537
  }
582
538
  }
583
539
  globalThis.Locator = Locator;
@@ -585,127 +541,84 @@ async function setupPlaywright(context, options) {
585
541
  `);
586
542
  context.evalSync(`
587
543
  (function() {
588
- globalThis.expect = (actual) => {
589
- if (actual instanceof Locator) {
590
- const info = actual._getInfo();
591
- return {
592
- async toBeVisible() {
593
- try {
594
- await __Playwright_expectVisible_ref.applySyncPromise(undefined, [...info, false]);
595
- } catch (err) { throw __decodeError(err); }
596
- },
597
- async toContainText(expected) {
598
- try {
599
- await __Playwright_expectText_ref.applySyncPromise(undefined, [...info, expected, false]);
600
- } catch (err) { throw __decodeError(err); }
601
- },
602
- async toHaveValue(expected) {
603
- try {
604
- await __Playwright_expectValue_ref.applySyncPromise(undefined, [...info, expected, false]);
605
- } catch (err) { throw __decodeError(err); }
606
- },
607
- async toBeEnabled() {
608
- try {
609
- await __Playwright_expectEnabled_ref.applySyncPromise(undefined, [...info, false]);
610
- } catch (err) { throw __decodeError(err); }
611
- },
612
- async toBeChecked() {
613
- try {
614
- await __Playwright_expectChecked_ref.applySyncPromise(undefined, [...info, false]);
615
- } catch (err) { throw __decodeError(err); }
616
- },
617
- not: {
618
- async toBeVisible() {
619
- try {
620
- await __Playwright_expectVisible_ref.applySyncPromise(undefined, [...info, true]);
621
- } catch (err) { throw __decodeError(err); }
622
- },
623
- async toContainText(expected) {
624
- try {
625
- await __Playwright_expectText_ref.applySyncPromise(undefined, [...info, expected, true]);
626
- } catch (err) { throw __decodeError(err); }
627
- },
628
- async toHaveValue(expected) {
629
- try {
630
- await __Playwright_expectValue_ref.applySyncPromise(undefined, [...info, expected, true]);
631
- } catch (err) { throw __decodeError(err); }
632
- },
633
- async toBeEnabled() {
634
- try {
635
- await __Playwright_expectEnabled_ref.applySyncPromise(undefined, [...info, true]);
636
- } catch (err) { throw __decodeError(err); }
637
- },
638
- async toBeChecked() {
639
- try {
640
- await __Playwright_expectChecked_ref.applySyncPromise(undefined, [...info, true]);
641
- } catch (err) { throw __decodeError(err); }
642
- },
643
- },
644
- };
645
- }
646
- // Fallback: basic matchers for primitives
647
- return {
648
- toBe(expected) {
649
- if (actual !== expected) throw new Error(\`Expected \${JSON.stringify(actual)} to be \${JSON.stringify(expected)}\`);
544
+ // Helper to create locator matchers
545
+ function createLocatorMatchers(locator, baseMatchers) {
546
+ const info = locator._getInfo();
547
+
548
+ const locatorMatchers = {
549
+ async toBeVisible(options) {
550
+ return __pw_invoke("expectLocator", [...info, "toBeVisible", null, false, options?.timeout]);
650
551
  },
651
- toEqual(expected) {
652
- if (JSON.stringify(actual) !== JSON.stringify(expected)) {
653
- throw new Error(\`Expected \${JSON.stringify(actual)} to equal \${JSON.stringify(expected)}\`);
654
- }
552
+ async toContainText(expected, options) {
553
+ return __pw_invoke("expectLocator", [...info, "toContainText", expected, false, options?.timeout]);
655
554
  },
656
- toBeTruthy() {
657
- if (!actual) throw new Error(\`Expected \${JSON.stringify(actual)} to be truthy\`);
555
+ async toHaveValue(expected, options) {
556
+ return __pw_invoke("expectLocator", [...info, "toHaveValue", expected, false, options?.timeout]);
658
557
  },
659
- toBeFalsy() {
660
- if (actual) throw new Error(\`Expected \${JSON.stringify(actual)} to be falsy\`);
558
+ async toBeEnabled(options) {
559
+ return __pw_invoke("expectLocator", [...info, "toBeEnabled", null, false, options?.timeout]);
661
560
  },
662
- toContain(expected) {
663
- if (typeof actual === 'string' && !actual.includes(expected)) {
664
- throw new Error(\`Expected "\${actual}" to contain "\${expected}"\`);
665
- }
666
- if (Array.isArray(actual) && !actual.includes(expected)) {
667
- throw new Error(\`Expected array to contain \${JSON.stringify(expected)}\`);
668
- }
561
+ async toBeChecked(options) {
562
+ return __pw_invoke("expectLocator", [...info, "toBeChecked", null, false, options?.timeout]);
669
563
  },
670
564
  not: {
671
- toBe(expected) {
672
- if (actual === expected) throw new Error(\`Expected \${JSON.stringify(actual)} to not be \${JSON.stringify(expected)}\`);
565
+ async toBeVisible(options) {
566
+ return __pw_invoke("expectLocator", [...info, "toBeVisible", null, true, options?.timeout]);
673
567
  },
674
- toEqual(expected) {
675
- if (JSON.stringify(actual) === JSON.stringify(expected)) {
676
- throw new Error(\`Expected \${JSON.stringify(actual)} to not equal \${JSON.stringify(expected)}\`);
677
- }
568
+ async toContainText(expected, options) {
569
+ return __pw_invoke("expectLocator", [...info, "toContainText", expected, true, options?.timeout]);
678
570
  },
679
- toBeTruthy() {
680
- if (actual) throw new Error(\`Expected \${JSON.stringify(actual)} to not be truthy\`);
571
+ async toHaveValue(expected, options) {
572
+ return __pw_invoke("expectLocator", [...info, "toHaveValue", expected, true, options?.timeout]);
681
573
  },
682
- toBeFalsy() {
683
- if (!actual) throw new Error(\`Expected \${JSON.stringify(actual)} to not be falsy\`);
574
+ async toBeEnabled(options) {
575
+ return __pw_invoke("expectLocator", [...info, "toBeEnabled", null, true, options?.timeout]);
684
576
  },
685
- toContain(expected) {
686
- if (typeof actual === 'string' && actual.includes(expected)) {
687
- throw new Error(\`Expected "\${actual}" to not contain "\${expected}"\`);
688
- }
689
- if (Array.isArray(actual) && actual.includes(expected)) {
690
- throw new Error(\`Expected array to not contain \${JSON.stringify(expected)}\`);
691
- }
577
+ async toBeChecked(options) {
578
+ return __pw_invoke("expectLocator", [...info, "toBeChecked", null, true, options?.timeout]);
692
579
  },
693
- },
580
+ }
694
581
  };
695
- };
582
+
583
+ // Merge locator matchers with base matchers from test-environment
584
+ if (baseMatchers) {
585
+ return {
586
+ ...baseMatchers,
587
+ ...locatorMatchers,
588
+ not: { ...baseMatchers.not, ...locatorMatchers.not }
589
+ };
590
+ }
591
+ return locatorMatchers;
592
+ }
593
+
594
+ // Only extend expect if test-environment already defined it
595
+ if (typeof globalThis.expect === 'function') {
596
+ const originalExpect = globalThis.expect;
597
+ globalThis.expect = function(actual) {
598
+ const baseMatchers = originalExpect(actual);
599
+ // If actual is a Locator, add locator-specific matchers
600
+ if (actual && actual.constructor && actual.constructor.name === 'Locator') {
601
+ return createLocatorMatchers(actual, baseMatchers);
602
+ }
603
+ return baseMatchers;
604
+ };
605
+ }
606
+ // If test-environment not loaded, expect remains undefined
696
607
  })();
697
608
  `);
698
609
  return {
699
610
  dispose() {
700
- page.off("request", requestHandler);
701
- page.off("response", responseHandler);
702
- page.off("console", consoleHandler);
703
- consoleLogs.length = 0;
611
+ if (page && requestHandler && responseHandler && consoleHandler) {
612
+ page.off("request", requestHandler);
613
+ page.off("response", responseHandler);
614
+ page.off("console", consoleHandler);
615
+ }
616
+ browserConsoleLogs.length = 0;
704
617
  networkRequests.length = 0;
705
618
  networkResponses.length = 0;
706
619
  },
707
- getConsoleLogs() {
708
- return [...consoleLogs];
620
+ getBrowserConsoleLogs() {
621
+ return [...browserConsoleLogs];
709
622
  },
710
623
  getNetworkRequests() {
711
624
  return [...networkRequests];
@@ -714,24 +627,12 @@ async function setupPlaywright(context, options) {
714
627
  return [...networkResponses];
715
628
  },
716
629
  clearCollected() {
717
- consoleLogs.length = 0;
630
+ browserConsoleLogs.length = 0;
718
631
  networkRequests.length = 0;
719
632
  networkResponses.length = 0;
720
633
  }
721
634
  };
722
635
  }
723
- async function runPlaywrightTests(context) {
724
- const runTestsRef = context.global.getSync("__runPlaywrightTests", {
725
- reference: true
726
- });
727
- const resultJson = await runTestsRef.apply(undefined, [], {
728
- result: { promise: true }
729
- });
730
- return JSON.parse(resultJson);
731
- }
732
- async function resetPlaywrightTests(context) {
733
- context.evalSync("__resetPlaywrightTests()");
734
- }
735
636
  })
736
637
 
737
- //# debugId=B798FB5EEEDF725764756E2164756E21
638
+ //# debugId=4D1ABAEF45F490EA64756E2164756E21