Skip to content
Merged

234 #312

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 113 additions & 1 deletion src/frontend/browser_console_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,152 @@
//
// SPDX-License-Identifier: MIT

//! Browser console error types.
//!
//! This module defines [`BrowserConsoleError`], which represents failures
//! when attempting to serialize errors or log them to the browser console.
//!
//! # Error Variants
//!
//! - [`BrowserConsoleError::Serialization`] - Serialization to JsValue failed
//! - [`BrowserConsoleError::ConsoleUnavailable`] - Console object not
//! accessible
//! - [`BrowserConsoleError::ConsoleErrorUnavailable`] - console.error not
//! accessible
//! - [`BrowserConsoleError::ConsoleMethodNotCallable`] - console.error not
//! callable
//! - [`BrowserConsoleError::ConsoleInvocation`] - console.error invocation
//! failed
//! - [`BrowserConsoleError::UnsupportedTarget`] - Not a WASM target
//!
//! # Examples
//!
//! ```
//! use masterror::frontend::BrowserConsoleError;
//!
//! let err = BrowserConsoleError::Serialization {
//! message: "invalid JSON".to_owned()
//! };
//! assert_eq!(err.context(), Some("invalid JSON"));
//! ```

use crate::Error;

/// Error returned when emitting to the browser console fails or is unsupported.
#[derive(Debug, Error, PartialEq, Eq)]
///
/// # Examples
///
/// ```
/// use masterror::frontend::BrowserConsoleError;
///
/// let err = BrowserConsoleError::UnsupportedTarget;
/// assert_eq!(
/// err.to_string(),
/// "browser console logging is not supported on this target"
/// );
///
/// let err = BrowserConsoleError::ConsoleMethodNotCallable;
/// assert!(err.to_string().contains("not callable"));
/// ```
#[derive(Debug, Error, Clone, PartialEq, Eq)]
#[cfg_attr(docsrs, doc(cfg(feature = "frontend")))]
pub enum BrowserConsoleError {
/// Failed to serialize the payload into [`wasm_bindgen::JsValue`].
///
/// # Examples
///
/// ```
/// use masterror::frontend::BrowserConsoleError;
///
/// let err = BrowserConsoleError::Serialization {
/// message: "JSON error".to_owned()
/// };
/// assert_eq!(err.context(), Some("JSON error"));
/// assert!(err.to_string().contains("failed to serialize"));
/// ```
#[error("failed to serialize payload for browser console: {message}")]
Serialization {
/// Human-readable description of the serialization failure.
message: String
},

/// The global `console` object is unavailable or could not be accessed.
///
/// # Examples
///
/// ```
/// use masterror::frontend::BrowserConsoleError;
///
/// let err = BrowserConsoleError::ConsoleUnavailable {
/// message: "console is null".to_owned()
/// };
/// assert_eq!(err.context(), Some("console is null"));
/// ```
#[error("browser console object is not available: {message}")]
ConsoleUnavailable {
/// Additional context explaining the failure.
message: String
},

/// The `console.error` function is missing or not accessible.
///
/// # Examples
///
/// ```
/// use masterror::frontend::BrowserConsoleError;
///
/// let err = BrowserConsoleError::ConsoleErrorUnavailable {
/// message: "error method undefined".to_owned()
/// };
/// assert_eq!(err.context(), Some("error method undefined"));
/// ```
#[error("failed to access browser console `error`: {message}")]
ConsoleErrorUnavailable {
/// Additional context explaining the failure.
message: String
},

/// The retrieved `console.error` value is not callable.
///
/// # Examples
///
/// ```
/// use masterror::frontend::BrowserConsoleError;
///
/// let err = BrowserConsoleError::ConsoleMethodNotCallable;
/// assert_eq!(err.context(), None);
/// ```
#[error("browser console `error` method is not callable")]
ConsoleMethodNotCallable,

/// Invoking `console.error` returned an error.
///
/// # Examples
///
/// ```
/// use masterror::frontend::BrowserConsoleError;
///
/// let err = BrowserConsoleError::ConsoleInvocation {
/// message: "TypeError".to_owned()
/// };
/// assert_eq!(err.context(), Some("TypeError"));
/// ```
#[error("failed to invoke browser console `error`: {message}")]
ConsoleInvocation {
/// Textual representation of the JavaScript exception.
message: String
},

/// Logging is not supported on the current compilation target.
///
/// # Examples
///
/// ```
/// use masterror::frontend::BrowserConsoleError;
///
/// let err = BrowserConsoleError::UnsupportedTarget;
/// assert_eq!(err.context(), None);
/// ```
#[error("browser console logging is not supported on this target")]
UnsupportedTarget
}
Expand Down
68 changes: 68 additions & 0 deletions src/frontend/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,74 @@ fn partial_eq_works() {
assert_ne!(err1, err3);
}

#[test]
fn serialization_error_with_empty_message() {
let err = BrowserConsoleError::Serialization {
message: String::new()
};
assert_eq!(err.context(), Some(""));
assert!(err.to_string().contains("failed to serialize"));
}

#[test]
fn console_unavailable_with_unicode() {
let err = BrowserConsoleError::ConsoleUnavailable {
message: "コンソールなし".to_owned()
};
assert_eq!(err.context(), Some("コンソールなし"));
}

#[test]
fn console_error_unavailable_with_long_message() {
let long_msg = "x".repeat(1000);
let err = BrowserConsoleError::ConsoleErrorUnavailable {
message: long_msg.clone()
};
assert_eq!(err.context(), Some(long_msg.as_str()));
}

#[test]
fn console_invocation_with_special_chars() {
let err = BrowserConsoleError::ConsoleInvocation {
message: "Error: \"test\" <>&".to_owned()
};
assert_eq!(err.context(), Some("Error: \"test\" <>&"));
}

#[test]
fn clone_works_for_error_variants() {
let err1 = BrowserConsoleError::Serialization {
message: "test".to_owned()
};
let err2 = err1.clone();
assert_eq!(err1, err2);
}

#[test]
fn eq_compares_messages() {
let err1 = BrowserConsoleError::Serialization {
message: "msg1".to_owned()
};
let err2 = BrowserConsoleError::Serialization {
message: "msg1".to_owned()
};
let err3 = BrowserConsoleError::Serialization {
message: "msg2".to_owned()
};

assert_eq!(err1, err2);
assert_ne!(err1, err3);
}

#[test]
fn context_returns_none_for_unit_variants() {
assert_eq!(
BrowserConsoleError::ConsoleMethodNotCallable.context(),
None
);
assert_eq!(BrowserConsoleError::UnsupportedTarget.context(), None);
}

#[cfg(not(target_arch = "wasm32"))]
mod native {
use super::*;
Expand Down
Loading