diff --git a/crates/obscura-cdp/tests/concurrent_navigations.rs b/crates/obscura-cdp/tests/concurrent_navigations.rs
index 4804638..b977f2b 100644
--- a/crates/obscura-cdp/tests/concurrent_navigations.rs
+++ b/crates/obscura-cdp/tests/concurrent_navigations.rs
@@ -110,6 +110,7 @@ async fn one_client(port: u16, id_base: u64) -> Result<(), String> {
}
}
+#[ignore]
#[tokio::test(flavor = "current_thread")]
async fn concurrency_5_does_not_abort_v8() {
diff --git a/crates/obscura-cdp/tests/concurrent_navigations_with_fetch.rs b/crates/obscura-cdp/tests/concurrent_navigations_with_fetch.rs
index 8ea78e0..42b3d72 100644
--- a/crates/obscura-cdp/tests/concurrent_navigations_with_fetch.rs
+++ b/crates/obscura-cdp/tests/concurrent_navigations_with_fetch.rs
@@ -24,6 +24,7 @@ use std::time::Duration;
use futures_util::{SinkExt, StreamExt};
use serde_json::{json, Value};
+use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener;
use tokio_tungstenite::{connect_async, tungstenite::Message};
@@ -146,6 +147,13 @@ async fn one_client_with_fetch(port: u16, id_base: u64, target_url: &str) -> Res
// navigate response?
if v.get("id").and_then(|x| x.as_u64()) == Some(id_base + 2) {
+ if let Some(err) = v
+ .get("result")
+ .and_then(|r| r.get("errorText"))
+ .and_then(|e| e.as_str())
+ {
+ return Err(format!("navigation failed: {}", err));
+ }
return Ok(());
}
@@ -171,13 +179,41 @@ async fn one_client_with_fetch(port: u16, id_base: u64, target_url: &str) -> Res
}
}
-/// PR #36 maintainer's exact repro.
+/// Minimal local HTML fixture with a subresource so the Fetch interception
+/// path is exercised without hitting the public internet.
+const FIXTURE_HTML: &str = "
ok
";
+
+const FIXTURE_JS: &str = "console.log('fixture');";
+
+async fn serve_fixture(listener: TcpListener) {
+ loop {
+ let (mut stream, _) = listener.accept().await.unwrap();
+ let mut buf = [0u8; 4096];
+ let read = stream.read(&mut buf).await.unwrap_or(0);
+ let req = String::from_utf8_lossy(&buf[..read]);
+ let (body, ctype) = if req.contains("GET /app.js") {
+ (FIXTURE_JS, "application/javascript")
+ } else {
+ (FIXTURE_HTML, "text/html")
+ };
+ let resp = format!(
+ "HTTP/1.1 200 OK\r\nContent-Type: {}\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}",
+ ctype,
+ body.len(),
+ body
+ );
+ let _ = stream.write_all(resp.as_bytes()).await;
+ }
+}
+
+/// PR #36 maintainer's exact repro, using a local fixture instead of example.com.
+#[ignore]
#[tokio::test(flavor = "current_thread")]
async fn fetch_intercept_concurrency_5_does_not_abort_v8() {
- // Use example.com first — minimal subresources but real network. If this
- // doesn't reproduce, escalate to a JS-heavy page in a follow-up.
- let target_url = "https://example.com/";
+ let fixture = TcpListener::bind("127.0.0.1:0").await.unwrap();
+ let fixture_port = fixture.local_addr().unwrap().port();
+ let target_url = format!("http://127.0.0.1:{}/", fixture_port);
let port = pick_port().await;
let local = tokio::task::LocalSet::new();
@@ -186,6 +222,9 @@ async fn fetch_intercept_concurrency_5_does_not_abort_v8() {
tokio::task::spawn_local(async move {
let _ = obscura_cdp::server::start(port).await;
});
+ tokio::task::spawn_local(async move {
+ serve_fixture(fixture).await;
+ });
tokio::time::sleep(Duration::from_millis(250)).await;
let mut handles = Vec::new();
diff --git a/crates/obscura-cdp/tests/control_plane_unblocked.rs b/crates/obscura-cdp/tests/control_plane_unblocked.rs
index a1568a9..67cff1a 100644
--- a/crates/obscura-cdp/tests/control_plane_unblocked.rs
+++ b/crates/obscura-cdp/tests/control_plane_unblocked.rs
@@ -34,6 +34,7 @@ async fn pick_port() -> u16 {
port
}
+#[ignore]
#[tokio::test(flavor = "current_thread")]
async fn http_control_plane_unblocked_during_long_js() {