use bao_cdp_client::{
bridge::ConsoleLevel, bridge::ServoEvent, AXNode, Accessibility, BoundingBox, BridgeError,
BridgeScreenshotFormat, Browser, BrowserContext, BrowserOptions, CDPRdpBridge, CdpError,
CdpEvent, ConnectError, Connection, ConnectionConfig, ConsoleMessage, ContextOptions, Cookie,
Coverage, DeviceDescriptor, Dialog, DialogType, ElementHandle, EventEmitter, EventEmitterInner,
EventHandler, EventSubscriber, ExecutionContext, Frame, HandlerId, HighLevelBrowser,
InMemoryBridge, InMemoryBridgeResponse, InMemoryTransport, JSHandle, Keyboard, Mouse,
MouseButton, NavigationEntry, NavigationHistory, Page, PageTargetInfo, PageViewport,
ParsedConnectUrl, PermissionOverride, Pid, RemoteObject, Request, Response, ScreenshotFormat,
ServoBackend, SubscriptionResult, TargetInfo, Touchscreen, Tracing, Transport, TransportKind,
Viewport, WaitUntilState, WebSocketTransport, Worker, VERSION,
};
#[test]
fn top_level_browser() {
let browser = Browser::connect("memory://bao").unwrap();
assert!(browser.is_in_memory());
assert!(!browser.is_websocket());
assert_eq!(browser.scheme(), "memory");
assert_eq!(browser.url(), "memory://bao");
assert_eq!(browser.transport_kind(), TransportKind::InMemory);
let ws_browser = Browser::connect("ws://127.0.0.1:9222").unwrap();
assert!(ws_browser.is_websocket());
assert!(!ws_browser.is_in_memory());
}
#[test]
fn top_level_errors() {
let _: ConnectError = ConnectError::InvalidUrl;
let _: ConnectError = ConnectError::InvalidScheme("ftp".to_string());
let _: ConnectError = ConnectError::LaunchError("msg".to_string());
let _: ConnectError = ConnectError::ConnectionFailed("refused".to_string());
let _: ConnectError = ConnectError::Timeout("30s".to_string());
let _: CdpError = CdpError::ProtocolError("err".to_string());
let _: CdpError = CdpError::JsonError("err".to_string());
let _: CdpError = CdpError::IoError(std::io::Error::new(std::io::ErrorKind::Other, "boom"));
let _: CdpError = CdpError::ConnectionClosed;
let _: CdpError = CdpError::Timeout("err".to_string());
let _: CdpError = CdpError::TransportError("err".to_string());
let _: CdpError = CdpError::HandshakeError("err".to_string());
let _: fn() -> Option<BridgeError> = || None;
fn assert_std_error<E: std::error::Error>() {}
assert_std_error::<ConnectError>();
assert_std_error::<CdpError>();
assert_std_error::<BridgeError>();
}
#[test]
fn top_level_transport() {
let evt = CdpEvent::new(
"Page.frameNavigated",
serde_json::json!({"url": "about:blank"}),
);
assert_eq!(evt.method, "Page.frameNavigated");
let evt_with_session = evt.with_session("TARGET-1");
assert_eq!(evt_with_session.session_id.as_deref(), Some("TARGET-1"));
assert_eq!(TransportKind::InMemory, TransportKind::InMemory);
assert_ne!(TransportKind::InMemory, TransportKind::WebSocket);
let parsed = ParsedConnectUrl::new("memory://bao", "memory", TransportKind::InMemory);
assert_eq!(parsed.raw, "memory://bao");
assert_eq!(parsed.scheme, "memory");
let cfg = ConnectionConfig::default();
assert_eq!(cfg.default_timeout_ms, 30_000);
let cfg2 = ConnectionConfig {
default_timeout_ms: 5000,
transport_kind: TransportKind::InMemory,
};
assert_eq!(cfg2.default_timeout_ms, 5000);
let _: Option<Box<dyn Transport>> = None;
let _: Option<Box<dyn InMemoryBridge>> = None;
let _: Option<WebSocketTransport> = None;
let _: Option<InMemoryTransport> = None;
let _: Option<InMemoryBridgeResponse> = None;
}
#[test]
fn high_level_api_types_are_public() {
fn _assert_high_level_types(
_: HighLevelBrowser,
_: BrowserOptions,
_: Pid,
_: BrowserContext,
_: ContextOptions,
_: PermissionOverride,
_: Page,
_: PageTargetInfo,
_: PageViewport,
_: Worker,
_: Frame,
_: ExecutionContext,
_: ElementHandle,
_: BoundingBox,
_: JSHandle,
_: Request,
_: Response,
_: Dialog,
_: DialogType,
_: ConsoleMessage,
) {
}
let _ = _assert_high_level_types;
}
#[test]
fn tool_classes_are_public() {
fn _assert_tool_classes(
_: Keyboard,
_: MouseButton,
_: Mouse,
_: Touchscreen,
_: Coverage,
_: Tracing,
_: Accessibility,
_: AXNode,
) {
}
let _ = _assert_tool_classes;
}
#[test]
fn event_emitter_trait_usable() {
let _: HandlerId = 0u64;
let _handler: Option<EventHandler> = None;
let _ = SubscriptionResult::Registered(0);
let _ = SubscriptionResult::Removed;
let _ = SubscriptionResult::NotFound;
fn _accept_emitter<E: EventEmitter>() {}
_accept_emitter::<Page>();
let _: Option<EventEmitterInner> = None;
}
#[test]
fn public_types_full_coverage() {
assert_eq!(ScreenshotFormat::Png.as_cdp_str(), "png");
assert_eq!(ScreenshotFormat::Jpeg.as_cdp_str(), "jpeg");
assert_eq!(ScreenshotFormat::Webp.as_cdp_str(), "webp");
assert_eq!(
ScreenshotFormat::from_cdp(Some("png")),
ScreenshotFormat::Png
);
assert_eq!(ScreenshotFormat::default(), ScreenshotFormat::Png);
assert_eq!(WaitUntilState::Load.as_str(), "load");
assert_eq!(
WaitUntilState::DomContentLoaded.as_str(),
"domcontentloaded"
);
assert_eq!(WaitUntilState::NetworkIdle0.as_str(), "networkidle0");
assert_eq!(WaitUntilState::NetworkIdle2.as_str(), "networkidle2");
assert_eq!(WaitUntilState::default(), WaitUntilState::Load);
let c = Cookie::new("k", "v")
.with_domain("example.com")
.with_path("/")
.with_secure(true)
.with_http_only(true)
.with_same_site("Lax");
let json = serde_json::to_string(&c).unwrap();
let back: Cookie = serde_json::from_str(&json).unwrap();
assert_eq!(c, back);
let vp = Viewport::default();
assert_eq!(vp.width, 1280);
assert_eq!(vp.height, 720);
let mobile_vp = Viewport {
width: 390,
height: 844,
device_scale_factor: 3.0,
is_mobile: true,
has_touch: true,
is_landscape: false,
};
let _json = serde_json::to_string(&mobile_vp).unwrap();
let dev = DeviceDescriptor::new("iPhone", "UA", mobile_vp);
assert_eq!(dev.name, "iPhone");
}
#[test]
fn bridge_types_are_public() {
let _: Option<Box<dyn ServoBackend>> = None;
let _: Option<Box<CDPRdpBridge>> = None;
let _: Option<EventSubscriber> = None;
let _: Option<RemoteObject> = None;
let _: Option<NavigationEntry> = None;
let _: Option<NavigationHistory> = None;
let _: Option<TargetInfo> = None;
let _ = ConsoleLevel::Verbose;
let _ = ConsoleLevel::Info;
let _ = ConsoleLevel::Warning;
let _ = ConsoleLevel::Error;
let _ = ConsoleLevel::Debug;
fn _accept_servo_event(_: ServoEvent) {}
let _ = _accept_servo_event;
let _ = BridgeScreenshotFormat::Png;
}
#[test]
fn version_constants_and_fn() {
assert!(!VERSION.is_empty());
assert!(VERSION.contains('.'));
assert_eq!(bao_cdp_client::version(), VERSION);
}
#[test]
fn connection_url_parsing_works() {
let p = ParsedConnectUrl::new("memory://bao", "memory", TransportKind::InMemory);
assert_eq!(p.transport_kind, TransportKind::InMemory);
let p = ParsedConnectUrl::new("ws://x", "ws", TransportKind::WebSocket);
assert_eq!(p.transport_kind, TransportKind::WebSocket);
}
#[test]
fn delegate_event_emitter_macro_exists() {
use bao_cdp_client::delegate_event_emitter;
use bao_cdp_client::EventEmitterInner;
use bao_cdp_client::{EventHandler, HandlerId, SubscriptionResult};
use std::rc::Rc;
struct MockEmitter {
inner: Rc<EventEmitterInner>,
}
impl EventEmitter for MockEmitter {
delegate_event_emitter!(self, inner);
}
let m = MockEmitter {
inner: Rc::new(EventEmitterInner::new()),
};
let handler: EventHandler = std::sync::Arc::new(|_args: &[serde_json::Value]| {});
let id: HandlerId = m.on("test", handler);
let result = m.off("test", id);
assert!(matches!(
result,
SubscriptionResult::Removed | SubscriptionResult::NotFound
));
assert_eq!(m.listener_count("test"), 0);
}