viewpoint_core/page/page_error/
mod.rs

1//! Page error types and event handling.
2//!
3//! This module provides types for capturing uncaught JavaScript exceptions
4//! and errors from the page.
5
6use viewpoint_cdp::protocol::runtime::{ExceptionDetails, ExceptionThrownEvent};
7
8/// An uncaught exception from the page.
9///
10/// Page errors are emitted when JavaScript code throws an uncaught exception.
11/// These correspond to the 'pageerror' event in Playwright.
12///
13/// # Example
14///
15/// ```ignore
16/// page.on_pageerror(|error| async move {
17///     println!("Page error: {}", error.message());
18///     Ok(())
19/// }).await;
20/// ```
21#[derive(Debug, Clone)]
22pub struct PageError {
23    /// Exception details.
24    exception_details: ExceptionDetails,
25    /// Timestamp when the error occurred.
26    timestamp: f64,
27}
28
29impl PageError {
30    /// Create a new page error from a CDP event.
31    pub(crate) fn from_event(event: ExceptionThrownEvent) -> Self {
32        Self {
33            exception_details: event.exception_details,
34            timestamp: event.timestamp,
35        }
36    }
37
38    /// Get the error message.
39    pub fn message(&self) -> String {
40        // Try to get the exception message first
41        if let Some(ref exception) = self.exception_details.exception {
42            if let Some(ref description) = exception.description {
43                return description.clone();
44            }
45            if let Some(ref value) = exception.value {
46                if let Some(s) = value.as_str() {
47                    return s.to_string();
48                }
49                return value.to_string();
50            }
51        }
52        
53        // Fall back to the exception text
54        self.exception_details.text.clone()
55    }
56
57    /// Get the full stack trace as a string.
58    pub fn stack(&self) -> Option<String> {
59        self.exception_details.exception.as_ref().and_then(|exc| {
60            exc.description.clone()
61        })
62    }
63
64    /// Get the error name (e.g., "`TypeError`", "`ReferenceError`").
65    pub fn name(&self) -> Option<String> {
66        self.exception_details.exception.as_ref().and_then(|exc| {
67            exc.class_name.clone()
68        })
69    }
70
71    /// Get the URL where the error occurred.
72    pub fn url(&self) -> Option<&str> {
73        self.exception_details.url.as_deref()
74    }
75
76    /// Get the line number where the error occurred.
77    pub fn line_number(&self) -> i64 {
78        self.exception_details.line_number
79    }
80
81    /// Get the column number where the error occurred.
82    pub fn column_number(&self) -> i64 {
83        self.exception_details.column_number
84    }
85
86    /// Get the timestamp when the error occurred.
87    pub fn timestamp(&self) -> f64 {
88        self.timestamp
89    }
90}
91
92impl std::fmt::Display for PageError {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        if let Some(name) = self.name() {
95            write!(f, "{}: {}", name, self.message())
96        } else {
97            write!(f, "{}", self.message())
98        }
99    }
100}
101
102impl std::error::Error for PageError {}
103
104/// An error from any page in a browser context.
105///
106/// Web errors are emitted at the context level when any page has an uncaught
107/// exception. They include a reference to the page where the error occurred.
108///
109/// # Example
110///
111/// ```ignore
112/// context.on_weberror(|error| async move {
113///     println!("Error on page {}: {}", error.page_url(), error.message());
114///     Ok(())
115/// }).await;
116/// ```
117#[derive(Debug, Clone)]
118pub struct WebError {
119    /// The underlying page error.
120    error: PageError,
121    /// Target ID of the page where the error occurred.
122    target_id: String,
123    /// Session ID of the page.
124    session_id: String,
125}
126
127impl WebError {
128    /// Create a new web error.
129    pub(crate) fn new(error: PageError, target_id: String, session_id: String) -> Self {
130        Self {
131            error,
132            target_id,
133            session_id,
134        }
135    }
136
137    /// Get the error message.
138    pub fn message(&self) -> String {
139        self.error.message()
140    }
141
142    /// Get the full stack trace as a string.
143    pub fn stack(&self) -> Option<String> {
144        self.error.stack()
145    }
146
147    /// Get the error name.
148    pub fn name(&self) -> Option<String> {
149        self.error.name()
150    }
151
152    /// Get the target ID of the page where the error occurred.
153    pub fn target_id(&self) -> &str {
154        &self.target_id
155    }
156
157    /// Get the session ID of the page.
158    pub fn session_id(&self) -> &str {
159        &self.session_id
160    }
161
162    /// Get the underlying page error.
163    pub fn page_error(&self) -> &PageError {
164        &self.error
165    }
166}
167
168impl std::fmt::Display for WebError {
169    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170        write!(f, "{}", self.error)
171    }
172}
173
174impl std::error::Error for WebError {}