1#[derive(Debug)]
5#[non_exhaustive]
6pub enum TestError {
7 Connection {
9 host: String,
11 port: u16,
13 reason: String,
15 },
16
17 Request(reqwest::Error),
19
20 Mcp {
22 code: i64,
24 message: String,
26 },
27
28 ToolError(String),
30
31 Assertion(String),
33
34 Timeout(String),
36
37 ElementNotFound(String),
39
40 VisualRegression(String),
42
43 Other(String),
45}
46
47impl From<reqwest::Error> for TestError {
48 fn from(e: reqwest::Error) -> Self {
49 Self::Request(e)
50 }
51}
52
53impl std::fmt::Display for TestError {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 match self {
56 Self::Connection { host, port, reason } => {
57 write!(
58 f,
59 "connection failed ({host}:{port}): {reason}\n\
60 \n Possible fixes:\n\
61 \x20 - Is your Tauri app running? Start it with: pnpm tauri dev\n\
62 \x20 - Check that victauri-plugin is wired in your Tauri builder\n\
63 \x20 - Try a different port: VICTAURI_PORT={port} cargo test\n\
64 \x20 - Run `victauri doctor` for full diagnostics"
65 )
66 }
67 Self::Request(e) => {
68 write!(f, "MCP request failed: {e}")
69 }
70 Self::Mcp { code, message } => {
71 let hint = match *code {
72 -32600 => "\n Hint: invalid request — check your MCP protocol version",
73 -32601 => "\n Hint: method not found — the tool may be disabled by privacy profile",
74 -32602 => "\n Hint: invalid params — check the tool's expected arguments",
75 -32603 => "\n Hint: internal error — check the Tauri app's stderr for details",
76 _ => "",
77 };
78 write!(f, "MCP error {code}: {message}{hint}")
79 }
80 Self::ToolError(msg) => write!(f, "tool call failed: {msg}"),
81 Self::Assertion(msg) => write!(f, "assertion failed: {msg}"),
82 Self::Timeout(msg) => {
83 write!(
84 f,
85 "timeout: {msg}\n\
86 \n Possible fixes:\n\
87 \x20 - Increase timeout: .timeout_ms(10_000) or wait_for(..., Some(15_000), ...)\n\
88 \x20 - Check that the expected condition can actually be met\n\
89 \x20 - Look for JS errors: client.get_console_logs().await"
90 )
91 }
92 Self::ElementNotFound(msg) => {
93 write!(
94 f,
95 "element not found: {msg}\n\
96 \n Possible fixes:\n\
97 \x20 - Take a DOM snapshot to see what's on the page: client.dom_snapshot().await\n\
98 \x20 - The element may not have rendered yet — use expect().to_be_visible().await\n\
99 \x20 - Check for typos in the locator query"
100 )
101 }
102 Self::VisualRegression(msg) => {
103 write!(
104 f,
105 "visual regression: {msg}\n\
106 \n If the change is intentional, delete the baseline image to regenerate it.\n\
107 \x20 Use ThresholdPreset::Relaxed for cross-platform tolerance."
108 )
109 }
110 Self::Other(msg) => write!(f, "{msg}"),
111 }
112 }
113}
114
115impl std::error::Error for TestError {
116 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
117 match self {
118 Self::Request(e) => Some(e),
119 _ => None,
120 }
121 }
122}