@ricsam/isolate-playwright 0.1.9 → 0.1.11

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.
@@ -6,6 +6,10 @@ function getLocator(page, selectorType, selectorValue, optionsJson) {
6
6
  const roleOptions = options ? { ...options } : undefined;
7
7
  if (roleOptions) {
8
8
  delete roleOptions.nth;
9
+ delete roleOptions.filter;
10
+ if (roleOptions.name && typeof roleOptions.name === "object" && roleOptions.name.$regex) {
11
+ roleOptions.name = new RegExp(roleOptions.name.$regex, roleOptions.name.$flags);
12
+ }
9
13
  }
10
14
  let locator;
11
15
  switch (selectorType) {
@@ -33,6 +37,16 @@ function getLocator(page, selectorType, selectorValue, optionsJson) {
33
37
  if (nthIndex !== undefined) {
34
38
  locator = locator.nth(nthIndex);
35
39
  }
40
+ if (options?.filter) {
41
+ const filterOpts = { ...options.filter };
42
+ if (filterOpts.hasText && typeof filterOpts.hasText === "object" && filterOpts.hasText.$regex) {
43
+ filterOpts.hasText = new RegExp(filterOpts.hasText.$regex, filterOpts.hasText.$flags);
44
+ }
45
+ if (filterOpts.hasNotText && typeof filterOpts.hasNotText === "object" && filterOpts.hasNotText.$regex) {
46
+ filterOpts.hasNotText = new RegExp(filterOpts.hasNotText.$regex, filterOpts.hasNotText.$flags);
47
+ }
48
+ locator = locator.filter(filterOpts);
49
+ }
36
50
  return locator;
37
51
  }
38
52
  async function executeLocatorAction(locator, action, actionArg, timeout) {
@@ -82,6 +96,27 @@ async function executeLocatorAction(locator, action, actionArg, timeout) {
82
96
  return await locator.isChecked();
83
97
  case "count":
84
98
  return await locator.count();
99
+ case "getAttribute":
100
+ return await locator.getAttribute(String(actionArg ?? ""), { timeout });
101
+ case "isDisabled":
102
+ return await locator.isDisabled();
103
+ case "isHidden":
104
+ return await locator.isHidden();
105
+ case "innerHTML":
106
+ return await locator.innerHTML({ timeout });
107
+ case "innerText":
108
+ return await locator.innerText({ timeout });
109
+ case "allTextContents":
110
+ return await locator.allTextContents();
111
+ case "allInnerTexts":
112
+ return await locator.allInnerTexts();
113
+ case "waitFor": {
114
+ const opts = actionArg && typeof actionArg === "object" ? actionArg : {};
115
+ await locator.waitFor({ state: opts.state, timeout: opts.timeout ?? timeout });
116
+ return null;
117
+ }
118
+ case "boundingBox":
119
+ return await locator.boundingBox({ timeout });
85
120
  default:
86
121
  throw new Error(`Unknown action: ${action}`);
87
122
  }
@@ -101,13 +136,22 @@ async function executeExpectAssertion(locator, matcher, expected, negated, timeo
101
136
  }
102
137
  case "toContainText": {
103
138
  const text = await locator.textContent({ timeout });
104
- const matches = text?.includes(String(expected)) ?? false;
139
+ let matches;
140
+ let expectedDisplay;
141
+ if (expected && typeof expected === "object" && expected.$regex) {
142
+ const regex = new RegExp(expected.$regex, expected.$flags);
143
+ matches = regex.test(text ?? "");
144
+ expectedDisplay = String(regex);
145
+ } else {
146
+ matches = text?.includes(String(expected)) ?? false;
147
+ expectedDisplay = String(expected);
148
+ }
105
149
  if (negated) {
106
150
  if (matches)
107
- throw new Error(`Expected text to not contain "${expected}", but got "${text}"`);
151
+ throw new Error(`Expected text to not contain ${expectedDisplay}, but got "${text}"`);
108
152
  } else {
109
153
  if (!matches)
110
- throw new Error(`Expected text to contain "${expected}", but got "${text}"`);
154
+ throw new Error(`Expected text to contain ${expectedDisplay}, but got "${text}"`);
111
155
  }
112
156
  break;
113
157
  }
@@ -145,6 +189,110 @@ async function executeExpectAssertion(locator, matcher, expected, negated, timeo
145
189
  }
146
190
  break;
147
191
  }
192
+ case "toHaveAttribute": {
193
+ const { name, value } = expected;
194
+ const actual = await locator.getAttribute(name, { timeout });
195
+ if (value instanceof RegExp || value && typeof value === "object" && value.$regex) {
196
+ const regex = value.$regex ? new RegExp(value.$regex, value.$flags) : value;
197
+ const matches = regex.test(actual ?? "");
198
+ if (negated) {
199
+ if (matches)
200
+ throw new Error(`Expected attribute "${name}" to not match ${regex}, but got "${actual}"`);
201
+ } else {
202
+ if (!matches)
203
+ throw new Error(`Expected attribute "${name}" to match ${regex}, but got "${actual}"`);
204
+ }
205
+ } else {
206
+ const matches = actual === String(value);
207
+ if (negated) {
208
+ if (matches)
209
+ throw new Error(`Expected attribute "${name}" to not be "${value}", but it was`);
210
+ } else {
211
+ if (!matches)
212
+ throw new Error(`Expected attribute "${name}" to be "${value}", but got "${actual}"`);
213
+ }
214
+ }
215
+ break;
216
+ }
217
+ case "toHaveText": {
218
+ const text = await locator.textContent({ timeout }) ?? "";
219
+ let matches;
220
+ let expectedDisplay;
221
+ if (expected && typeof expected === "object" && expected.$regex) {
222
+ const regex = new RegExp(expected.$regex, expected.$flags);
223
+ matches = regex.test(text);
224
+ expectedDisplay = String(regex);
225
+ } else {
226
+ matches = text === String(expected);
227
+ expectedDisplay = JSON.stringify(expected);
228
+ }
229
+ if (negated) {
230
+ if (matches)
231
+ throw new Error(`Expected text to not be ${expectedDisplay}, but got "${text}"`);
232
+ } else {
233
+ if (!matches)
234
+ throw new Error(`Expected text to be ${expectedDisplay}, but got "${text}"`);
235
+ }
236
+ break;
237
+ }
238
+ case "toHaveCount": {
239
+ const count = await locator.count();
240
+ const expectedCount = Number(expected);
241
+ if (negated) {
242
+ if (count === expectedCount)
243
+ throw new Error(`Expected count to not be ${expectedCount}, but it was`);
244
+ } else {
245
+ if (count !== expectedCount)
246
+ throw new Error(`Expected count to be ${expectedCount}, but got ${count}`);
247
+ }
248
+ break;
249
+ }
250
+ case "toBeHidden": {
251
+ const isHidden = await locator.isHidden();
252
+ if (negated) {
253
+ if (isHidden)
254
+ throw new Error("Expected element to not be hidden, but it was hidden");
255
+ } else {
256
+ if (!isHidden)
257
+ throw new Error("Expected element to be hidden, but it was not");
258
+ }
259
+ break;
260
+ }
261
+ case "toBeDisabled": {
262
+ const isDisabled = await locator.isDisabled();
263
+ if (negated) {
264
+ if (isDisabled)
265
+ throw new Error("Expected element to not be disabled, but it was disabled");
266
+ } else {
267
+ if (!isDisabled)
268
+ throw new Error("Expected element to be disabled, but it was not");
269
+ }
270
+ break;
271
+ }
272
+ case "toBeFocused": {
273
+ const isFocused = await locator.evaluate((el) => document.activeElement === el).catch(() => false);
274
+ if (negated) {
275
+ if (isFocused)
276
+ throw new Error("Expected element to not be focused, but it was focused");
277
+ } else {
278
+ if (!isFocused)
279
+ throw new Error("Expected element to be focused, but it was not");
280
+ }
281
+ break;
282
+ }
283
+ case "toBeEmpty": {
284
+ const text = await locator.textContent({ timeout });
285
+ const value = await locator.inputValue({ timeout }).catch(() => null);
286
+ const isEmpty = value !== null ? value === "" : (text ?? "") === "";
287
+ if (negated) {
288
+ if (isEmpty)
289
+ throw new Error("Expected element to not be empty, but it was");
290
+ } else {
291
+ if (!isEmpty)
292
+ throw new Error("Expected element to be empty, but it was not");
293
+ }
294
+ break;
295
+ }
148
296
  default:
149
297
  throw new Error(`Unknown matcher: ${matcher}`);
150
298
  }
@@ -190,7 +338,12 @@ function createPlaywrightHandler(page, options) {
190
338
  return { ok: true };
191
339
  }
192
340
  case "evaluate": {
193
- const [script] = op.args;
341
+ const [script, arg] = op.args;
342
+ if (op.args.length > 1) {
343
+ const fn = new Function("return (" + script + ")")();
344
+ const result2 = await page.evaluate(fn, arg);
345
+ return { ok: true, value: result2 };
346
+ }
194
347
  const result = await page.evaluate(script);
195
348
  return { ok: true, value: result };
196
349
  }
@@ -240,6 +393,34 @@ function createPlaywrightHandler(page, options) {
240
393
  }
241
394
  };
