use browser_oxide::Page;
#[tokio::test]
async fn iframe_srcdoc_creates_child() {
let page = Page::from_html(
r#"<!DOCTYPE html><html><body>
<iframe srcdoc="<html><body><p>hello from iframe</p></body></html>"></iframe>
</body></html>"#,
None::<browser_oxide::stealth::StealthProfile>,
)
.await
.unwrap();
assert_eq!(page.child_iframe_count(), 1, "should have 1 child iframe");
}
#[tokio::test]
async fn iframe_srcdoc_has_isolated_globals() {
let mut page = Page::from_html(r#"<!DOCTYPE html><html><body>
<script>globalThis.parentVar = 42;</script>
<iframe srcdoc="<html><body><script>globalThis.childVar = 99;</script></body></html>"></iframe>
</body></html>"#, None::<browser_oxide::stealth::StealthProfile>).await.unwrap();
assert_eq!(page.evaluate("parentVar").unwrap(), "42");
assert_eq!(page.evaluate("typeof childVar").unwrap(), "undefined");
assert_eq!(
page.child_iframe(0).unwrap().evaluate("childVar").unwrap(),
"99"
);
assert_eq!(
page.child_iframe(0)
.unwrap()
.evaluate("typeof parentVar")
.unwrap(),
"undefined"
);
}
#[tokio::test]
async fn iframe_child_has_own_document() {
let mut page = Page::from_html(
r#"<!DOCTYPE html><html><body>
<p id="parent-p">parent content</p>
<iframe srcdoc="<html><body><p id='child-p'>child content</p></body></html>"></iframe>
</body></html>"#,
None::<browser_oxide::stealth::StealthProfile>,
)
.await
.unwrap();
assert_eq!(
page.evaluate("document.getElementById('parent-p').textContent")
.unwrap(),
"parent content"
);
assert_eq!(
page.evaluate("document.getElementById('child-p')").unwrap(),
"null"
);
assert_eq!(
page.child_iframe(0)
.unwrap()
.query_text("#child-p")
.unwrap(),
"child content"
);
}
#[tokio::test]
async fn iframe_srcdoc_executes_scripts() {
let mut page = Page::from_html(r#"<!DOCTYPE html><html><body>
<iframe srcdoc="<html><body><div id='target'>before</div><script>document.getElementById('target').textContent = 'after';</script></body></html>"></iframe>
</body></html>"#, None::<browser_oxide::stealth::StealthProfile>).await.unwrap();
assert_eq!(
page.child_iframe(0).unwrap().query_text("#target").unwrap(),
"after"
);
}
#[tokio::test]
async fn multiple_iframes_isolated() {
let mut page = Page::from_html(
r#"<!DOCTYPE html><html><body>
<iframe srcdoc="<script>globalThis.x = 'iframe1';</script>"></iframe>
<iframe srcdoc="<script>globalThis.x = 'iframe2';</script>"></iframe>
</body></html>"#,
None::<browser_oxide::stealth::StealthProfile>,
)
.await
.unwrap();
assert_eq!(page.child_iframe_count(), 2);
assert_eq!(
page.child_iframe(0).unwrap().evaluate("x").unwrap(),
"iframe1"
);
assert_eq!(
page.child_iframe(1).unwrap().evaluate("x").unwrap(),
"iframe2"
);
}
#[ignore = "FP-E1: rescan infra landed; needs createElement/.src arena-interception (decisive experiment recorded in 99 doc)"]
#[tokio::test]
async fn fp_e1_post_js_injected_iframe_is_materialized() {
let profile = browser_oxide::stealth::presets::chrome_148_macos();
let client = browser_oxide::net::HttpClient::new(&profile).unwrap();
let mut page = Page::from_html(
"<!DOCTYPE html><html><body><div id=root></div></body></html>",
Some(profile.clone()),
)
.await
.unwrap();
assert_eq!(page.child_iframe_count(), 0);
page.evaluate(
r#"const f = document.createElement('iframe');
f.srcdoc = "<html><body><script>globalThis.__childRan='yes';</script></body></html>";
document.body.appendChild(f);"#,
)
.unwrap();
let n = page
.rematerialize_iframes("https://example.test/", &client, &profile)
.await;
assert_eq!(n, 1, "post-JS-injected iframe must be materialized");
assert_eq!(page.child_iframe_count(), 1);
assert_eq!(
page.child_iframe(0)
.unwrap()
.evaluate("__childRan")
.unwrap(),
"yes",
"the materialized child must really execute its document's script"
);
let n2 = page
.rematerialize_iframes("https://example.test/", &client, &profile)
.await;
assert_eq!(n2, 0, "rematerialize must be idempotent");
}