#![cfg(feature = "integration")]
use std::sync::Once;
use std::time::Duration;
use viewpoint_core::DocumentLoadState;
use viewpoint_test::{TestHarness, expect, expect_page};
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 e2e_form_interaction() {
init_tracing();
let harness = TestHarness::new().await.expect("should create harness");
let page = harness.page();
page.goto("https://httpbin.org/forms/post")
.wait_until(DocumentLoadState::Load)
.goto()
.await
.expect("should navigate");
expect_page(page)
.to_have_url_containing("httpbin.org/forms")
.await
.expect("should be on forms page");
let name_input = page.locator("input[name='custname']");
expect(&name_input)
.to_be_visible()
.await
.expect("name input should be visible");
name_input.fill("John Doe").await.expect("should fill name");
let phone_input = page.locator("input[name='custtel']");
phone_input.click().await.expect("should click phone");
phone_input
.type_text("555-1234")
.await
.expect("should type phone");
let email_input = page.locator("input[name='custemail']");
email_input
.fill("john@example.com")
.await
.expect("should fill email");
let medium_size = page.locator("input[value='medium']");
medium_size.click().await.expect("should select medium");
let cheese = page.locator("input[value='cheese']");
cheese.check().await.expect("should check cheese");
expect(&cheese)
.to_be_checked()
.await
.expect("cheese should be checked");
let mushrooms = page.locator("input[value='mushroom']");
mushrooms.check().await.expect("should check mushrooms");
expect(&mushrooms)
.to_be_checked()
.await
.expect("mushrooms should be checked");
mushrooms.uncheck().await.expect("should uncheck mushrooms");
expect(&mushrooms)
.not()
.to_be_checked()
.await
.expect("mushrooms should be unchecked");
let time_input = page.locator("input[name='delivery']");
time_input.fill("18:00").await.expect("should fill time");
let comments = page.locator("textarea[name='comments']");
comments
.fill("Please ring the doorbell twice.")
.await
.expect("should fill comments");
}
#[tokio::test]
async fn e2e_navigation_and_content() {
init_tracing();
let harness = TestHarness::new().await.expect("should create harness");
let page = harness.page();
page.goto("https://example.com")
.wait_until(DocumentLoadState::DomContentLoaded)
.goto()
.await
.expect("should navigate to example.com");
expect_page(page)
.to_have_title("Example Domain")
.await
.expect("should have correct title");
expect_page(page)
.to_have_url_containing("example.com")
.await
.expect("should have correct URL");
let heading = page.locator("h1");
expect(&heading)
.to_be_visible()
.await
.expect("heading should be visible");
expect(&heading)
.to_have_text("Example Domain")
.await
.expect("heading should have correct text");
let paragraphs = page.locator("p");
let count = paragraphs.count().await.expect("should count paragraphs");
assert!(count >= 1, "should have at least one paragraph");
page.goto("https://httpbin.org/html")
.wait_until(DocumentLoadState::DomContentLoaded)
.goto()
.await
.expect("should navigate to httpbin");
expect_page(page)
.to_have_url_containing("httpbin.org")
.await
.expect("should be on httpbin");
let body = page.locator("body");
expect(&body)
.to_contain_text("Herman Melville")
.await
.expect("should contain expected text");
}
#[tokio::test]
async fn e2e_element_selection() {
init_tracing();
let harness = TestHarness::new().await.expect("should create harness");
let page = harness.page();
page.goto("https://example.com")
.wait_until(DocumentLoadState::DomContentLoaded)
.goto()
.await
.expect("should navigate");
let h1 = page.locator("h1");
expect(&h1)
.to_be_visible()
.await
.expect("h1 should be visible");
let by_text = page.get_by_text("Example Domain");
expect(&by_text)
.to_be_visible()
.await
.expect("text element should be visible");
let chained = page.locator("body").locator("div").locator("h1");
expect(&chained)
.to_be_visible()
.await
.expect("chained locator should find element");
let first_p = page.locator("p").first();
expect(&first_p)
.to_be_visible()
.await
.expect("first paragraph should be visible");
}
#[tokio::test]
async fn e2e_mouse_interactions() {
init_tracing();
let harness = TestHarness::new().await.expect("should create harness");
let page = harness.page();
page.goto("https://example.com")
.wait_until(DocumentLoadState::DomContentLoaded)
.goto()
.await
.expect("should navigate");
let heading = page.locator("h1");
heading.hover().await.expect("should hover over heading");
heading
.dblclick()
.await
.expect("should double-click heading");
let link = page.locator("a");
expect(&link)
.to_be_visible()
.await
.expect("link should be visible");
}
#[tokio::test]
async fn e2e_keyboard_interactions() {
init_tracing();
let harness = TestHarness::new().await.expect("should create harness");
let page = harness.page();
page.goto("https://httpbin.org/forms/post")
.wait_until(DocumentLoadState::Load)
.goto()
.await
.expect("should navigate");
let input = page.locator("input[name='custname']");
input.focus().await.expect("should focus input");
input.type_text("Test").await.expect("should type");
input.press("Tab").await.expect("should press Tab");
let phone = page.locator("input[name='custtel']");
phone.fill("12345").await.expect("should fill");
phone.press("Control+a").await.expect("should select all");
phone.press("Backspace").await.expect("should delete");
}
#[tokio::test]
async fn e2e_assertion_negation() {
init_tracing();
let harness = TestHarness::new().await.expect("should create harness");
let page = harness.page();
page.goto("https://example.com")
.wait_until(DocumentLoadState::DomContentLoaded)
.goto()
.await
.expect("should navigate");
let heading = page.locator("h1");
expect(&heading)
.not()
.to_have_text("Wrong Title")
.await
.expect("should not have wrong text");
let nonexistent = page.locator("#does-not-exist");
expect(&nonexistent)
.to_be_hidden()
.await
.expect("nonexistent should be hidden");
expect(&nonexistent)
.not()
.to_be_visible()
.await
.expect("nonexistent should not be visible");
expect_page(page)
.not()
.to_have_url("https://google.com")
.await
.expect("should not be on google");
expect_page(page)
.not()
.to_have_title("Google")
.await
.expect("should not have Google title");
}
#[tokio::test]
async fn e2e_custom_timeouts() {
init_tracing();
let harness = TestHarness::new().await.expect("should create harness");
let page = harness.page();
page.goto("https://example.com")
.wait_until(DocumentLoadState::DomContentLoaded)
.goto()
.await
.expect("should navigate");
let heading = page.locator("h1");
expect(&heading)
.timeout(Duration::from_millis(500))
.to_be_visible()
.await
.expect("should find element quickly");
let result = expect(&heading)
.timeout(Duration::from_millis(100))
.to_have_text("Wrong Text")
.await;
assert!(
result.is_err(),
"should fail with wrong text and short timeout"
);
}
#[tokio::test]
async fn e2e_multiple_pages() {
init_tracing();
let harness = TestHarness::new().await.expect("should create harness");
let page1 = harness.page();
page1
.goto("https://example.com")
.wait_until(DocumentLoadState::DomContentLoaded)
.goto()
.await
.expect("should navigate page 1");
let page2 = harness.new_page().await.expect("should create second page");
page2
.goto("https://httpbin.org/html")
.wait_until(DocumentLoadState::DomContentLoaded)
.goto()
.await
.expect("should navigate page 2");
expect_page(page1)
.to_have_title("Example Domain")
.await
.expect("page 1 should have correct title");
let page2_body = page2.locator("body");
expect(&page2_body)
.to_contain_text("Herman Melville")
.await
.expect("page 2 should have correct content");
}