leptos_browser_test/
config.rs1use crate::{CargoLeptosMode, LeptosBrowserTestError, SiteScheme, app::LeptosTestApp};
2use rootcause::Report;
3use std::{
4 ffi::{OsStr, OsString},
5 path::PathBuf,
6 time::Duration,
7};
8use tokio_process_tools::UnixGracefulSignal;
9
10const DEFAULT_STARTUP_LOG_TAIL_LINES: usize = 200;
11const DEFAULT_STARTUP_TIMEOUT: Duration = Duration::from_secs(60 * 10);
12const DEFAULT_STARTUP_TIMEOUT_REASON: &str =
13 "default — generous bound for a cold cargo-leptos compile of server + wasm";
14const DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(10);
15const DEFAULT_GRACEFUL_SHUTDOWN_UNIX_SIGNAL: UnixGracefulSignal = UnixGracefulSignal::Interrupt;
16
17#[derive(Debug, Clone)]
19pub struct LeptosTestAppConfig {
20 pub(crate) app_dir: PathBuf,
21 pub(crate) app_name: String,
22 pub(crate) mode: CargoLeptosMode,
23 pub(crate) cargo_bin: Option<OsString>,
24 pub(crate) site_scheme: SiteScheme,
25 pub(crate) site_addr: Option<String>,
26 pub(crate) reload_port: Option<u16>,
27 pub(crate) startup_line: Option<String>,
28 pub(crate) startup_timeout: Duration,
29 pub(crate) startup_timeout_reason: String,
30 pub(crate) startup_log_tail_lines: usize,
31 pub(crate) graceful_shutdown_timeout: Duration,
32 pub(crate) graceful_shutdown_unix_signal: UnixGracefulSignal,
33 pub(crate) forward_logs: bool,
34 pub(crate) extra_env: Vec<(OsString, OsString)>,
35}
36
37impl LeptosTestAppConfig {
38 #[must_use]
40 pub fn new(app_dir: impl Into<PathBuf>) -> Self {
41 Self {
42 app_dir: app_dir.into(),
43 app_name: "Leptos test app".to_owned(),
44 mode: CargoLeptosMode::Serve,
45 cargo_bin: None,
46 site_scheme: SiteScheme::Http,
47 site_addr: None,
48 reload_port: None,
49 startup_line: None,
50 startup_timeout: DEFAULT_STARTUP_TIMEOUT,
51 startup_timeout_reason: DEFAULT_STARTUP_TIMEOUT_REASON.to_owned(),
52 startup_log_tail_lines: DEFAULT_STARTUP_LOG_TAIL_LINES,
53 graceful_shutdown_timeout: DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT,
54 graceful_shutdown_unix_signal: DEFAULT_GRACEFUL_SHUTDOWN_UNIX_SIGNAL,
55 forward_logs: true,
56 extra_env: Vec::new(),
57 }
58 }
59
60 #[must_use]
62 pub fn with_app_name(mut self, app_name: impl Into<String>) -> Self {
63 self.app_name = app_name.into();
64 self
65 }
66
67 #[must_use]
69 pub const fn with_mode(mut self, mode: CargoLeptosMode) -> Self {
70 self.mode = mode;
71 self
72 }
73
74 #[must_use]
80 pub fn with_cargo(mut self, cargo_bin: impl Into<OsString>) -> Self {
81 self.cargo_bin = Some(cargo_bin.into());
82 self
83 }
84
85 #[must_use]
90 pub const fn with_site_scheme(mut self, site_scheme: SiteScheme) -> Self {
91 self.site_scheme = site_scheme;
92 self
93 }
94
95 #[must_use]
99 pub fn with_site_addr(mut self, site_addr: impl Into<String>) -> Self {
100 self.site_addr = Some(site_addr.into());
101 self
102 }
103
104 #[must_use]
108 pub const fn with_reload_port(mut self, reload_port: u16) -> Self {
109 self.reload_port = Some(reload_port);
110 self
111 }
112
113 #[must_use]
115 pub fn with_startup_line(mut self, startup_line: impl Into<String>) -> Self {
116 self.startup_line = Some(startup_line.into());
117 self
118 }
119
120 #[must_use]
129 pub fn with_startup_timeout(mut self, timeout: Duration, reason: impl Into<String>) -> Self {
130 self.startup_timeout = timeout;
131 self.startup_timeout_reason = reason.into();
132 self
133 }
134
135 #[must_use]
137 pub const fn with_startup_log_tail_lines(mut self, lines: usize) -> Self {
138 self.startup_log_tail_lines = lines;
139 self
140 }
141
142 #[must_use]
153 pub fn with_graceful_shutdown_timeout(mut self, timeout: Duration) -> Self {
154 self.graceful_shutdown_timeout = timeout;
155 self
156 }
157
158 #[must_use]
167 pub fn with_graceful_shutdown_unix_signal(mut self, signal: UnixGracefulSignal) -> Self {
168 self.graceful_shutdown_unix_signal = signal;
169 self
170 }
171
172 #[must_use]
179 pub fn with_env(mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> Self {
180 self.extra_env
181 .push((key.as_ref().to_owned(), value.as_ref().to_owned()));
182 self
183 }
184
185 #[must_use]
190 pub const fn with_forward_logs(mut self, forward_logs: bool) -> Self {
191 self.forward_logs = forward_logs;
192 self
193 }
194
195 pub async fn start(self) -> Result<LeptosTestApp, Report<LeptosBrowserTestError>> {
207 crate::app::start_configured_app(self).await
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use std::time::Duration;
214
215 use super::{
216 DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT, DEFAULT_GRACEFUL_SHUTDOWN_UNIX_SIGNAL,
217 DEFAULT_STARTUP_LOG_TAIL_LINES, DEFAULT_STARTUP_TIMEOUT, DEFAULT_STARTUP_TIMEOUT_REASON,
218 LeptosTestAppConfig,
219 };
220 use crate::{CargoLeptosMode, SiteScheme};
221 use assertr::prelude::*;
222 use tokio_process_tools::UnixGracefulSignal;
223
224 #[test]
225 fn new_uses_documented_defaults() {
226 let config = LeptosTestAppConfig::new("./test-app");
227
228 assert_that!(config.app_name).is_equal_to("Leptos test app");
229 assert_that!(config.mode).is_equal_to(CargoLeptosMode::Serve);
230 assert_that!(config.cargo_bin).is_equal_to(None);
231 assert_that!(config.site_scheme).is_equal_to(SiteScheme::Http);
232 assert_that!(config.site_addr).is_equal_to(None);
233 assert_that!(config.reload_port).is_equal_to(None);
234 assert_that!(config.startup_line).is_equal_to(None);
235 assert_that!(config.startup_timeout).is_equal_to(DEFAULT_STARTUP_TIMEOUT);
236 assert_that!(config.startup_timeout_reason).is_equal_to(DEFAULT_STARTUP_TIMEOUT_REASON);
237 assert_that!(config.startup_log_tail_lines).is_equal_to(DEFAULT_STARTUP_LOG_TAIL_LINES);
238 assert_that!(config.graceful_shutdown_timeout)
239 .is_equal_to(DEFAULT_GRACEFUL_SHUTDOWN_TIMEOUT);
240 assert_that!(config.graceful_shutdown_unix_signal)
241 .is_equal_to(DEFAULT_GRACEFUL_SHUTDOWN_UNIX_SIGNAL);
242 assert_that!(config.forward_logs).is_true();
243 assert_that!(config.extra_env.is_empty()).is_true();
244 }
245
246 #[test]
247 fn setters_override_defaults() {
248 let config = LeptosTestAppConfig::new("./test-app")
249 .with_app_name("custom")
250 .with_mode(CargoLeptosMode::Watch)
251 .with_cargo("/opt/cargo")
252 .with_site_scheme(SiteScheme::Https)
253 .with_site_addr("127.0.0.1:4000")
254 .with_reload_port(4001)
255 .with_startup_line("ready")
256 .with_startup_timeout(
257 Duration::from_secs(5),
258 "tight bound for unit-style smoke test",
259 )
260 .with_startup_log_tail_lines(10)
261 .with_graceful_shutdown_timeout(Duration::from_millis(100))
262 .with_graceful_shutdown_unix_signal(UnixGracefulSignal::Terminate)
263 .with_forward_logs(false)
264 .with_env("FOO", "bar");
265
266 assert_that!(config.app_name).is_equal_to("custom");
267 assert_that!(config.mode).is_equal_to(CargoLeptosMode::Watch);
268 assert_that!(config.cargo_bin).is_equal_to(Some(std::ffi::OsString::from("/opt/cargo")));
269 assert_that!(config.site_scheme).is_equal_to(SiteScheme::Https);
270 assert_that!(config.site_addr).is_equal_to(Some("127.0.0.1:4000".to_owned()));
271 assert_that!(config.reload_port).is_equal_to(Some(4001));
272 assert_that!(config.startup_line).is_equal_to(Some("ready".to_owned()));
273 assert_that!(config.startup_timeout).is_equal_to(Duration::from_secs(5));
274 assert_that!(config.startup_timeout_reason)
275 .is_equal_to("tight bound for unit-style smoke test");
276 assert_that!(config.startup_log_tail_lines).is_equal_to(10);
277 assert_that!(config.graceful_shutdown_timeout).is_equal_to(Duration::from_millis(100));
278 assert_that!(config.graceful_shutdown_unix_signal)
279 .is_equal_to(UnixGracefulSignal::Terminate);
280 assert_that!(config.forward_logs).is_false();
281 assert_that!(config.extra_env.len()).is_equal_to(1);
282 }
283}