use playwright_rs::protocol::{
ActionCursor, ChapterOptions, ScreencastStartOptions, ShowActionsOptions, ShowOverlayOptions,
};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
#[tokio::test]
async fn test_screencast_streams_frames_to_handler() {
let (_pw, browser, page) = crate::common::setup().await;
page.set_content(
"<body style='background:#06f;color:#fff;font-size:48px'>frame</body>",
None,
)
.await
.expect("Failed to set content");
let frames = Arc::new(AtomicUsize::new(0));
let bytes_seen = Arc::new(parking_lot::Mutex::new(0usize));
let timestamp_seen = Arc::new(parking_lot::Mutex::new(None::<f64>));
let counter = frames.clone();
let bytes = bytes_seen.clone();
let timestamp = timestamp_seen.clone();
page.screencast().on_frame(move |frame| {
let counter = counter.clone();
let bytes = bytes.clone();
let timestamp = timestamp.clone();
async move {
counter.fetch_add(1, Ordering::SeqCst);
*bytes.lock() = frame.data.len();
*timestamp.lock() = frame.timestamp;
Ok(())
}
});
page.screencast()
.start(ScreencastStartOptions::default())
.await
.expect("screencast start failed");
let _ = page
.evaluate_value("new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r)))")
.await;
let mut waited = std::time::Duration::ZERO;
while frames.load(Ordering::SeqCst) == 0 && waited < std::time::Duration::from_secs(10) {
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
waited += std::time::Duration::from_millis(100);
}
page.screencast()
.stop()
.await
.expect("screencast stop failed");
assert!(
frames.load(Ordering::SeqCst) > 0,
"expected at least one screencast frame within 10s"
);
assert!(
*bytes_seen.lock() > 0,
"frame data should be a non-empty JPEG byte buffer"
);
assert!(
timestamp_seen.lock().is_some(),
"screencast frame should carry a presentation timestamp (Playwright 1.61)"
);
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_screencast_records_to_path() {
let (_pw, browser, page) = crate::common::setup().await;
page.set_content("<body>recorded</body>", None)
.await
.expect("Failed to set content");
let path = std::env::temp_dir().join(format!(
"pw-rust-screencast-{}.webm",
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
));
let _ = std::fs::remove_file(&path);
page.screencast()
.start(ScreencastStartOptions::default().path(path.clone()))
.await
.expect("screencast start with path failed");
let _ = page
.evaluate_value("new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r)))")
.await;
page.screencast()
.stop()
.await
.expect("screencast stop failed");
let metadata =
std::fs::metadata(&path).expect("recorded screencast file should exist after stop");
assert!(
metadata.len() > 0,
"recorded screencast should be non-empty"
);
let _ = std::fs::remove_file(&path);
browser.close().await.expect("Failed to close browser");
}
#[tokio::test]
async fn test_screencast_overlay_and_chapter_calls_succeed() {
let (_pw, browser, page) = crate::common::setup().await;
page.set_content("<body>overlays</body>", None)
.await
.expect("Failed to set content");
let screencast = page.screencast();
screencast
.start(ScreencastStartOptions::default())
.await
.expect("start failed");
screencast
.show_actions(
ShowActionsOptions::default()
.duration(500.0)
.cursor(ActionCursor::Pointer),
)
.await
.expect("show_actions failed");
screencast
.hide_actions()
.await
.expect("hide_actions failed");
screencast
.show_chapter(
"Phase 1",
ChapterOptions::default()
.description("setting up")
.duration(500.0),
)
.await
.expect("show_chapter failed");
let id = screencast
.show_overlay(
"<div style='color:white;background:black;padding:8px'>hi</div>",
ShowOverlayOptions::default().duration(500.0),
)
.await
.expect("show_overlay failed");
assert!(!id.0.is_empty(), "overlay id should be non-empty");
screencast
.set_overlay_visible(false)
.await
.expect("set_overlay_visible(false) failed");
screencast
.set_overlay_visible(true)
.await
.expect("set_overlay_visible(true) failed");
screencast
.remove_overlay(id)
.await
.expect("remove_overlay failed");
screencast.stop().await.expect("stop failed");
browser.close().await.expect("Failed to close browser");
}