From 1df256bf1a2c17cc899ef9f7cc1c744d80aaa6dc Mon Sep 17 00:00:00 2001 From: Sean McGuire Date: Tue, 12 Aug 2025 10:47:01 -0700 Subject: [PATCH 1/3] handle namespaced elements in xpath build step --- lib/a11y/utils.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/a11y/utils.ts b/lib/a11y/utils.ts index e603961b..6c77af94 100644 --- a/lib/a11y/utils.ts +++ b/lib/a11y/utils.ts @@ -222,13 +222,18 @@ export async function buildBackendIdMaps( const tag = lc(String(child.nodeName)); const key = `${child.nodeType}:${tag}`; const idx = (ctr[key] = (ctr[key] ?? 0) + 1); - segs.push( - child.nodeType === 3 - ? `text()[${idx}]` - : child.nodeType === 8 - ? `comment()[${idx}]` + if (child.nodeType === 3) { + segs.push(`text()[${idx}]`); + } else if (child.nodeType === 8) { + segs.push(`comment()[${idx}]`); + } else { + // Element node: if qualified (e.g. "as:ajaxinclude"), switch to name()='as:ajaxinclude' + segs.push( + tag.includes(":") + ? `*[name()='${tag}'][${idx}]` : `${tag}[${idx}]`, - ); + ); + } } // push R→L so traversal remains L→R for (let i = kids.length - 1; i >= 0; i--) { From 5c3ab2624211ce0ab3e35485dc6aafc6d3ed1228 Mon Sep 17 00:00:00 2001 From: Sean McGuire Date: Tue, 12 Aug 2025 10:47:58 -0700 Subject: [PATCH 2/3] changeset --- .changeset/true-bees-sniff.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/true-bees-sniff.md diff --git a/.changeset/true-bees-sniff.md b/.changeset/true-bees-sniff.md new file mode 100644 index 00000000..df4e6846 --- /dev/null +++ b/.changeset/true-bees-sniff.md @@ -0,0 +1,5 @@ +--- +"@browserbasehq/stagehand": patch +--- + +handle namespaced elements in xpath build step From 0b963e93b299f4b7a0823d9f68a037fb8a1e85ae Mon Sep 17 00:00:00 2001 From: Sean McGuire Date: Tue, 12 Aug 2025 17:17:24 -0700 Subject: [PATCH 3/3] add an eval --- evals/evals.config.json | 4 ++++ evals/tasks/namespace_xpath.ts | 39 ++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 evals/tasks/namespace_xpath.ts diff --git a/evals/evals.config.json b/evals/evals.config.json index 06ed6459..9d3c7ccb 100644 --- a/evals/evals.config.json +++ b/evals/evals.config.json @@ -418,6 +418,10 @@ { "name": "agent/sign_in", "categories": ["agent"] + }, + { + "name": "namespace_xpath", + "categories": ["act"] } ] } diff --git a/evals/tasks/namespace_xpath.ts b/evals/tasks/namespace_xpath.ts new file mode 100644 index 00000000..fe12f500 --- /dev/null +++ b/evals/tasks/namespace_xpath.ts @@ -0,0 +1,39 @@ +import { EvalFunction } from "@/types/evals"; + +export const namespace_xpath: EvalFunction = async ({ + debugUrl, + sessionUrl, + stagehand, + logger, +}) => { + try { + await stagehand.page.goto( + "https://browserbase.github.io/stagehand-eval-sites/sites/namespaced-xpath/", + ); + + await stagehand.page.act({ + action: "fill 'nunya' into the 'type here' form", + }); + + const inputValue = await stagehand.page.locator("#ns-text").inputValue(); + // confirm that the form was filled + const formHasBeenFilled = inputValue === "nunya"; + + return { + _success: formHasBeenFilled, + debugUrl, + sessionUrl, + logs: logger.getLogs(), + }; + } catch (error) { + return { + _success: false, + error: error, + debugUrl, + sessionUrl, + logs: logger.getLogs(), + }; + } finally { + await stagehand.close(); + } +};