viewpoint_core/network/
mod.rs

1//! # Network Interception and Monitoring
2//!
3//! This module provides comprehensive network capabilities including request
4//! interception, response mocking, event monitoring, and HAR recording/replay.
5//!
6//! ## Features
7//!
8//! - **Request Interception**: Intercept and modify outgoing requests
9//! - **Response Mocking**: Return custom responses without hitting the server
10//! - **Request Blocking**: Block requests matching specific patterns
11//! - **Network Events**: Monitor requests, responses, and failures
12//! - **HAR Recording**: Record network traffic for debugging
13//! - **HAR Replay**: Replay recorded traffic for testing
14//! - **WebSocket Monitoring**: Track WebSocket connections and messages
15//!
16//! ## Mock API Responses
17//!
18//! Mock API endpoints to test UI without a backend:
19//!
20//! ```ignore
21//! use viewpoint_core::Browser;
22//!
23//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
24//! # let browser = Browser::launch().headless(true).launch().await?;
25//! # let context = browser.new_context().await?;
26//! # let page = context.new_page().await?;
27//! // Mock a REST API endpoint with JSON response
28//! page.route("**/api/users", |route| async move {
29//!     route.fulfill()
30//!         .status(200)
31//!         .content_type("application/json")
32//!         .body(r#"{"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}"#)
33//!         .fulfill()
34//!         .await
35//! }).await?;
36//!
37//! // Mock different responses based on request method
38//! page.route("**/api/items", |route| async move {
39//!     let method = route.request().method();
40//!     match method.as_str() {
41//!         "GET" => {
42//!             route.fulfill()
43//!                 .status(200)
44//!                 .content_type("application/json")
45//!                 .body(r#"[{"id": 1, "name": "Item 1"}]"#)
46//!                 .fulfill()
47//!                 .await
48//!         }
49//!         "POST" => {
50//!             route.fulfill()
51//!                 .status(201)
52//!                 .content_type("application/json")
53//!                 .body(r#"{"id": 2, "name": "New Item", "created": true}"#)
54//!                 .fulfill()
55//!                 .await
56//!         }
57//!         "DELETE" => {
58//!             route.fulfill()
59//!                 .status(204)
60//!                 .fulfill()
61//!                 .await
62//!         }
63//!         _ => route.continue_route().continue_route().await
64//!     }
65//! }).await?;
66//!
67//! // Mock error responses
68//! page.route("**/api/error", |route| async move {
69//!     route.fulfill()
70//!         .status(500)
71//!         .content_type("application/json")
72//!         .body(r#"{"error": "Internal Server Error", "code": "SERVER_ERROR"}"#)
73//!         .fulfill()
74//!         .await
75//! }).await?;
76//!
77//! // Mock 404 Not Found
78//! page.route("**/api/not-found", |route| async move {
79//!     route.fulfill()
80//!         .status(404)
81//!         .content_type("application/json")
82//!         .body(r#"{"error": "Resource not found"}"#)
83//!         .fulfill()
84//!         .await
85//! }).await?;
86//!
87//! // Mock delayed response for loading state testing
88//! page.route("**/api/slow", |route| async move {
89//!     tokio::time::sleep(std::time::Duration::from_secs(2)).await;
90//!     route.fulfill()
91//!         .status(200)
92//!         .content_type("application/json")
93//!         .body(r#"{"data": "loaded"}"#)
94//!         .fulfill()
95//!         .await
96//! }).await?;
97//! # Ok(())
98//! # }
99//! ```
100//!
101//! ## Request Interception
102//!
103//! Use [`Route`] to intercept and handle network requests:
104//!
105//! ```ignore
106//! use viewpoint_core::Browser;
107//!
108//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
109//! # let browser = Browser::launch().headless(true).launch().await?;
110//! # let context = browser.new_context().await?;
111//! # let page = context.new_page().await?;
112//! // Block images for faster tests
113//! page.route("**/*.{png,jpg,jpeg,gif,webp}", |route| async move {
114//!     route.abort().await
115//! }).await?;
116//!
117//! // Add authentication header to all API requests
118//! page.route("**/api/**", |route| async move {
119//!     route.continue_route()
120//!         .header("Authorization", "Bearer test-token-123")
121//!         .continue_route()
122//!         .await
123//! }).await?;
124//!
125//! // Modify POST body
126//! page.route("**/api/submit", |route| async move {
127//!     route.continue_route()
128//!         .post_data(r#"{"modified": true, "test": true}"#)
129//!         .continue_route()
130//!         .await
131//! }).await?;
132//!
133//! // Intercept and inspect request before continuing
134//! page.route("**/api/log", |route| async move {
135//!     let request = route.request();
136//!     println!("Request URL: {}", request.url());
137//!     println!("Request method: {}", request.method());
138//!     if let Some(body) = request.post_data() {
139//!         println!("Request body: {}", body);
140//!     }
141//!     route.continue_route().continue_route().await
142//! }).await?;
143//! # Ok(())
144//! # }
145//! ```
146//!
147//! ## URL Patterns
148//!
149//! Routes support glob patterns for matching URLs:
150//!
151//! - `**` - Match any path segments
152//! - `*` - Match any characters except `/`
153//! - `?` - Match a single character
154//!
155//! ```ignore
156//! use viewpoint_core::{Browser, Route};
157//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
158//! # let browser = Browser::launch().headless(true).launch().await?;
159//! # let context = browser.new_context().await?;
160//! # let page = context.new_page().await?;
161//! // Match all API endpoints
162//! page.route("**/api/**", |route| async move {
163//!     route.continue_route().continue_route().await
164//! }).await?;
165//!
166//! // Match specific file types
167//! page.route("**/*.{js,css}", |route| async move {
168//!     route.continue_route().continue_route().await
169//! }).await?;
170//!
171//! // Match exact URL
172//! page.route("https://example.com/login", |route| async move {
173//!     route.continue_route().continue_route().await
174//! }).await?;
175//! # Ok(())
176//! # }
177//! ```
178//!
179//! ## Network Events
180//!
181//! Monitor network activity with event listeners:
182//!
183//! ```ignore
184//! use viewpoint_core::Browser;
185//!
186//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
187//! # let browser = Browser::launch().headless(true).launch().await?;
188//! # let context = browser.new_context().await?;
189//! # let page = context.new_page().await?;
190//! // Wait for a specific request
191//! let request = page.wait_for_request("**/api/data")
192//!     .wait()
193//!     .await?;
194//! println!("Request URL: {}", request.url());
195//!
196//! // Wait for a specific response
197//! let response = page.wait_for_response("**/api/data")
198//!     .wait()
199//!     .await?;
200//! println!("Response status: {}", response.status());
201//! # Ok(())
202//! # }
203//! ```
204//!
205//! ## HAR Recording
206//!
207//! Record network traffic for debugging or test fixtures:
208//!
209//! ```ignore
210//! use viewpoint_core::Browser;
211//!
212//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
213//! # let browser = Browser::launch().headless(true).launch().await?;
214//! # let context = browser.new_context().await?;
215//! // Start HAR recording
216//! context.route_from_har()
217//!     .record_path("recording.har")
218//!     .build()
219//!     .await?;
220//!
221//! // ... navigate and interact ...
222//!
223//! // HAR is automatically saved when context closes
224//! # Ok(())
225//! # }
226//! ```
227//!
228//! ## HAR Replay
229//!
230//! Replay recorded traffic for deterministic tests:
231//!
232//! ```ignore
233//! use viewpoint_core::Browser;
234//!
235//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
236//! # let browser = Browser::launch().headless(true).launch().await?;
237//! # let context = browser.new_context().await?;
238//! // Replay from HAR file
239//! context.route_from_har()
240//!     .path("recording.har")
241//!     .build()
242//!     .await?;
243//!
244//! // Now requests will be served from the HAR file
245//! let page = context.new_page().await?;
246//! page.goto("https://example.com").goto().await?;
247//! # Ok(())
248//! # }
249//! ```
250//!
251//! ## WebSocket Monitoring
252//!
253//! Monitor WebSocket connections:
254//!
255//! ```ignore
256//! use viewpoint_core::Browser;
257//!
258//! # async fn example() -> Result<(), viewpoint_core::CoreError> {
259//! # let browser = Browser::launch().headless(true).launch().await?;
260//! # let context = browser.new_context().await?;
261//! # let page = context.new_page().await?;
262//! // Listen for WebSocket connections
263//! page.on_websocket(|ws| async move {
264//!     println!("WebSocket connected: {}", ws.url());
265//!     
266//!     // Listen for messages
267//!     ws.on_frame(|frame| async move {
268//!         println!("Frame: {:?}", frame.payload());
269//!         Ok(())
270//!     }).await;
271//!     
272//!     Ok(())
273//! }).await;
274//! # Ok(())
275//! # }
276//! ```
277
278pub mod auth;
279pub mod events;
280pub(crate) mod handler;
281mod handler_fetch;
282mod handler_request;
283pub mod har;
284pub mod har_recorder;
285pub mod har_replay;
286mod har_types;
287mod request;
288mod response;
289mod route;
290mod route_builders;
291mod route_fetch;
292mod types;
293pub mod websocket;
294
295pub use events::{
296    NetworkEvent, NetworkEventListener, RequestEvent, RequestFailedEvent, RequestFinishedEvent,
297    ResponseEvent, WaitForRequestBuilder, WaitForResponseBuilder,
298};
299pub use handler::RouteHandlerRegistry;
300pub use har::{Har, HarEntry, HarPage, HarRequest, HarResponse, HarTimings};
301pub use har_recorder::{HarRecorder, HarRecordingBuilder, HarRecordingOptions};
302pub use har_replay::{
303    HarReplayHandler, HarReplayOptions, HarResponseData, TimingMode, UpdateContentMode,
304};
305pub use request::{Request, RequestSizes, RequestTiming};
306pub use response::{RemoteAddress, Response, SecurityDetails};
307pub use route::{Route, RouteAction, RouteHandler};
308pub use route_builders::{ContinueBuilder, FulfillBuilder};
309pub use route_fetch::{FetchBuilder, FetchedResponse};
310pub use types::{AbortError, ResourceType, UrlMatcher, UrlPattern};
311pub use websocket::{WebSocket, WebSocketFrame, WebSocketManager};
312
313// Re-export CDP types that are used directly
314pub use viewpoint_cdp::protocol::fetch::HeaderEntry;