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.
- package/dist/analysis/accessibility-empathy.d.ts.map +1 -1
- package/dist/analysis/accessibility-empathy.js +25 -4
- package/dist/analysis/accessibility-empathy.js.map +1 -1
- package/dist/analysis/natural-language.d.ts.map +1 -1
- package/dist/analysis/natural-language.js +9 -8
- package/dist/analysis/natural-language.js.map +1 -1
- package/dist/analysis/page-understanding.d.ts.map +1 -1
- package/dist/analysis/page-understanding.js +38 -2
- package/dist/analysis/page-understanding.js.map +1 -1
- package/dist/artifact-store.d.ts +55 -0
- package/dist/artifact-store.d.ts.map +1 -0
- package/dist/artifact-store.js +63 -0
- package/dist/artifact-store.js.map +1 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +64 -22
- package/dist/browser.js.map +1 -1
- package/dist/mcp-tools/base/audit-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/audit-tools.js +117 -33
- package/dist/mcp-tools/base/audit-tools.js.map +1 -1
- package/dist/mcp-tools/base/gif-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/gif-tools.js +7 -7
- package/dist/mcp-tools/base/gif-tools.js.map +1 -1
- package/dist/mcp-tools/base/persona-comparison-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/persona-comparison-tools.js +78 -10
- package/dist/mcp-tools/base/persona-comparison-tools.js.map +1 -1
- package/dist/mcp-tools/base/site-knowledge-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/site-knowledge-tools.js +32 -0
- package/dist/mcp-tools/base/site-knowledge-tools.js.map +1 -1
- package/dist/mcp-tools/base/visual-testing-tools.d.ts.map +1 -1
- package/dist/mcp-tools/base/visual-testing-tools.js +19 -23
- package/dist/mcp-tools/base/visual-testing-tools.js.map +1 -1
- package/dist/mcp-tools/persona-creation-tools.d.ts.map +1 -1
- package/dist/mcp-tools/persona-creation-tools.js +22 -10
- package/dist/mcp-tools/persona-creation-tools.js.map +1 -1
- package/dist/mcp-ui-resources.d.ts +83 -0
- package/dist/mcp-ui-resources.d.ts.map +1 -0
- package/dist/mcp-ui-resources.js +128 -0
- package/dist/mcp-ui-resources.js.map +1 -0
- package/dist/selector-escape.d.ts +37 -0
- package/dist/selector-escape.d.ts.map +1 -0
- package/dist/selector-escape.js +83 -0
- package/dist/selector-escape.js.map +1 -0
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/visual/attention-quality.d.ts +0 -9
- package/dist/visual/attention-quality.d.ts.map +1 -1
- package/dist/visual/attention-quality.js +28 -1
- package/dist/visual/attention-quality.js.map +1 -1
- package/dist/visual/barrier-overlay-html.d.ts +88 -0
- package/dist/visual/barrier-overlay-html.d.ts.map +1 -0
- package/dist/visual/barrier-overlay-html.js +142 -0
- package/dist/visual/barrier-overlay-html.js.map +1 -0
- package/dist/visual/cognitive-transport.d.ts +0 -6
- package/dist/visual/cognitive-transport.d.ts.map +1 -1
- package/dist/visual/cognitive-transport.js +28 -3
- package/dist/visual/cognitive-transport.js.map +1 -1
- package/dist/visual/cross-browser.d.ts +13 -0
- package/dist/visual/cross-browser.d.ts.map +1 -1
- package/dist/visual/cross-browser.js +29 -3
- package/dist/visual/cross-browser.js.map +1 -1
- 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
|
-
|
|
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 += `
|
|
3706
|
+
script += `go to ${step.target}\n`;
|
|
3685
3707
|
break;
|
|
3686
3708
|
case "click":
|
|
3687
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 +=
|
|
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 +=
|
|
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.
|
|
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) {
|