#![cfg(feature = "servo-engine")] use std::{collections::BTreeSet, error::Error, fs, path::PathBuf, process::Command}; use ely_domain::ProfileId; #[path = "sidecar/support.rs"] mod support; use support::*; #[test] fn sidecar_prd_reference_cases_cover_prd_urls() -> Result<(), Box> { let prd = fs::read_to_string(prd_path())?; let prd_urls = prd_reference_urls(&prd); let covered_urls = PRD_REFERENCE_SITE_COMPATIBILITY_CASES .iter() .map(|case| normalized_url(case.url)) .collect::>(); let missing_urls = prd_urls .iter() .filter(|url| !covered_urls.contains(url.as_str())) .cloned() .collect::>(); assert!(missing_urls.is_empty(), "missing PRD sidecar smoke cases: {missing_urls:?}"); assert_eq!(prd_urls.len(), PRD_REFERENCE_SITE_COMPATIBILITY_CASES.len()); Ok(()) } #[test] fn sidecar_opens_and_renders_prd_sites_to_rgba_files() -> Result<(), Box> { for case in PRD_SITE_COMPATIBILITY_CASES { for size in PRD_SITE_COMPATIBILITY_SIZES { snapshot_prd_site(case, *size, ScrollOffset::ZERO)?; } } Ok(()) } #[test] fn sidecar_report_uses_requested_profile_id() -> Result<(), Box> { let profile_id = ProfileId::new(); let profile_data_dir = std::env::temp_dir().join(format!( "ely-servo-sidecar-profile-test-{}-{}", std::process::id(), profile_id.as_str() )); let rgba_path = std::env::temp_dir().join(format!( "ely-servo-sidecar-profile-test-{}-{}.rgba", std::process::id(), profile_id.as_str() )); let output = Command::new(env!("CARGO_BIN_EXE_ely_servo_sidecar")) .arg("snapshot") .arg("--url") .arg("data:text/html,%3Ctitle%3EProfile%20Probe%3C%2Ftitle%3EProfile%20Probe") .arg("--profile-id") .arg(profile_id.as_str()) .arg("--profile-data-dir") .arg(&profile_data_dir) .arg("--rgba-out") .arg(&rgba_path) .arg("--width") .arg("64") .arg("--height") .arg("64") .output()?; assert!( output.status.success(), "stdout: {}\nstderr: {}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr) ); let report: serde_json::Value = serde_json::from_slice(&output.stdout)?; assert_eq!( report.get("profile_id").and_then(serde_json::Value::as_str), Some(profile_id.as_str()) ); remove_file_if_present(rgba_path)?; remove_dir_if_present(profile_data_dir)?; Ok(()) } fn prd_path() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("..").join("..").join("PRD.md") } fn remove_file_if_present(path: PathBuf) -> Result<(), Box> { match fs::remove_file(path) { Ok(()) => Ok(()), Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()), Err(error) => Err(error.into()), } } fn remove_dir_if_present(path: PathBuf) -> Result<(), Box> { match fs::remove_dir_all(path) { Ok(()) => Ok(()), Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()), Err(error) => Err(error.into()), } } fn prd_reference_urls(prd: &str) -> Vec { prd.lines() .filter(|line| line.starts_with("[R")) .filter_map(|line| { let start = line.find("https://")?; let url = line[start..].split_whitespace().next()?; Some(normalized_url(url)) }) .collect() } fn normalized_url(url: &str) -> String { url.trim().trim_end_matches('/').to_string() } #[test] fn sidecar_opens_and_renders_prd_reference_sites_to_rgba_files() -> Result<(), Box> { for case in PRD_REFERENCE_SITE_COMPATIBILITY_CASES { snapshot_prd_site(case, PRD_REFERENCE_SITE_SIZE, ScrollOffset::ZERO)?; } Ok(()) } #[test] fn sidecar_scrolls_prd_site_with_servo_input() -> Result<(), Box> { let scrolled_report = snapshot_prd_site(&SERVO_SCROLL_SITE, SERVO_SCROLL_SIZE, SERVO_SCROLL_OFFSET)?; assert_eq!(report_field_as_i64(&scrolled_report, "scroll_x")?, SERVO_SCROLL_OFFSET.x); assert_eq!(report_field_as_i64(&scrolled_report, "scroll_y")?, SERVO_SCROLL_OFFSET.y); assert_eq!(report_field_as_u64(&scrolled_report, "width")?, SERVO_SCROLL_SIZE.width); assert!(report_field_as_bool(&scrolled_report, "scroll_changed_frame")?); Ok(()) } #[test] fn sidecar_clicks_page_with_servo_mouse_input() -> Result<(), Box> { let initial_report = snapshot_click_probe(None)?; let clicked_report = snapshot_click_probe(Some(SERVO_CLICK_POINT))?; assert_eq!(report_field_as_u64(&clicked_report, "click_x")?, SERVO_CLICK_POINT.x); assert_eq!(report_field_as_u64(&clicked_report, "click_y")?, SERVO_CLICK_POINT.y); assert!(report_field_as_bool(&clicked_report, "click_changed_frame")?); assert_ne!( report_field_as_u64(&initial_report, "sample_hash")?, report_field_as_u64(&clicked_report, "sample_hash")? ); Ok(()) } #[test] fn sidecar_drags_page_with_servo_mouse_input() -> Result<(), Box> { let initial_report = snapshot_drag_probe(None)?; let drag_points = DragPoints { from: SERVO_DRAG_FROM, to: SERVO_DRAG_TO }; let dragged_report = snapshot_drag_probe(Some(drag_points))?; assert_eq!(report_field_as_u64(&dragged_report, "drag_from_x")?, SERVO_DRAG_FROM.x); assert_eq!(report_field_as_u64(&dragged_report, "drag_from_y")?, SERVO_DRAG_FROM.y); assert_eq!(report_field_as_u64(&dragged_report, "drag_to_x")?, SERVO_DRAG_TO.x); assert_eq!(report_field_as_u64(&dragged_report, "drag_to_y")?, SERVO_DRAG_TO.y); assert!(report_field_as_bool(&dragged_report, "drag_changed_frame")?); assert_ne!( report_field_as_u64(&initial_report, "sample_hash")?, report_field_as_u64(&dragged_report, "sample_hash")? ); Ok(()) } #[test] fn sidecar_touches_page_with_servo_touch_input() -> Result<(), Box> { let initial_report = snapshot_touch_probe(None)?; let touched_report = snapshot_touch_probe(Some(SERVO_TOUCH_POINT))?; assert_eq!(report_field_as_u64(&touched_report, "touch_x")?, SERVO_TOUCH_POINT.x); assert_eq!(report_field_as_u64(&touched_report, "touch_y")?, SERVO_TOUCH_POINT.y); assert!(report_field_as_bool(&touched_report, "touch_changed_frame")?); assert_ne!( report_field_as_u64(&initial_report, "sample_hash")?, report_field_as_u64(&touched_report, "sample_hash")? ); Ok(()) } #[test] fn sidecar_types_text_with_servo_keyboard_input() -> Result<(), Box> { let initial_report = snapshot_text_probe(None)?; let typed_report = snapshot_text_probe(Some(SERVO_TEXT_VALUE))?; assert_eq!( report_field_as_u64(&typed_report, "typed_text_byte_count")?, SERVO_TEXT_VALUE.len() as u64 ); assert!(report_field_as_bool(&typed_report, "text_changed_frame")?); assert_ne!( report_field_as_u64(&initial_report, "sample_hash")?, report_field_as_u64(&typed_report, "sample_hash")? ); Ok(()) }