use playwright_cdp::options::LaunchOptions;
use playwright_cdp::route::{RouteFulfillOptions, Route};
use playwright_cdp::Playwright;
async fn http_server(body: &'static str) -> String {
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let port = listener.local_addr().unwrap().port();
tokio::spawn(async move {
loop {
let Ok((mut sock, _)) = listener.accept().await else { break };
let body = body;
tokio::spawn(async move {
use tokio::io::{AsyncReadExt, AsyncWriteExt};
let mut buf = [0u8; 4096];
let _ = sock.read(&mut buf).await;
let resp = format!(
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}",
body.len(),
body
);
let _ = sock.write_all(resp.as_bytes()).await;
let _ = sock.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 base = http_server(r#"{"server":"real"}"#).await;
let target = format!("{base}api/data");
println!("embedded JSON server: {base}");
println!("target URL (matches **/api/**): {target}");
let page = browser.new_page().await?;
println!("\nregistering route with pattern `**/api/**`");
page.route("**/api/**", |route: Route| async move {
println!(" [handler] route.fetch -> real request");
let resp = route.fetch(None).await.expect("fetch should succeed");
println!(" [handler] fetched status: {}", resp.status());
let text = resp.text();
println!(" [handler] fetched body: {text}");
assert!(text.contains(r#""server":"real""#), "fetch hit the real server");
route
.fulfill(
RouteFulfillOptions::new()
.status(200)
.content_type("application/json")
.body(text),
)
.await
.ok();
})
.await?;
println!("\n[page] goto {target}");
page.goto(&target, None).await?;
let body_text: String = page
.evaluate("document.body && document.body.textContent")
.await?;
println!("[page] body.textContent: {body_text}");
assert!(
body_text.contains(r#""server":"real""#),
"page should show the fulfilled content, got: {body_text}"
);
println!("\nroute.fetch + fulfill served the real server's body to the page.");
browser.close().await?;
println!("done.");
Ok(())
}