use playwright_cdp::options::LaunchOptions;
use playwright_cdp::route::RouteFulfillOptions;
use playwright_cdp::Playwright;
async fn serve(body: &'static str) -> String {
let l = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let port = l.local_addr().unwrap().port();
tokio::spawn(async move {
loop {
let Ok((mut s, _)) = l.accept().await else { break };
tokio::spawn(async move {
use tokio::io::{AsyncReadExt, AsyncWriteExt};
let mut buf = [0u8; 4096];
let _ = s.read(&mut buf).await;
let resp = format!(
"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}",
body.len(),
body
);
let _ = s.write_all(resp.as_bytes()).await;
let _ = s.flush().await;
});
}
});
format!("http://127.0.0.1:{port}/")
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let _ = tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "playwright_cdp=info".into()),
)
.try_init();
let browser = Playwright::launch()
.await?
.chromium()
.launch_with_options(LaunchOptions::default())
.await?;
println!("browser version: {}", browser.version().await?);
let html = "<!doctype html><html><head><title>Network Demo</title></head>\
<body><h1 id=\"h\">network capture works</h1></body></html>";
let base = serve(html).await;
println!("serving demo page at {base}");
let page = browser.new_page().await?;
page.on_request(|req| async move {
println!(">> {} {}", req.method(), req.url());
});
page.on_response(|resp| async move {
println!("<< {} {}", resp.status(), resp.url());
});
println!("navigating to {base} (capture listeners armed)...");
let resp = page.goto(&base, None).await?.expect("document response");
println!("--- captured document response ---");
println!("status: {} ok: {}", resp.status(), resp.ok());
println!("content-type: {:?}", resp.headers().get("content-type"));
let body = resp.text().await?;
let snippet: String = body.chars().take(80).collect();
println!("body (first ~80 chars): {snippet}");
assert!(resp.ok());
assert!(body.contains("network capture works"));
page.route("*mocked*", |route| async move {
route
.fulfill(
RouteFulfillOptions::new()
.status(200)
.content_type("text/html")
.body("<h1 id=\"m\">mocked-by-route</h1>"),
)
.await
.ok();
})
.await?;
println!("\nnavigating to {base}mocked (route will fulfill)...");
page.goto(&format!("{base}mocked"), None).await?;
let mocked: String = page
.evaluate("document.getElementById('m').textContent")
.await?;
println!("route-fulfilled element text: {mocked}");
assert_eq!(mocked, "mocked-by-route");
page.route("*blocked*", |route| async move {
route.abort(None).await.ok();
})
.await?;
println!("\nnavigating to {base}blocked (route will abort)...");
if let Err(e) = page.goto(&format!("{base}blocked"), None).await {
println!("blocked nav errored (expected): {e}");
}
println!("\nall network capture + routing steps completed.");
browser.close().await?;
println!("done.");
Ok(())
}