viewpoint_core/lib.rs
1//! # Viewpoint Core - Browser Automation Library
2//!
3//! Core domain types for `Viewpoint` browser automation, providing a Playwright-inspired
4//! API for controlling Chromium-based browsers via the Chrome DevTools Protocol (CDP).
5//!
6//! This crate provides the high-level API for browser automation,
7//! including [`Browser`], [`BrowserContext`], [`Page`], and navigation types.
8//!
9//! ## Features
10//!
11//! - **Browser Control**: Launch or connect to Chromium browsers
12//! - **Page Navigation**: Navigate pages and wait for load states
13//! - **Element Interaction**: Click, type, and interact with page elements via [`Locator`]
14//! - **Network Interception**: Route, modify, and mock network requests
15//! - **Device Emulation**: Emulate mobile devices, geolocation, and media features
16//! - **Input Devices**: Keyboard, mouse, and touchscreen control
17//! - **Screenshots & PDF**: Capture screenshots and generate PDFs
18//! - **Clock Mocking**: Control time in tests with [`Clock`]
19//! - **Event Handling**: Dialogs, downloads, file choosers, console messages
20//! - **Tracing**: Record traces for debugging
21//! - **Video Recording**: Record page interactions as video
22//!
23//! ## Quick Start
24//!
25//! ```no_run
26//! use viewpoint_core::{Browser, DocumentLoadState};
27//!
28//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
29//! // Launch a browser and create a new context and page
30//! let browser = Browser::launch()
31//! .headless(true)
32//! .launch()
33//! .await?;
34//!
35//! let context = browser.new_context().await?;
36//! let page = context.new_page().await?;
37//!
38//! // Navigate to a page
39//! page.goto("https://example.com").goto().await?;
40//!
41//! // Interact with elements
42//! page.locator("button#submit").click().await?;
43//!
44//! // Fill a form
45//! page.locator("input[name='email']").fill("user@example.com").await?;
46//!
47//! // Get text content
48//! let text = page.locator("h1").text_content().await?;
49//! println!("Page title: {:?}", text);
50//! # Ok(())
51//! # }
52//! ```
53//!
54//! ## Browser Connection Methods
55//!
56//! There are three ways to get a [`Browser`] instance:
57//!
58//! ```no_run
59//! use viewpoint_core::Browser;
60//! use std::time::Duration;
61//!
62//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
63//! // 1. Launch a new browser process
64//! let browser = Browser::launch()
65//! .headless(true)
66//! .launch()
67//! .await?;
68//!
69//! // 2. Connect via WebSocket URL (for pre-configured connections)
70//! let browser = Browser::connect("ws://localhost:9222/devtools/browser/...").await?;
71//!
72//! // 3. Connect via HTTP endpoint (auto-discovers WebSocket URL)
73//! let browser = Browser::connect_over_cdp("http://localhost:9222")
74//! .timeout(Duration::from_secs(10))
75//! .connect()
76//! .await?;
77//! # Ok(())
78//! # }
79//! ```
80//!
81//! ## Element Locators
82//!
83//! The [`Locator`] API provides auto-waiting and retry logic for robust element interaction:
84//!
85//! ```no_run
86//! use viewpoint_core::{Browser, AriaRole};
87//!
88//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
89//! # let browser = Browser::launch().headless(true).launch().await?;
90//! # let context = browser.new_context().await?;
91//! # let page = context.new_page().await?;
92//! // CSS selector
93//! page.locator("button.primary").click().await?;
94//!
95//! // Text selector
96//! page.get_by_text("Submit").click().await?;
97//!
98//! // Role selector (accessibility)
99//! page.get_by_role(AriaRole::Button)
100//! .with_name("Submit")
101//! .build()
102//! .click()
103//! .await?;
104//!
105//! // Test ID selector (recommended for stable tests)
106//! page.get_by_test_id("submit-button").click().await?;
107//!
108//! // Label selector (for form fields)
109//! page.get_by_label("Email address").fill("test@example.com").await?;
110//!
111//! // Placeholder selector
112//! page.get_by_placeholder("Enter your name").fill("John Doe").await?;
113//!
114//! // Chained locators
115//! page.locator(".form")
116//! .locator("input")
117//! .first()
118//! .fill("value")
119//! .await?;
120//! # Ok(())
121//! # }
122//! ```
123//!
124//! ## Network Interception
125//!
126//! Intercept and modify network requests using [`Route`]:
127//!
128//! ```ignore
129//! use viewpoint_core::{Browser, Route};
130//!
131//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
132//! # let browser = Browser::launch().headless(true).launch().await?;
133//! # let context = browser.new_context().await?;
134//! # let page = context.new_page().await?;
135//! // Block images
136//! page.route("**/*.{png,jpg,jpeg,gif}", |route| {
137//! async move { route.abort().await }
138//! }).await?;
139//!
140//! // Mock an API response
141//! page.route("**/api/users", |route| {
142//! async move {
143//! route.fulfill()
144//! .status(200)
145//! .content_type("application/json")
146//! .body(r#"{"users": []}"#)
147//! .fulfill()
148//! .await
149//! }
150//! }).await?;
151//!
152//! // Modify requests
153//! page.route("**/api/**", |route| {
154//! async move {
155//! route.continue_route()
156//! .header("X-Custom-Header", "value")
157//! .continue_route()
158//! .await
159//! }
160//! }).await?;
161//! # Ok(())
162//! # }
163//! ```
164//!
165//! ## Device Emulation
166//!
167//! Emulate mobile devices and other capabilities:
168//!
169//! ```no_run
170//! use viewpoint_core::{Browser, Permission, ViewportSize};
171//!
172//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
173//! # let browser = Browser::launch().headless(true).launch().await?;
174//! // Create a context with mobile viewport and geolocation
175//! let context = browser.new_context_builder()
176//! .viewport(390, 844) // iPhone 14 size
177//! .device_scale_factor(3.0)
178//! .is_mobile(true)
179//! .has_touch(true)
180//! .geolocation(37.7749, -122.4194) // San Francisco
181//! .permissions(vec![Permission::Geolocation])
182//! .build()
183//! .await?;
184//!
185//! let page = context.new_page().await?;
186//! # Ok(())
187//! # }
188//! ```
189//!
190//! ## Screenshots and PDF
191//!
192//! Capture screenshots and generate PDFs:
193//!
194//! ```no_run
195//! use viewpoint_core::Browser;
196//! use viewpoint_core::page::PaperFormat;
197//!
198//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
199//! # let browser = Browser::launch().headless(true).launch().await?;
200//! # let context = browser.new_context().await?;
201//! # let page = context.new_page().await?;
202//! // Screenshot the viewport
203//! page.screenshot()
204//! .path("screenshot.png")
205//! .capture()
206//! .await?;
207//!
208//! // Full page screenshot
209//! page.screenshot()
210//! .full_page(true)
211//! .path("full-page.png")
212//! .capture()
213//! .await?;
214//!
215//! // Generate PDF (headless only)
216//! page.pdf()
217//! .format(PaperFormat::A4)
218//! .path("document.pdf")
219//! .generate()
220//! .await?;
221//! # Ok(())
222//! # }
223//! ```
224//!
225//! ## Event Handling
226//!
227//! Handle browser events like dialogs and downloads:
228//!
229//! ```ignore
230//! use viewpoint_core::Browser;
231//!
232//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
233//! # let browser = Browser::launch().headless(true).launch().await?;
234//! # let context = browser.new_context().await?;
235//! # let page = context.new_page().await?;
236//! // Handle dialogs (alerts, confirms, prompts)
237//! page.on_dialog(|dialog| async move {
238//! println!("Dialog message: {}", dialog.message());
239//! dialog.accept(None).await
240//! }).await;
241//!
242//! // Handle downloads
243//! page.on_download(|download| async move {
244//! download.save_as("downloads/file.zip").await
245//! }).await;
246//!
247//! // Handle console messages
248//! page.on_console(|msg| async move {
249//! println!("[{}] {}", msg.message_type(), msg.text());
250//! Ok(())
251//! }).await;
252//! # Ok(())
253//! # }
254//! ```
255//!
256//! ## Module Organization
257//!
258//! - [`browser`] - Browser launching and connection management
259//! - [`context`] - Browser context (similar to incognito window) management
260//! - [`page`] - Page navigation, content, and interaction
261//! - [`network`] - Network interception, routing, and HAR recording
262//! - [`wait`] - Wait system and load states
263//! - [`devices`] - Predefined device descriptors
264//! - [`error`] - Error types
265//! - [`api`] - API request context for HTTP requests
266
267pub mod api;
268pub mod browser;
269pub mod context;
270pub mod devices;
271pub mod error;
272pub mod network;
273pub mod page;
274pub mod wait;
275
276pub use browser::{Browser, BrowserBuilder, ConnectOverCdpBuilder, NewContextBuilder, UserDataDir};
277pub use context::{
278 BrowserContext, ClearCookiesBuilder, ColorScheme, ContextEventManager, ContextOptions,
279 ContextOptionsBuilder, Cookie, ForcedColors, Geolocation, HandlerId, HttpCredentials,
280 IndexedDbDatabase, IndexedDbEntry, IndexedDbIndex, IndexedDbObjectStore, LocalStorageEntry,
281 PageInfo, Permission, ProxyConfig, ReducedMotion, SameSite, SetGeolocationBuilder,
282 StorageOrigin, StorageState, StorageStateBuilder, StorageStateOptions, StorageStateSource,
283 Tracing, TracingOptions, ViewportSize as ContextViewportSize,
284};
285pub use error::CoreError;
286pub use network::{
287 AbortError,
288 ContinueBuilder,
289 FetchedResponse,
290 FulfillBuilder,
291 HeaderEntry,
292 NetworkEvent,
293 NetworkEventListener,
294 RemoteAddress,
295 Request,
296 RequestEvent,
297 RequestFailedEvent,
298 RequestFinishedEvent,
299 RequestSizes,
300 RequestTiming,
301 ResourceType,
302 Response,
303 ResponseEvent,
304 Route,
305 RouteHandler,
306 RouteHandlerRegistry,
307 SecurityDetails,
308 UrlMatcher,
309 UrlPattern,
310 WaitForRequestBuilder,
311 WaitForResponseBuilder,
312 // WebSocket monitoring
313 WebSocket,
314 WebSocketFrame,
315 WebSocketManager,
316};
317pub use page::{
318 // Screenshot & PDF
319 Animations,
320 AriaCheckedState,
321 AriaRole,
322 AriaSnapshot,
323 // Element handles and bounding boxes
324 BoundingBox,
325 BoxModel,
326 ClipRegion,
327 // Clock mocking
328 Clock,
329 // Console and Error events
330 ConsoleMessage,
331 ConsoleMessageLocation,
332 ConsoleMessageType,
333 // Dialog, Download, FileChooser
334 Dialog,
335 DialogType,
336 Download,
337 DownloadState,
338 // Input devices
339 DragAndDropBuilder,
340 ElementHandle,
341 // Media and Vision Emulation
342 EmulateMediaBuilder,
343 FileChooser,
344 FilePayload,
345 FilterBuilder,
346 // Frame support
347 Frame,
348 FrameElementLocator,
349 FrameLocator,
350 FrameRoleLocatorBuilder,
351 // Navigation
352 GotoBuilder,
353 JsArg,
354 // JavaScript evaluation
355 JsHandle,
356 Keyboard,
357 Locator,
358 // Locator handlers
359 LocatorHandlerHandle,
360 LocatorHandlerOptions,
361 LocatorOptions,
362 Margins,
363 MediaType,
364 Mouse,
365 MouseButton,
366 NavigationResponse,
367 Page,
368 PageErrorInfo,
369 PaperFormat,
370 PdfBuilder,
371 Polling,
372 RoleLocatorBuilder,
373 ScreenshotBuilder,
374 ScreenshotFormat,
375 // Content manipulation
376 ScriptTagBuilder,
377 ScriptType,
378 Selector,
379 SetContentBuilder,
380 // Snapshot options
381 SnapshotOptions,
382 StyleTagBuilder,
383 TextOptions,
384 TimeValue,
385 Touchscreen,
386 // Video recording
387 Video,
388 VideoOptions,
389 // Viewport
390 ViewportSize,
391 VisionDeficiency,
392 WaitForFunctionBuilder,
393 WebError,
394};
395pub use wait::DocumentLoadState;