cbrowser 18.73.4 → 18.74.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/analysis/accessibility-empathy.d.ts.map +1 -1
  2. package/dist/analysis/accessibility-empathy.js +25 -4
  3. package/dist/analysis/accessibility-empathy.js.map +1 -1
  4. package/dist/analysis/natural-language.d.ts.map +1 -1
  5. package/dist/analysis/natural-language.js +9 -8
  6. package/dist/analysis/natural-language.js.map +1 -1
  7. package/dist/analysis/page-understanding.d.ts.map +1 -1
  8. package/dist/analysis/page-understanding.js +38 -2
  9. package/dist/analysis/page-understanding.js.map +1 -1
  10. package/dist/artifact-store.d.ts +55 -0
  11. package/dist/artifact-store.d.ts.map +1 -0
  12. package/dist/artifact-store.js +63 -0
  13. package/dist/artifact-store.js.map +1 -0
  14. package/dist/browser.d.ts.map +1 -1
  15. package/dist/browser.js +64 -22
  16. package/dist/browser.js.map +1 -1
  17. package/dist/mcp-tools/base/audit-tools.d.ts.map +1 -1
  18. package/dist/mcp-tools/base/audit-tools.js +117 -33
  19. package/dist/mcp-tools/base/audit-tools.js.map +1 -1
  20. package/dist/mcp-tools/base/gif-tools.d.ts.map +1 -1
  21. package/dist/mcp-tools/base/gif-tools.js +7 -7
  22. package/dist/mcp-tools/base/gif-tools.js.map +1 -1
  23. package/dist/mcp-tools/base/persona-comparison-tools.d.ts.map +1 -1
  24. package/dist/mcp-tools/base/persona-comparison-tools.js +78 -10
  25. package/dist/mcp-tools/base/persona-comparison-tools.js.map +1 -1
  26. package/dist/mcp-tools/base/site-knowledge-tools.d.ts.map +1 -1
  27. package/dist/mcp-tools/base/site-knowledge-tools.js +32 -0
  28. package/dist/mcp-tools/base/site-knowledge-tools.js.map +1 -1
  29. package/dist/mcp-tools/base/visual-testing-tools.d.ts.map +1 -1
  30. package/dist/mcp-tools/base/visual-testing-tools.js +19 -23
  31. package/dist/mcp-tools/base/visual-testing-tools.js.map +1 -1
  32. package/dist/mcp-tools/persona-creation-tools.d.ts.map +1 -1
  33. package/dist/mcp-tools/persona-creation-tools.js +22 -10
  34. package/dist/mcp-tools/persona-creation-tools.js.map +1 -1
  35. package/dist/mcp-ui-resources.d.ts +83 -0
  36. package/dist/mcp-ui-resources.d.ts.map +1 -0
  37. package/dist/mcp-ui-resources.js +128 -0
  38. package/dist/mcp-ui-resources.js.map +1 -0
  39. package/dist/selector-escape.d.ts +37 -0
  40. package/dist/selector-escape.d.ts.map +1 -0
  41. package/dist/selector-escape.js +83 -0
  42. package/dist/selector-escape.js.map +1 -0
  43. package/dist/types.d.ts +9 -0
  44. package/dist/types.d.ts.map +1 -1
  45. package/dist/types.js.map +1 -1
  46. package/dist/visual/attention-quality.d.ts +0 -9
  47. package/dist/visual/attention-quality.d.ts.map +1 -1
  48. package/dist/visual/attention-quality.js +28 -1
  49. package/dist/visual/attention-quality.js.map +1 -1
  50. package/dist/visual/barrier-overlay-html.d.ts +88 -0
  51. package/dist/visual/barrier-overlay-html.d.ts.map +1 -0
  52. package/dist/visual/barrier-overlay-html.js +142 -0
  53. package/dist/visual/barrier-overlay-html.js.map +1 -0
  54. package/dist/visual/cognitive-transport.d.ts +0 -6
  55. package/dist/visual/cognitive-transport.d.ts.map +1 -1
  56. package/dist/visual/cognitive-transport.js +28 -3
  57. package/dist/visual/cognitive-transport.js.map +1 -1
  58. package/dist/visual/cross-browser.d.ts +13 -0
  59. package/dist/visual/cross-browser.d.ts.map +1 -1
  60. package/dist/visual/cross-browser.js +29 -3
  61. package/dist/visual/cross-browser.js.map +1 -1
  62. package/package.json +2 -1
