use std::sync::Arc;
use std::sync::atomic::{AtomicI64, Ordering};
#[tokio::test]
async fn test_evaluate_with_callback_round_trips_through_rust() {
let (_pw, browser, page) = crate::common::setup().await;
page.set_content("<div>cb</div>", None)
.await
.expect("set_content");
let result: i64 = page
.evaluate_with_callback("async cb => (await cb(20, 22)) + 1", |args| async move {
let a = args[0].as_i64().unwrap_or(0);
let b = args[1].as_i64().unwrap_or(0);
serde_json::json!(a + b)
})
.await
.expect("evaluate_with_callback");
assert_eq!(result, 43);
browser.close().await.expect("close");
}
#[tokio::test]
async fn test_evaluate_with_callback_is_not_installed_on_window() {
let (_pw, browser, page) = crate::common::setup().await;
page.set_content("<div>cb</div>", None)
.await
.expect("set_content");
let received: bool = page
.evaluate_with_callback("cb => typeof cb === 'function'", |_args| async move {
serde_json::json!(null)
})
.await
.expect("evaluate_with_callback");
assert!(received, "the expression should receive a function");
let named_globals: i64 = page
.evaluate(
"() => Object.getOwnPropertyNames(window).filter(k => k.startsWith('__pw_fn_rs_')).length",
None::<&()>,
)
.await
.expect("probe window for the callback name");
assert_eq!(
named_globals, 0,
"noGlobal must keep the callback off window"
);
browser.close().await.expect("close");
}
#[tokio::test]
async fn test_evaluate_with_callback_survives_for_later_calls() {
let (_pw, browser, page) = crate::common::setup().await;
page.set_content("<div>cb</div>", None)
.await
.expect("set_content");
let seen = Arc::new(AtomicI64::new(0));
let seen_in_cb = seen.clone();
let _: bool = page
.evaluate_with_callback("cb => { window.__stash = cb; return true; }", move |args| {
let seen = seen_in_cb.clone();
async move {
seen.store(args[0].as_i64().unwrap_or(0), Ordering::SeqCst);
serde_json::json!(null)
}
})
.await
.expect("stash the callback");
let _: serde_json::Value = page
.evaluate("() => window.__stash(7)", None::<&()>)
.await
.expect("invoke the stashed callback");
let delivered = crate::common::poll_until(std::time::Duration::from_secs(5), || {
seen.load(Ordering::SeqCst) == 7
})
.await;
assert!(delivered, "the stashed callback should still reach Rust");
browser.close().await.expect("close");
}