#![allow(
clippy::too_many_lines,
clippy::doc_markdown,
clippy::uninlined_format_args,
clippy::unwrap_used,
clippy::expect_used,
clippy::needless_pass_by_value
)]
use super::client::McpClient;
pub fn test_dialog_accept_confirm(c: &mut McpClient) {
let script = r#"
await page.goto("data:text/html,<script>setTimeout(()=>{document.title = confirm('sure?') ? 'yes' : 'no'}, 80)</script>");
const dialog = await page.waitForEvent("dialog", 10000);
const info = { type: dialog.type(), message: dialog.message() };
await dialog.accept();
// Give the page's setTimeout a moment to observe the accepted
// confirm and update the title.
for (let i = 0; i < 100; i++) {
const t = await page.title();
if (t === "yes" || t === "no") return { ...info, title: t };
await new Promise(r => { let d = Date.now() + 25; while (Date.now() < d) {} });
}
return { ...info, title: await page.title() };
"#;
if c.backend == "webkit" {
let payload = c.script(script);
let status = payload["status"].as_str().unwrap_or("");
if status == "error" {
let msg = payload["error"]["message"].as_str().unwrap_or("");
assert!(
msg.contains("Timeout") || msg.contains("not supported") || msg.contains("unsupported"),
"webkit dialog path should surface Timeout or Unsupported, got: {msg}",
);
} else {
}
return;
}
let v = c.script_value(script);
assert_eq!(v["type"].as_str(), Some("confirm"), "dialog type: {v}");
assert!(
v["message"].as_str().is_some_and(|m| m.contains("sure")),
"dialog message carries page text: {v}",
);
assert_eq!(v["title"].as_str(), Some("yes"), "accepting confirm → title 'yes': {v}");
}
pub fn test_dialog_dismiss_confirm(c: &mut McpClient) {
if c.backend == "webkit" {
return; }
let script = r#"
await page.goto("data:text/html,<script>setTimeout(()=>{document.title = confirm('ok?') ? 'yes' : 'no'}, 80)</script>");
const dialog = await page.waitForEvent("dialog", 10000);
await dialog.dismiss();
for (let i = 0; i < 100; i++) {
const t = await page.title();
if (t === "yes" || t === "no") return { title: t };
await new Promise(r => { let d = Date.now() + 25; while (Date.now() < d) {} });
}
return { title: await page.title() };
"#;
let v = c.script_value(script);
assert_eq!(v["title"].as_str(), Some("no"), "dismissing confirm → 'no': {v}");
}
pub fn test_dialog_prompt_with_text(c: &mut McpClient) {
if c.backend == "webkit" {
return;
}
let script = r#"
await page.goto("data:text/html,<script>setTimeout(()=>{document.title = prompt('name?', 'alice') || 'null'}, 80)</script>");
const dialog = await page.waitForEvent("dialog", 10000);
const info = {
type: dialog.type(),
defaultValue: dialog.defaultValue(),
};
await dialog.accept("bob");
for (let i = 0; i < 100; i++) {
const t = await page.title();
if (t && t !== "") return { ...info, title: t };
await new Promise(r => { let d = Date.now() + 25; while (Date.now() < d) {} });
}
return { ...info, title: await page.title() };
"#;
let v = c.script_value(script);
assert_eq!(v["type"].as_str(), Some("prompt"), "dialog type: {v}");
assert_eq!(v["defaultValue"].as_str(), Some("alice"), "default: {v}");
assert_eq!(v["title"].as_str(), Some("bob"), "accepted prompt text wins: {v}");
}
pub fn test_dialog_double_accept_rejects(c: &mut McpClient) {
if c.backend == "webkit" {
return;
}
let script = r#"
await page.goto("data:text/html,<script>setTimeout(()=>{alert('once')}, 80)</script>");
const dialog = await page.waitForEvent("dialog", 10000);
await dialog.accept();
let threw = false;
let message = "";
try {
await dialog.accept();
} catch (e) {
threw = true;
message = String(e && e.message || e);
}
return { threw, message };
"#;
let v = c.script_value(script);
assert_eq!(v["threw"].as_bool(), Some(true), "second accept should reject: {v}");
assert!(
v["message"].as_str().is_some_and(|m| m.contains("already handled")),
"rejection uses Playwright's exact wording: {v}",
);
}
pub fn test_dialog_auto_dismiss_without_listener(c: &mut McpClient) {
if c.backend == "webkit" {
return; }
c.nav_url("data:text/html,<script>document.title = confirm('no listener?') ? 'yes' : 'no'</script>");
let script = r"
return { title: await page.title() };
";
let v = c.script_value(script);
assert_eq!(
v["title"].as_str(),
Some("no"),
"without a dialog listener the backend auto-dismisses: {v}",
);
}
pub fn test_dialog_page_accessor(c: &mut McpClient) {
let script = r#"
await page.goto("data:text/html,<title>dlg</title><script>setTimeout(()=>{document.title = confirm('p?') ? 'y' : 'n'}, 80)</script>");
const dialog = await page.waitForEvent("dialog", 10000);
const dlgPage = dialog.page();
const out = {
hasPage: dlgPage != null,
sameUrl: dlgPage != null ? (dlgPage.url() === page.url()) : false,
};
await dialog.accept();
return out;
"#;
if c.backend == "webkit" {
let payload = c.script(script);
let status = payload["status"].as_str().unwrap_or("");
if status == "error" {
let msg = payload["error"]["message"].as_str().unwrap_or("");
assert!(
msg.contains("Timeout") || msg.contains("not supported") || msg.contains("unsupported"),
"webkit dialog path should surface Timeout or Unsupported, got: {msg}",
);
}
return;
}
let v = c.script_value(script);
assert_eq!(v["hasPage"].as_bool(), Some(true), "dialog.page() returns a page: {v}");
assert_eq!(
v["sameUrl"].as_bool(),
Some(true),
"dialog.page().url() matches the owning page url: {v}",
);
}