package/dist/browser.js CHANGED
@@ -3421,14 +3421,29 @@ For more help: https://playwright.dev/docs/browsers
3421
3421
  async analyzePage() {
3422
3422
  const page = await this.getPage();
3423
3423
  const analysis = await page.evaluate(() => {
3424
+ // Values are escaped before they enter a selector. Raw interpolation broke
3425
+ // on ids a framework generated rather than a human wrote: `#:r0:` (React 18
3426
+ // useId) and `#2fa-code` throw DOMException, and `#a.b` silently matches
3427
+ // nothing at all. Priority is ARIA-first to match find_element_by_intent
3428
+ // and the documented behaviour; an explicit test hook outranks a generated
3429
+ // id, and aria-label outranks both. (2026-07-29)
3430
+ const q = (v) => v.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
3424
3431
  const getSelector = (el) => {
3432
+ const ariaLabel = el.getAttribute("aria-label");
3433
+ if (ariaLabel)
3434
+ return `[aria-label="${q(ariaLabel)}"]`;
3435
+ const testId = el.getAttribute("data-testid");
3436
+ if (testId)
3437
+ return `[data-testid="${q(testId)}"]`;
3425
3438
  if (el.id)
3426
- return `#${el.id}`;
3427
- if (el.getAttribute("data-testid"))
3428
- return `[data-testid="${el.getAttribute("data-testid")}"]`;
3439
+ return `#${CSS.escape(el.id)}`;
3429
3440
  if (el.getAttribute("name"))
3430
- return `[name="${el.getAttribute("name")}"]`;
3431
- const text = el.textContent?.trim().substring(0, 30);
3441
+ return `[name="${q(el.getAttribute("name"))}"]`;
3442
+ // Was substring(0, 30) — the same truncation removed from aria-label and
3443
+ // visible text elsewhere, still cutting the SELECTOR here, so a generated
3444
+ // step said text="Sign up for Pro and get 500 bo" and matched nothing.
3445
+ // A selector has to be the whole string to resolve. (2026-07-29)
3446
+ const text = el.textContent?.trim().substring(0, 200);
3432
3447
  if (text)
3433
3448
  return `text="${text}"`;
3434
3449
  return el.tagName.toLowerCase();
@@ -3678,27 +3693,40 @@ For more help: https://playwright.dev/docs/browsers
3678
3693
  for (const test of tests) {
3679
3694
  script += `# ${test.name}\n`;
3680
3695
  script += `# ${test.description}\n`;
3696
+ // This must be the dialect src/testing/nl-test-suite.ts PARSES, because the
3697
+ // MCP tool tells callers to paste it straight into nl_test_inline. It used
3698
+ // to emit a `verb "quoted-arg"` form of its own invention, and every line
3699
+ // came back action:"unknown" — `navigate "url"` is not a rule (the rule is
3700
+ // `go to <url>`), and wrapping a selector in quotes leaves literal quote
3701
+ // characters inside the target, which then nests against selectors like
3702
+ // [data-testid="x"]. (2026-07-29)
3681
3703
  for (const step of test.steps) {
3682
3704
  switch (step.action) {
3683
3705
  case "navigate":
3684
- script += `navigate "${step.target}"\n`;
3706
+ script += `go to ${step.target}\n`;
3685
3707
  break;
3686
3708
  case "click":
3687
- script += `click "${step.target}"\n`;
3709
+ // Unquoted: the parser takes the rest of the line as the target.
3710
+ script += `click ${step.target}\n`;
3688
3711
  break;
3689
3712
  case "fill":
3690
- script += `fill "${step.target}" "${step.value}"\n`;
3713
+ // The parser wants the VALUE quoted and the field bare.
3714
+ script += `fill ${step.target} with "${step.value}"\n`;
3691
3715
  break;
3692
3716
  case "assert":
3693
- script += `assert "${step.target}"\n`;
3717
+ // step.target is already a predicate, e.g. url contains '/docs/'.
3718
+ script += `assert ${step.target}\n`;
3694
3719
  break;
3695
3720
  case "wait":
3696
- script += `# wait ${step.value}ms\n`;
3721
+ script += `wait ${Math.max(1, Math.round(Number(step.value ?? 1000) / 1000))} seconds\n`;
3697
3722
  break;
3698
3723
  }
3699
3724
  }
3725
+ // test.assertions are intentions, not executable steps — "no console
3726
+ // errors" has no rule, and the grammar has no OR. Emitting them as steps
3727
+ // produced unparseable lines, so they ship as comments.
3700
3728
  for (const assertion of test.assertions) {
3701
- script += `assert "${assertion}"\n`;
3729
+ script += `# expected: ${assertion}\n`;
3702
3730
  }
3703
3731
  script += "\n";
3704
3732
  }
@@ -3888,7 +3916,11 @@ For more help: https://playwright.dev/docs/browsers
3888
3916
  return {
3889
3917
  tag: el.tagName.toLowerCase(),
3890
3918
  text: el.innerText?.trim().substring(0, 80) || el.getAttribute("aria-label") || el.getAttribute("value") || "",
3891
- selector: el.id ? `#${el.id}` : el.getAttribute("data-testid") ? `[data-testid="${el.getAttribute("data-testid")}"]` : `${el.tagName.toLowerCase()}:nth-of-type(${i + 1})`,
3919
+ selector: el.getAttribute("data-testid")
3920
+ ? `[data-testid="${el.getAttribute("data-testid").replace(/"/g, '\\"')}"]`
3921
+ : el.id
3922
+ ? `#${CSS.escape(el.id)}`
3923
+ : `${el.tagName.toLowerCase()}:nth-of-type(${i + 1})`,
3892
3924
  role: el.getAttribute("role") || undefined,
3893
3925
  aboveFold,
3894
3926
  region: classifyRegion(el, r.top, r.bottom),
@@ -4369,14 +4401,19 @@ For more help: https://playwright.dev/docs/browsers
4369
4401
  // Convert ElementHandle back to Locator isn't directly possible,
4370
4402
  // but we can get a selector from it
4371
4403
  const generatedSelector = await page.evaluate((el) => {
4404
+ // Escaped, and ARIA-first — see the note on analyzePage's getSelector.
4405
+ const q = (v) => v.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
4406
+ const ariaLabel = el.getAttribute("aria-label");
4407
+ if (ariaLabel)
4408
+ return `[aria-label="${q(ariaLabel)}"]`;
4409
+ const testId = el.getAttribute("data-testid");
4410
+ if (testId)
4411
+ return `[data-testid="${q(testId)}"]`;
4372
4412
  if (el.id)
4373
- return `#${el.id}`;
4413
+ return `#${CSS.escape(el.id)}`;
4374
4414
  const name = el.getAttribute("name");
4375
4415
  if (name)
4376
- return `[name="${name}"]`;
4377
- const testId = el.getAttribute("data-testid");
4378
- if (testId)
4379
- return `[data-testid="${testId}"]`;
4416
+ return `[name="${q(name)}"]`;
4380
4417
  return null;
4381
4418
  }, element);
4382
4419
  if (generatedSelector) {
@@ -4519,14 +4556,19 @@ For more help: https://playwright.dev/docs/browsers
4519
4556
  const element = fuzzyHandle.asElement();
4520
4557
  if (element) {
4521
4558
  const generatedSelector = await page.evaluate((el) => {
4559
+ // Escaped, and ARIA-first — see the note on analyzePage's getSelector.
4560
+ const q = (v) => v.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
4561
+ const ariaLabel = el.getAttribute("aria-label");
4562
+ if (ariaLabel)
4563
+ return `[aria-label="${q(ariaLabel)}"]`;
4564
+ const testId = el.getAttribute("data-testid");
4565
+ if (testId)
4566
+ return `[data-testid="${q(testId)}"]`;
4522
4567
  if (el.id)
4523
- return `#${el.id}`;
4568
+ return `#${CSS.escape(el.id)}`;
4524
4569
  const name = el.getAttribute("name");
4525
4570
  if (name)
4526
- return `[name="${name}"]`;
4527
- const testId = el.getAttribute("data-testid");
4528
- if (testId)
4529
- return `[data-testid="${testId}"]`;
4571
+ return `[name="${q(name)}"]`;
4530
4572
  return null;
4531
4573
  }, element);
4532
4574
  if (generatedSelector) {