#![cfg(feature = "integration")]
use std::sync::Arc;
use std::sync::Once;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Duration;
use viewpoint_core::Browser;
static TRACING_INIT: Once = Once::new();
fn init_tracing() {
TRACING_INIT.call_once(|| {
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::from_default_env()
.add_directive(tracing::Level::INFO.into()),
)
.with_test_writer()
.try_init()
.ok();
});
}
#[tokio::test]
async fn test_main_frame() {
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.goto_url("https://example.com")
.await
.expect("Failed to navigate");
let main_frame = page.main_frame().await.expect("Failed to get main frame");
let url = main_frame.url();
assert!(
url.contains("example.com"),
"Main frame URL should contain example.com, got: {url}"
);
assert!(main_frame.is_main(), "Should be main frame");
assert!(
main_frame.parent_id().is_none(),
"Main frame should have no parent"
);
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_main_frame_access() {
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 Frame</h1></body></html>")
.set()
.await
.expect("Failed to set content");
let main_frame = page.main_frame().await.expect("Failed to get main frame");
let _ = main_frame.name();
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_frames_list() {
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.goto_url("https://example.com")
.await
.expect("Failed to navigate");
let frames = page.frames().await.expect("Failed to get frames");
assert!(!frames.is_empty(), "Should have at least one frame");
assert!(frames[0].is_main(), "First frame should be main frame");
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_list_frames() {
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>
<iframe name="frame1" srcdoc="<html><body>Frame 1</body></html>"></iframe>
<iframe name="frame2" srcdoc="<html><body>Frame 2</body></html>"></iframe>
</body></html>
"#,
)
.set()
.await
.expect("Failed to set content");
tokio::time::sleep(Duration::from_millis(200)).await;
let frames = page.frames().await.expect("Failed to get frames");
assert!(
frames.len() >= 3,
"Should have at least 3 frames (main + 2 iframes), got {}",
frames.len()
);
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_frame_properties() {
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.goto_url("https://example.com")
.await
.expect("Failed to navigate");
let main_frame = page.main_frame().await.expect("Failed to get main frame");
let url = main_frame.url();
assert!(
url.contains("example.com"),
"URL should contain example.com"
);
let content = main_frame.content().await.expect("Failed to get content");
assert!(content.contains("<html"), "Content should contain HTML");
assert!(
content.contains("Example Domain"),
"Content should contain page text"
);
let title = main_frame.title().await.expect("Failed to get title");
assert!(!title.is_empty(), "Title should not be empty");
assert!(
!main_frame.is_detached(),
"Main frame should not be detached"
);
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_frame_locator_creation() {
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.goto_url("https://example.com")
.await
.expect("Failed to navigate");
let frame_locator = page.frame_locator("#non-existent-frame");
assert_eq!(frame_locator.selector(), "#non-existent-frame");
assert!(!frame_locator.page().is_closed());
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_nested_frame_locator() {
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.goto_url("https://example.com")
.await
.expect("Failed to navigate");
let outer = page.frame_locator("#outer-frame");
let inner = outer.frame_locator("#inner-frame");
assert_eq!(inner.selector(), "#inner-frame");
assert_eq!(inner.parent_selectors().len(), 1);
assert_eq!(inner.parent_selectors()[0], "#outer-frame");
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_frame_locator() {
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>
<iframe id="myframe" srcdoc="<html><body><button id='btn'>Click me</button></body></html>"></iframe>
</body></html>
"#)
.set()
.await
.expect("Failed to set content");
tokio::time::sleep(Duration::from_millis(200)).await;
let frame_locator = page.frame_locator("#myframe");
let button = frame_locator.locator("#btn");
let text = button.text_content().await.expect("Failed to get text");
assert_eq!(text, Some("Click me".to_string()));
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_frame_attached_event() {
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");
let handler_called = Arc::new(AtomicBool::new(false));
let handler_called_clone = handler_called.clone();
page.on_frameattached(move |_frame| {
let called = handler_called_clone.clone();
async move {
called.store(true, Ordering::SeqCst);
}
})
.await;
page.set_content(
r#"
<html><body>
<div id="container"></div>
<script>
setTimeout(() => {
const iframe = document.createElement('iframe');
iframe.src = 'about:blank';
document.getElementById('container').appendChild(iframe);
}, 100);
</script>
</body></html>
"#,
)
.set()
.await
.expect("Failed to set content");
tokio::time::sleep(Duration::from_millis(500)).await;
assert!(
handler_called.load(Ordering::SeqCst),
"Frame attached handler should have been called"
);
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_frame_detached_event() {
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");
let handler_called = Arc::new(AtomicBool::new(false));
let handler_called_clone = handler_called.clone();
page.on_framedetached(move |_frame| {
let called = handler_called_clone.clone();
async move {
called.store(true, Ordering::SeqCst);
}
})
.await;
page.set_content(
r#"
<html><body>
<iframe id="myframe" src="about:blank"></iframe>
<script>
setTimeout(() => {
document.getElementById('myframe').remove();
}, 200);
</script>
</body></html>
"#,
)
.set()
.await
.expect("Failed to set content");
tokio::time::sleep(Duration::from_millis(500)).await;
assert!(
handler_called.load(Ordering::SeqCst),
"Frame detached handler should have been called"
);
browser.close().await.expect("Failed to close browser");
}