#![cfg(feature = "integration")]
mod common;
use viewpoint_core::{AriaSnapshot, Browser};
#[tokio::test]
async fn test_iframe_refs_resolvable_via_aria_snapshot_with_frames() {
common::init_tracing();
let browser = Browser::launch()
.headless(true)
.launch()
.await
.expect("Failed to launch browser");
let context = browser
.new_context()
.await
.expect("Failed to create context");
let page = context.new_page().await.expect("Failed to create page");
page.set_content(
r#"
<html><body>
<h1>Main Page</h1>
<iframe name="widget" srcdoc="<html><body><button id='iframe-btn'>Iframe Button</button></body></html>"></iframe>
</body></html>
"#,
)
.set()
.await
.expect("Failed to set content");
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
let snapshot = page
.aria_snapshot_with_frames()
.await
.expect("Failed to get multi-frame snapshot");
let yaml = snapshot.to_yaml();
println!("Multi-frame snapshot:\n{yaml}");
let button_ref =
common::find_button_ref(&snapshot).expect("Should find button ref from iframe");
println!("Found iframe button ref: {button_ref}");
assert!(
button_ref.contains("f1"),
"Iframe button ref should have frame index f1, got: {button_ref}"
);
let handle = page
.element_from_ref(&button_ref)
.await
.expect("Iframe refs should now be resolvable via aria_snapshot_with_frames()");
assert!(
handle.is_attached().await.unwrap(),
"Resolved iframe element should be attached"
);
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_click_iframe_element_via_ref() {
common::init_tracing();
let browser = Browser::launch()
.headless(true)
.launch()
.await
.expect("Failed to launch browser");
let context = browser
.new_context()
.await
.expect("Failed to create context");
let page = context.new_page().await.expect("Failed to create page");
page.set_content(
r#"
<html><body>
<h1>Main Page</h1>
<iframe name="widget" srcdoc="<html><body><button onclick='this.innerText = "Clicked!"'>Click Me</button></body></html>"></iframe>
</body></html>
"#,
)
.set()
.await
.expect("Failed to set content");
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
let snapshot = page
.aria_snapshot_with_frames()
.await
.expect("Failed to get multi-frame snapshot");
let button_ref = common::find_button_ref(&snapshot).expect("Should find button ref");
println!("Clicking button with ref: {button_ref}");
page.locator_from_ref(&button_ref)
.click()
.await
.expect("Should be able to click iframe button via ref");
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
let button_text = page
.locator_from_ref(&button_ref)
.text_content()
.await
.expect("Should get button text");
assert_eq!(
button_text,
Some("Clicked!".to_string()),
"Button click should have updated button text"
);
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_type_into_iframe_input_via_ref() {
common::init_tracing();
let browser = Browser::launch()
.headless(true)
.launch()
.await
.expect("Failed to launch browser");
let context = browser
.new_context()
.await
.expect("Failed to create context");
let page = context.new_page().await.expect("Failed to create page");
page.set_content(
r#"
<html><body>
<h1>Main Page</h1>
<iframe name="form-frame" srcdoc="<html><body><label for='name'>Name:</label><input type='text' id='name' placeholder='Enter name'></body></html>"></iframe>
</body></html>
"#,
)
.set()
.await
.expect("Failed to set content");
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
let snapshot = page
.aria_snapshot_with_frames()
.await
.expect("Failed to get multi-frame snapshot");
let yaml = snapshot.to_yaml();
println!("Snapshot:\n{yaml}");
let input_ref = common::find_textbox_ref(&snapshot).expect("Should find textbox ref");
println!("Filling input with ref: {input_ref}");
page.locator_from_ref(&input_ref)
.fill("Test User")
.await
.expect("Should be able to fill iframe input via ref");
let value = page
.locator_from_ref(&input_ref)
.input_value()
.await
.expect("Should get input value");
assert_eq!(value, "Test User", "Input should contain typed text");
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_nested_iframe_refs_resolvable() {
common::init_tracing();
let browser = Browser::launch()
.headless(true)
.launch()
.await
.expect("Failed to launch browser");
let context = browser
.new_context()
.await
.expect("Failed to create context");
let page = context.new_page().await.expect("Failed to create page");
page.set_content(
r#"
<html><body>
<h1>Level 0 Main</h1>
<button id="btn0">Main Button</button>
<iframe name="level1" srcdoc="<html><body><h2>Level 1</h2><button id='btn1'>Level 1 Button</button><iframe name='level2' srcdoc='<html><body><h3>Level 2</h3><button id="btn2">Level 2 Button</button></body></html>'></iframe></body></html>"></iframe>
</body></html>
"#,
)
.set()
.await
.expect("Failed to set content");
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
let snapshot = page
.aria_snapshot_with_frames()
.await
.expect("Failed to get multi-frame snapshot");
let yaml = snapshot.to_yaml();
println!("Nested frames snapshot:\n{yaml}");
let mut button_refs: Vec<String> = Vec::new();
common::collect_refs_by_role(&snapshot, "button", &mut button_refs);
println!("Found button refs: {:?}", button_refs);
assert!(
button_refs.len() >= 2,
"Should have at least 2 button refs, got {}",
button_refs.len()
);
for button_ref in &button_refs {
let handle = page
.element_from_ref(button_ref)
.await
.expect(&format!("Button ref {} should be resolvable", button_ref));
assert!(
handle.is_attached().await.unwrap(),
"Resolved button should be attached"
);
}
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_iframe_refs_have_correct_frame_indices() {
common::init_tracing();
let browser = Browser::launch()
.headless(true)
.launch()
.await
.expect("Failed to launch browser");
let context = browser
.new_context()
.await
.expect("Failed to create context");
let page = context.new_page().await.expect("Failed to create page");
page.set_content(
r#"
<html><body>
<h1>Main Page</h1>
<button id="main-btn">Main Button</button>
<iframe name="frame1" srcdoc="<html><body><button id='btn1'>Frame1 Button</button></body></html>"></iframe>
<iframe name="frame2" srcdoc="<html><body><button id='btn2'>Frame2 Button</button></body></html>"></iframe>
</body></html>
"#,
)
.set()
.await
.expect("Failed to set content");
tokio::time::sleep(std::time::Duration::from_millis(300)).await;
let snapshot = page
.aria_snapshot_with_frames()
.await
.expect("Failed to get multi-frame snapshot");
let yaml = snapshot.to_yaml();
println!("Multi-frame snapshot:\n{yaml}");
fn collect_button_info(snapshot: &AriaSnapshot, info: &mut Vec<(String, String)>) {
if snapshot.role.as_deref() == Some("button") {
if let Some(ref r) = snapshot.node_ref {
let name = snapshot.name.clone().unwrap_or_default();
info.push((name, r.clone()));
}
}
for child in &snapshot.children {
collect_button_info(child, info);
}
}
let mut button_info: Vec<(String, String)> = Vec::new();
collect_button_info(&snapshot, &mut button_info);
println!("Button info: {:?}", button_info);
fn extract_frame_index(ref_str: &str) -> Option<usize> {
let f_pos = ref_str.find('f')?;
let e_pos = ref_str.find('e')?;
if f_pos < e_pos {
ref_str[f_pos + 1..e_pos].parse().ok()
} else {
None
}
}
let main_btn = button_info
.iter()
.find(|(name, _)| name.contains("Main"))
.expect("Should find main button");
let main_frame_idx =
extract_frame_index(&main_btn.1).expect("Main button should have frame index");
assert_eq!(
main_frame_idx, 0,
"Main frame button should have frame index 0"
);
let frame1_btn = button_info
.iter()
.find(|(name, _)| name.contains("Frame1"))
.expect("Should find frame1 button");
let frame1_idx =
extract_frame_index(&frame1_btn.1).expect("Frame1 button should have frame index");
assert!(
frame1_idx > 0,
"Frame1 button should have frame index > 0, got {}",
frame1_idx
);
let frame2_btn = button_info
.iter()
.find(|(name, _)| name.contains("Frame2"))
.expect("Should find frame2 button");
let frame2_idx =
extract_frame_index(&frame2_btn.1).expect("Frame2 button should have frame index");
assert!(
frame2_idx > 0,
"Frame2 button should have frame index > 0, got {}",
frame2_idx
);
assert_ne!(
frame1_idx, frame2_idx,
"Frame1 and Frame2 should have different frame indices"
);
for (name, ref_str) in &button_info {
let handle = page.element_from_ref(ref_str).await.expect(&format!(
"Button '{}' ref {} should be resolvable",
name, ref_str
));
assert!(
handle.is_attached().await.unwrap(),
"Button '{}' should be attached",
name
);
}
browser.close().await.expect("Failed to close browser");
}