242
395
  }
396
+ case "goBack": {
397
+ const [waitUntil] = op.args;
398
+ await page.goBack({
399
+ timeout,
400
+ waitUntil: waitUntil ?? "load"
401
+ });
402
+ return { ok: true };
403
+ }
404
+ case "goForward": {
405
+ const [waitUntil] = op.args;
406
+ await page.goForward({
407
+ timeout,
408
+ waitUntil: waitUntil ?? "load"
409
+ });
410
+ return { ok: true };
411
+ }
412
+ case "waitForURL": {
413
+ const [url, customTimeout, waitUntil] = op.args;
414
+ await page.waitForURL(url, {
415
+ timeout: customTimeout ?? timeout,
416
+ waitUntil: waitUntil ?? undefined
417
+ });
418
+ return { ok: true };
419
+ }
420
+ case "clearCookies": {
421
+ await page.context().clearCookies();
422
+ return { ok: true };
423
+ }
243
424
  default:
244
425
  return { ok: false, error: { name: "Error", message: `Unknown operation: ${op.type}` } };
245
426
  }
@@ -357,15 +538,22 @@ async function setupPlaywright(context, options) {
357
538
  `);
358
539
  context.evalSync(`
359
540
  (function() {
541
+ let __pw_currentUrl = '';
360
542
  globalThis.page = {
361
543
  async goto(url, options) {
362
- return __pw_invoke("goto", [url, options?.waitUntil || null]);
544
+ const result = await __pw_invoke("goto", [url, options?.waitUntil || null]);
545
+ const resolvedUrl = await __pw_invoke("url", []);
546
+ __pw_currentUrl = resolvedUrl || url;
547
+ return result;
363
548
  },
364
549
  async reload() {
365
- return __pw_invoke("reload", []);
550
+ const result = await __pw_invoke("reload", []);
551
+ const resolvedUrl = await __pw_invoke("url", []);
552
+ if (resolvedUrl) __pw_currentUrl = resolvedUrl;
553
+ return result;
366
554
  },
367
- async url() {
368
- return __pw_invoke("url", []);
555
+ url() {
556
+ return __pw_currentUrl;
369
557
  },
370
558
  async title() {
371
559
  return __pw_invoke("title", []);
@@ -382,15 +570,50 @@ async function setupPlaywright(context, options) {
382
570
  async waitForLoadState(state) {
383
571
  return __pw_invoke("waitForLoadState", [state || null]);
384
572
  },
385
- async evaluate(script) {
386
- return __pw_invoke("evaluate", [script]);
573
+ async evaluate(script, arg) {
574
+ const hasArg = arguments.length > 1;
575
+ if (hasArg) {
576
+ const serialized = typeof script === "function" ? script.toString() : script;
577
+ return __pw_invoke("evaluate", [serialized, arg]);
578
+ }
579
+ const serialized = typeof script === "function" ? "(" + script.toString() + ")()" : script;
580
+ return __pw_invoke("evaluate", [serialized]);
387
581
  },
388
582
  locator(selector) { return new Locator("css", selector, null); },
389
- getByRole(role, options) { return new Locator("role", role, options ? JSON.stringify(options) : null); },
583
+ getByRole(role, options) {
584
+ if (options) {
585
+ const serialized = { ...options };
586
+ if (options.name instanceof RegExp) {
587
+ serialized.name = { $regex: options.name.source, $flags: options.name.flags };
588
+ }
589
+ return new Locator("role", role, JSON.stringify(serialized));
590
+ }
591
+ return new Locator("role", role, null);
592
+ },
390
593
  getByText(text) { return new Locator("text", text, null); },
391
594
  getByLabel(label) { return new Locator("label", label, null); },
392
595
  getByPlaceholder(p) { return new Locator("placeholder", p, null); },
393
596
  getByTestId(id) { return new Locator("testId", id, null); },
597
+ async goBack(options) {
598
+ await __pw_invoke("goBack", [options?.waitUntil || null]);
599
+ const resolvedUrl = await __pw_invoke("url", []);
600
+ if (resolvedUrl) __pw_currentUrl = resolvedUrl;
601
+ },
602
+ async goForward(options) {
603
+ await __pw_invoke("goForward", [options?.waitUntil || null]);
604
+ const resolvedUrl = await __pw_invoke("url", []);
605
+ if (resolvedUrl) __pw_currentUrl = resolvedUrl;
606
+ },
607
+ async waitForURL(url, options) {
608
+ return __pw_invoke("waitForURL", [url, options?.timeout || null, options?.waitUntil || null]);
609
+ },
610
+ context() {
611
+ return {
612
+ async clearCookies() {
613
+ return __pw_invoke("clearCookies", []);
614
+ }
615
+ };
616
+ },
394
617
  async click(selector) { return this.locator(selector).click(); },
395
618
  async fill(selector, value) { return this.locator(selector).fill(value); },
396
619
  request: {
@@ -484,10 +707,70 @@ async function setupPlaywright(context, options) {
484
707
  async count() {
485
708
  return __pw_invoke("locatorAction", [...this._getInfo(), "count", null]);
486
709
  }
710
+ async getAttribute(name) {
711
+ return __pw_invoke("locatorAction", [...this._getInfo(), "getAttribute", name]);
712
+ }
713
+ async isDisabled() {
714
+ return __pw_invoke("locatorAction", [...this._getInfo(), "isDisabled", null]);
715
+ }
716
+ async isHidden() {
717
+ return __pw_invoke("locatorAction", [...this._getInfo(), "isHidden", null]);
718
+ }
719
+ async innerHTML() {
720
+ return __pw_invoke("locatorAction", [...this._getInfo(), "innerHTML", null]);
721
+ }
722
+ async innerText() {
723
+ return __pw_invoke("locatorAction", [...this._getInfo(), "innerText", null]);
724
+ }
725
+ async allTextContents() {
726
+ return __pw_invoke("locatorAction", [...this._getInfo(), "allTextContents", null]);
727
+ }
728
+ async allInnerTexts() {
729
+ return __pw_invoke("locatorAction", [...this._getInfo(), "allInnerTexts", null]);
730
+ }
731
+ async waitFor(options) {
732
+ return __pw_invoke("locatorAction", [...this._getInfo(), "waitFor", options || {}]);
733
+ }
734
+ async boundingBox() {
735
+ return __pw_invoke("locatorAction", [...this._getInfo(), "boundingBox", null]);
736
+ }
737
+ locator(selector) {
738
+ const parentSelector = this.#type === 'css' ? this.#value : null;
739
+ if (parentSelector) {
740
+ return new Locator("css", parentSelector + " " + selector, this.#options);
741
+ }
742
+ // For non-css locators, use css with the combined approach
743
+ return new Locator("css", selector, this.#options);
744
+ }
745
+ async all() {
746
+ const n = await this.count();
747
+ const result = [];
748
+ for (let i = 0; i < n; i++) {
749
+ result.push(this.nth(i));
750
+ }
751
+ return result;
752
+ }
487
753
  nth(index) {
488
754
  const existingOpts = this.#options ? JSON.parse(this.#options) : {};
489
755
  return new Locator(this.#type, this.#value, JSON.stringify({ ...existingOpts, nth: index }));
490
756
  }
757
+ first() {
758
+ return this.nth(0);
759
+ }
760
+ last() {
761
+ return this.nth(-1);
762
+ }
763
+ filter(options) {
764
+ const existingOpts = this.#options ? JSON.parse(this.#options) : {};
765
+ const serializedFilter = { ...options };
766
+ if (options.hasText instanceof RegExp) {
767
+ serializedFilter.hasText = { $regex: options.hasText.source, $flags: options.hasText.flags };
768
+ }
769
+ if (options.hasNotText instanceof RegExp) {
770
+ serializedFilter.hasNotText = { $regex: options.hasNotText.source, $flags: options.hasNotText.flags };
771
+ }
772
+ return new Locator(this.#type, this.#value, JSON.stringify({ ...existingOpts, filter: serializedFilter }));
773
+ }
491
774
  }
492
775
  globalThis.Locator = Locator;
493
776
  })();
@@ -503,7 +786,8 @@ async function setupPlaywright(context, options) {
503
786
  return __pw_invoke("expectLocator", [...info, "toBeVisible", null, false, options?.timeout]);
504
787
  },
505
788
  async toContainText(expected, options) {
506
- return __pw_invoke("expectLocator", [...info, "toContainText", expected, false, options?.timeout]);
789
+ const serialized = expected instanceof RegExp ? { $regex: expected.source, $flags: expected.flags } : expected;
790
+ return __pw_invoke("expectLocator", [...info, "toContainText", serialized, false, options?.timeout]);
507
791
  },
508
792
  async toHaveValue(expected, options) {
509
793
  return __pw_invoke("expectLocator", [...info, "toHaveValue", expected, false, options?.timeout]);
@@ -514,12 +798,35 @@ async function setupPlaywright(context, options) {
514
798
  async toBeChecked(options) {
515
799
  return __pw_invoke("expectLocator", [...info, "toBeChecked", null, false, options?.timeout]);
516
800
  },
801
+ async toHaveAttribute(name, value, options) {
802
+ return __pw_invoke("expectLocator", [...info, "toHaveAttribute", { name, value }, false, options?.timeout]);
803
+ },
804
+ async toHaveText(expected, options) {
805
+ const serialized = expected instanceof RegExp ? { $regex: expected.source, $flags: expected.flags } : expected;
806
+ return __pw_invoke("expectLocator", [...info, "toHaveText", serialized, false, options?.timeout]);
807
+ },
808
+ async toHaveCount(count, options) {
809
+ return __pw_invoke("expectLocator", [...info, "toHaveCount", count, false, options?.timeout]);
810
+ },
811
+ async toBeHidden(options) {
812
+ return __pw_invoke("expectLocator", [...info, "toBeHidden", null, false, options?.timeout]);
813
+ },
814
+ async toBeDisabled(options) {
815
+ return __pw_invoke("expectLocator", [...info, "toBeDisabled", null, false, options?.timeout]);
816
+ },
817
+ async toBeFocused(options) {
818
+ return __pw_invoke("expectLocator", [...info, "toBeFocused", null, false, options?.timeout]);
819
+ },
820
+ async toBeEmpty(options) {
821
+ return __pw_invoke("expectLocator", [...info, "toBeEmpty", null, false, options?.timeout]);
822
+ },
517
823
  not: {
518
824
  async toBeVisible(options) {
519
825
  return __pw_invoke("expectLocator", [...info, "toBeVisible", null, true, options?.timeout]);
520
826
  },
521
827
  async toContainText(expected, options) {
522
- return __pw_invoke("expectLocator", [...info, "toContainText", expected, true, options?.timeout]);
828
+ const serialized = expected instanceof RegExp ? { $regex: expected.source, $flags: expected.flags } : expected;
829
+ return __pw_invoke("expectLocator", [...info, "toContainText", serialized, true, options?.timeout]);
523
830
  },
524
831
  async toHaveValue(expected, options) {
525
832
  return __pw_invoke("expectLocator", [...info, "toHaveValue", expected, true, options?.timeout]);
@@ -530,6 +837,28 @@ async function setupPlaywright(context, options) {
530
837
  async toBeChecked(options) {
531
838
  return __pw_invoke("expectLocator", [...info, "toBeChecked", null, true, options?.timeout]);
532
839
  },
840
+ async toHaveAttribute(name, value, options) {
841
+ return __pw_invoke("expectLocator", [...info, "toHaveAttribute", { name, value }, true, options?.timeout]);
842
+ },
843
+ async toHaveText(expected, options) {
844
+ const serialized = expected instanceof RegExp ? { $regex: expected.source, $flags: expected.flags } : expected;
845
+ return __pw_invoke("expectLocator", [...info, "toHaveText", serialized, true, options?.timeout]);
846
+ },
847
+ async toHaveCount(count, options) {
848
+ return __pw_invoke("expectLocator", [...info, "toHaveCount", count, true, options?.timeout]);
849
+ },
850
+ async toBeHidden(options) {
851
+ return __pw_invoke("expectLocator", [...info, "toBeHidden", null, true, options?.timeout]);
852
+ },
853
+ async toBeDisabled(options) {
854
+ return __pw_invoke("expectLocator", [...info, "toBeDisabled", null, true, options?.timeout]);
855
+ },
856
+ async toBeFocused(options) {
857
+ return __pw_invoke("expectLocator", [...info, "toBeFocused", null, true, options?.timeout]);
858
+ },
859
+ async toBeEmpty(options) {
860
+ return __pw_invoke("expectLocator", [...info, "toBeEmpty", null, true, options?.timeout]);
861
+ },
533
862
  }
534
863
  };
535
864
 
@@ -591,4 +920,4 @@ export {
591
920
  createPlaywrightHandler
592
921
  };
593
922
 
594
- //# debugId=D0C77B5DBE0D4CDD64756E2164756E21
923
+ //# debugId=E0EDC9DB148039D664756E2164756E21