Skip to content

Commit be8497c

Browse files
fix: incorrect nested iframe xpaths (#891)
1 parent f75f5fb commit be8497c

File tree

5 files changed

+63
-4
lines changed

5 files changed

+63
-4
lines changed

.changeset/rich-bobcats-sneeze.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@browserbasehq/stagehand": patch
3+
---
4+
5+
fix: nested iframe xpath bug

evals/evals.config.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,10 @@
382382
{
383383
"name": "hidden_input_dropdown",
384384
"categories": ["act"]
385+
},
386+
{
387+
"name": "nested_iframes_2",
388+
"categories": ["act"]
385389
}
386390
]
387391
}

evals/tasks/nested_iframes_2.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { EvalFunction } from "@/types/evals";
2+
import { FrameLocator } from "playwright";
3+
4+
export const nested_iframes_2: EvalFunction = async ({
5+
debugUrl,
6+
sessionUrl,
7+
stagehand,
8+
logger,
9+
}) => {
10+
const page = stagehand.page;
11+
try {
12+
await page.goto(
13+
"https://browserbase.github.io/stagehand-eval-sites/sites/nested-iframes-2/",
14+
);
15+
16+
await page.act({
17+
action: "click the button called 'click me (inner 2)'",
18+
iframes: true,
19+
});
20+
21+
const inner: FrameLocator = page
22+
.frameLocator('iframe[src="iframe2.html"]')
23+
.frameLocator('iframe[src="inner2.html"]');
24+
25+
const messageText = await inner.locator("#msg").textContent();
26+
27+
const passed: boolean =
28+
messageText.toLowerCase().trim() ===
29+
"clicked the button in the second inner iframe";
30+
31+
return {
32+
_success: passed,
33+
logs: logger.getLogs(),
34+
debugUrl,
35+
sessionUrl,
36+
};
37+
} catch (error) {
38+
return {
39+
_success: false,
40+
logs: logger.getLogs(),
41+
debugUrl,
42+
sessionUrl,
43+
error,
44+
};
45+
} finally {
46+
await stagehand.close();
47+
}
48+
};

lib/a11y/utils.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,7 @@ export async function getAccessibilityTreeWithFrames(
894894
const frameId = await getCDPFrameId(stagehandPage, frame);
895895

896896
snapshots.push({
897+
frame,
897898
tree: res.simplified.trimEnd(),
898899
xpathMap: res.xpathMap as Record<EncodedId, string>,
899900
urlMap: res.idToUrl as Record<string, string>,
@@ -918,15 +919,15 @@ export async function getAccessibilityTreeWithFrames(
918919
const combinedXpathMap: Record<EncodedId, string> = {};
919920
const combinedUrlMap: Record<EncodedId, string> = {};
920921

921-
const seg = new Map<Frame | null, string>();
922-
for (const s of snapshots) seg.set(s.parentFrame, s.frameXpath);
922+
const seg = new Map<Frame, string>();
923+
for (const s of snapshots) seg.set(s.frame, s.frameXpath);
923924

924925
/* recursively build the full prefix for a frame */
925926
function fullPrefix(f: Frame | null): string {
926-
if (!f) return ""; // reached main
927+
if (!f || f === main) return "";
927928
const parent = f.parentFrame();
928929
const above = fullPrefix(parent);
929-
const hop = seg.get(parent) ?? "";
930+
const hop = seg.get(f) ?? "";
930931
return hop === "/"
931932
? above
932933
: above

types/context.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export interface CombinedA11yResult {
105105
}
106106

107107
export interface FrameSnapshot {
108+
frame: Frame;
108109
tree: string;
109110
xpathMap: Record<EncodedId, string>;
110111
urlMap: Record<EncodedId, string>;

0 commit comments

Comments
 (0)