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 => {
74 "\n Hint: method not found — the tool may be disabled by privacy profile"
75 }
76 -32602 => "\n Hint: invalid params — check the tool's expected arguments",
77 -32603 => "\n Hint: internal error — check the Tauri app's stderr for details",
78 _ => "",
79 };
80 write!(f, "MCP error {code}: {message}{hint}")
81 }
82 Self::ToolError(msg) => write!(f, "tool call failed: {msg}"),
83 Self::Assertion(msg) => write!(f, "assertion failed: {msg}"),
84 Self::Timeout(msg) => {
85 write!(
86 f,
87 "timeout: {msg}\n\
88 \n Possible fixes:\n\
89 \x20 - Increase timeout: .timeout_ms(10_000) or wait_for(..., Some(15_000), ...)\n\
90 \x20 - Check that the expected condition can actually be met\n\
91 \x20 - Look for JS errors: client.get_console_logs().await"
92 )
93 }
94 Self::ElementNotFound(msg) => {
95 write!(
96 f,
97 "element not found: {msg}\n\
98 \n Possible fixes:\n\
99 \x20 - Take a DOM snapshot to see what's on the page: client.dom_snapshot().await\n\
100 \x20 - The element may not have rendered yet — use expect().to_be_visible().await\n\
101 \x20 - Check for typos in the locator query"
102 )
103 }
104 Self::VisualRegression(msg) => {
105 write!(
106 f,
107 "visual regression: {msg}\n\
108 \n If the change is intentional, delete the baseline image to regenerate it.\n\
109 \x20 Use ThresholdPreset::Relaxed for cross-platform tolerance."
110 )
111 }
112 Self::Other(msg) => write!(f, "{msg}"),
113 }
114 }
115}
116
117impl std::error::Error for TestError {
118 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
119 match self {
120 Self::Request(e) => Some(e),
121 _ => None,
122 }
123 }
124}