use std::{path::PathBuf, time::Duration};
use thiserror::Error;
use crate::CargoLeptosMode;
#[derive(Debug, PartialEq, Eq)]
pub struct StartupFailureContext {
pub app_name: String,
pub expected_line: String,
pub stdout_tail: String,
pub stderr_tail: String,
}
#[derive(Debug, PartialEq, Eq, Error)]
pub enum LeptosBrowserTestError {
#[error("failed to resolve {app_name} directory {app_dir:?}")]
ResolveAppDir {
app_name: String,
app_dir: PathBuf,
},
#[error("failed to spawn `cargo leptos {mode_arg}` for {app_name}", mode_arg = mode.as_arg())]
SpawnCargoLeptos {
app_name: String,
mode: CargoLeptosMode,
},
#[error("failed to find a free site port for {app_name}")]
FindFreeSitePort {
app_name: String,
},
#[error("failed to find a free reload port for {app_name}")]
FindFreeReloadPort {
app_name: String,
},
#[error(
"{app_name} stdout closed before startup completed. Expected stdout to contain {expected_line:?}.\n\nRecent stdout:\n{stdout_tail}\n\nRecent stderr:\n{stderr_tail}",
app_name = .0.app_name,
expected_line = .0.expected_line,
stdout_tail = .0.stdout_tail,
stderr_tail = .0.stderr_tail,
)]
StartupStdoutClosed(StartupFailureContext),
#[error(
"{app_name} did not start within {timeout:?} ({reason}); expected stdout to contain {expected_line:?}.\n\nRecent stdout:\n{stdout_tail}\n\nRecent stderr:\n{stderr_tail}",
app_name = ctx.app_name,
expected_line = ctx.expected_line,
stdout_tail = ctx.stdout_tail,
stderr_tail = ctx.stderr_tail,
)]
StartupTimedOut {
ctx: StartupFailureContext,
timeout: Duration,
reason: String,
},
#[error(
"{app_name} failed to read stdout while waiting for {expected_line:?}.\n\nRecent stdout:\n{stdout_tail}\n\nRecent stderr:\n{stderr_tail}",
app_name = .0.app_name,
expected_line = .0.expected_line,
stdout_tail = .0.stdout_tail,
stderr_tail = .0.stderr_tail,
)]
StreamRead(StartupFailureContext),
#[error("invalid site_addr {site_addr:?} for {app_name}: expected `host:port`")]
InvalidSiteAddr {
app_name: String,
site_addr: String,
},
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use assertr::prelude::*;
use super::{LeptosBrowserTestError, StartupFailureContext};
fn ctx() -> StartupFailureContext {
StartupFailureContext {
app_name: "demo".to_owned(),
expected_line: "listening on".to_owned(),
stdout_tail: "out-line".to_owned(),
stderr_tail: "err-line".to_owned(),
}
}
#[test]
fn startup_stdout_closed_display_matches_documented_format() {
let err = LeptosBrowserTestError::StartupStdoutClosed(ctx());
assert_that!(err.to_string()).is_equal_to(
"demo stdout closed before startup completed. Expected stdout to contain \"listening on\".\n\nRecent stdout:\nout-line\n\nRecent stderr:\nerr-line"
.to_owned(),
);
}
#[test]
fn startup_timed_out_display_matches_documented_format() {
let err = LeptosBrowserTestError::StartupTimedOut {
ctx: ctx(),
timeout: Duration::from_secs(7),
reason: "tight bound for unit-style smoke test".to_owned(),
};
assert_that!(err.to_string()).is_equal_to(
"demo did not start within 7s (tight bound for unit-style smoke test); expected stdout to contain \"listening on\".\n\nRecent stdout:\nout-line\n\nRecent stderr:\nerr-line"
.to_owned(),
);
}
#[test]
fn stream_read_display_matches_documented_format() {
let err = LeptosBrowserTestError::StreamRead(ctx());
assert_that!(err.to_string()).is_equal_to(
"demo failed to read stdout while waiting for \"listening on\".\n\nRecent stdout:\nout-line\n\nRecent stderr:\nerr-line"
.to_owned(),
);
}
}