Skip to content

add support for shadow doms (open & closed mode) #954

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/calm-snails-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@browserbasehq/stagehand": patch
---

add support for shadow DOMs (open & closed mode) when experimental: true
36 changes: 36 additions & 0 deletions evals/evals.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,42 @@
{
"name": "agent/sign_in",
"categories": ["agent"]
},
{
"name": "osr_in_oopif",
"categories": ["act"]
},
{
"name": "csr_in_oopif",
"categories": ["act"]
},
{
"name": "csr_in_spif",
"categories": ["act"]
},
{
"name": "csr_in_spif",
"categories": ["act"]
},
{
"name": "spif_in_osr",
"categories": ["act"]
},
{
"name": "oopif_in_osr",
"categories": ["act"]
},
{
"name": "spif_in_csr",
"categories": ["act"]
},
{
"name": "oopif_in_csr",
"categories": ["act"]
},
{
"name": "osr_in_spif",
"categories": ["act"]
}
]
}
54 changes: 54 additions & 0 deletions evals/tasks/csr_in_oopif.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { EvalFunction } from "@/types/evals";

export const csr_in_oopif: EvalFunction = async ({
debugUrl,
sessionUrl,
stagehand,
logger,
}) => {
// this eval is designed to test whether stagehand can successfully
// click inside an CSR (closed mode shadow) root that is inside an
// OOPIF (out of process iframe)

const page = stagehand.page;
try {
await page.goto(
"https://browserbase.github.io/stagehand-eval-sites/sites/closed-shadow-root-in-oopif/",
);
await page.act({ action: "click the button", iframes: true });

const extraction = await page.extract({
instruction: "extract the entire page text",
iframes: true,
});

const pageText = extraction.extraction;

if (pageText.includes("button successfully clicked")) {
return {
_success: true,
message: `successfully clicked the button`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
}
return {
_success: false,
message: `unable to click on the button`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
} catch (error) {
return {
_success: false,
message: `error: ${error.message}`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
} finally {
await stagehand.close();
}
};
54 changes: 54 additions & 0 deletions evals/tasks/csr_in_spif.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { EvalFunction } from "@/types/evals";

export const csr_in_spif: EvalFunction = async ({
debugUrl,
sessionUrl,
stagehand,
logger,
}) => {
// this eval is designed to test whether stagehand can successfully
// click inside an CSR (closed mode shadow) root that is inside an
// SPIF (same process iframe)

const page = stagehand.page;
try {
await page.goto(
"https://browserbase.github.io/stagehand-eval-sites/sites/closed-shadow-dom-in-spif/",
);
await page.act({ action: "click the button", iframes: true });

const extraction = await page.extract({
instruction: "extract the entire page text",
iframes: true,
});

const pageText = extraction.extraction;

if (pageText.includes("button successfully clicked")) {
return {
_success: true,
message: `successfully clicked the button`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
}
return {
_success: false,
message: `unable to click on the button`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
} catch (error) {
return {
_success: false,
message: `error: ${error.message}`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
} finally {
await stagehand.close();
}
};
57 changes: 57 additions & 0 deletions evals/tasks/oopif_in_csr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { EvalFunction } from "@/types/evals";

export const oopif_in_csr: EvalFunction = async ({
debugUrl,
sessionUrl,
stagehand,
logger,
}) => {
// this eval is designed to test whether stagehand can successfully
// fill a form inside a OOPIF (out of process iframe) that is inside an
// CSR (closed mode shadow) root

const page = stagehand.page;
try {
await page.goto(
"https://browserbase.github.io/stagehand-eval-sites/sites/oopif-in-open-shadow-dom/",
);
await page.act({
action: "fill 'nunya' into the first name field",
iframes: true,
});

const extraction = await page.extract({
instruction: "extract the entire page text",
iframes: true,
});

const pageText = extraction.extraction;

if (pageText.includes("nunya")) {
return {
_success: true,
message: `successfully filled the form`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
}
return {
_success: false,
message: `unable to fill the form`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
} catch (error) {
return {
_success: false,
message: `error: ${error.message}`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
} finally {
await stagehand.close();
}
};
57 changes: 57 additions & 0 deletions evals/tasks/oopif_in_osr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { EvalFunction } from "@/types/evals";

export const oopif_in_osr: EvalFunction = async ({
debugUrl,
sessionUrl,
stagehand,
logger,
}) => {
// this eval is designed to test whether stagehand can successfully
// fill a form inside a OOPIF (out of process iframe) that is inside an
// OSR (open mode shadow) root

const page = stagehand.page;
try {
await page.goto(
"https://browserbase.github.io/stagehand-eval-sites/sites/oopif-in-open-shadow-dom/",
);
await page.act({
action: "fill 'nunya' into the first name field",
iframes: true,
});

const extraction = await page.extract({
instruction: "extract the entire page text",
iframes: true,
});

const pageText = extraction.extraction;

if (pageText.includes("nunya")) {
return {
_success: true,
message: `successfully filled the form`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
}
return {
_success: false,
message: `unable to fill the form`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
} catch (error) {
return {
_success: false,
message: `error: ${error.message}`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
} finally {
await stagehand.close();
}
};
54 changes: 54 additions & 0 deletions evals/tasks/osr_in_oopif.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { EvalFunction } from "@/types/evals";

export const osr_in_oopif: EvalFunction = async ({
debugUrl,
sessionUrl,
stagehand,
logger,
}) => {
// this eval is designed to test whether stagehand can successfully
// click inside an OSR (open mode shadow) root that is inside an
// OOPIF (out of process iframe)

const page = stagehand.page;
try {
await page.goto(
"https://browserbase.github.io/stagehand-eval-sites/sites/open-shadow-root-in-oopif/",
);
await page.act({ action: "click the button", iframes: true });

const extraction = await page.extract({
instruction: "extract the entire page text",
iframes: true,
});

const pageText = extraction.extraction;

if (pageText.includes("button successfully clicked")) {
return {
_success: true,
message: `successfully clicked the button`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
}
return {
_success: false,
message: `unable to click on the button`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
} catch (error) {
return {
_success: false,
message: `error: ${error.message}`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
} finally {
await stagehand.close();
}
};
54 changes: 54 additions & 0 deletions evals/tasks/osr_in_spif.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { EvalFunction } from "@/types/evals";

export const osr_in_spif: EvalFunction = async ({
debugUrl,
sessionUrl,
stagehand,
logger,
}) => {
// this eval is designed to test whether stagehand can successfully
// click inside an OSR (open mode shadow) root that is inside an
// SPIF (same process iframe)

const page = stagehand.page;
try {
await page.goto(
"https://browserbase.github.io/stagehand-eval-sites/sites/open-shadow-root-in-spif/",
);
await page.act({ action: "click the button", iframes: true });

const extraction = await page.extract({
instruction: "extract the entire page text",
iframes: true,
});

const pageText = extraction.extraction;

if (pageText.includes("button successfully clicked")) {
return {
_success: true,
message: `successfully clicked the button`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
}
return {
_success: false,
message: `unable to click on the button`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
} catch (error) {
return {
_success: false,
message: `error: ${error.message}`,
debugUrl,
sessionUrl,
logs: logger.getLogs(),
};
} finally {
await stagehand.close();
}
};
Loading