From 1485110204307fbe9b1b449c8338c5dfeb384419 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Wed, 30 Apr 2025 01:39:11 +0200 Subject: [PATCH] Integration tests: homepage (WIP) --- Cargo.lock | 413 +++++++++++++++++++++++++++++++++++++ backend/Cargo.toml | 4 + backend/src/data/db/mod.rs | 1 - backend/src/log.rs | 99 +++++---- backend/src/main.rs | 2 +- backend/tests/http.rs | 78 +++++++ 6 files changed, 556 insertions(+), 41 deletions(-) create mode 100644 backend/tests/http.rs diff --git a/Cargo.lock b/Cargo.lock index d3cd69b..11ef38a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,6 +109,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + [[package]] name = "argon2" version = "0.5.3" @@ -163,6 +169,16 @@ dependencies = [ "winnow 0.7.7", ] +[[package]] +name = "assert-json-diff" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "async-compression" version = "0.4.23" @@ -196,6 +212,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "auto-future" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c1e7e457ea78e524f48639f551fd79703ac3f2237f5ecccdf4708f8a75ad373" + [[package]] name = "autocfg" version = "1.4.0" @@ -294,6 +316,36 @@ dependencies = [ "syn", ] +[[package]] +name = "axum-test" +version = "17.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eb1dfb84bd48bad8e4aa1acb82ed24c2bb5e855b659959b4e03b4dca118fcac" +dependencies = [ + "anyhow", + "assert-json-diff", + "auto-future", + "axum", + "bytes", + "bytesize", + "cookie", + "http 1.3.1", + "http-body-util", + "hyper", + "hyper-util", + "mime", + "pretty_assertions", + "reserve-port", + "rust-multipart-rfc7578_2", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "tokio", + "tower", + "url", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -430,6 +482,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "bytesize" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3c8f83209414aacf0eeae3cf730b18d6981697fba62f200fcfb92b9f082acba" + [[package]] name = "caseless" version = "0.2.2" @@ -664,6 +722,29 @@ dependencies = [ "typenum", ] +[[package]] +name = "cssparser" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c66d1cd8ed61bf80b38432613a7a2f09401ab8d0501110655f8b341484a3e3" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "darling" version = "0.20.11" @@ -719,12 +800,29 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "deunicode" version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abd57806937c9cc163efc8ea3910e00a62e2aeb0b8119f1793a978088f8f6b04" +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.10.7" @@ -754,6 +852,27 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "ego-tree" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2972feb8dffe7bc8c5463b1dacda1b0dfbed3710e50f977d965429692d74cd8" + [[package]] name = "either" version = "1.15.0" @@ -901,6 +1020,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + [[package]] name = "futures" version = "0.3.31" @@ -1001,6 +1130,15 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1011,6 +1149,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + [[package]] name = "getrandom" version = "0.2.16" @@ -1306,6 +1453,18 @@ dependencies = [ "windows-link", ] +[[package]] +name = "html5ever" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" +dependencies = [ + "log", + "mac", + "markup5ever", + "match_token", +] + [[package]] name = "http" version = "0.2.12" @@ -1386,6 +1545,7 @@ dependencies = [ "pin-project-lite", "smallvec", "tokio", + "want", ] [[package]] @@ -1395,13 +1555,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" dependencies = [ "bytes", + "futures-channel", "futures-util", "http 1.3.1", "http-body", "hyper", + "libc", "pin-project-lite", + "socket2", "tokio", "tower-service", + "tracing", ] [[package]] @@ -1709,6 +1873,37 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "markup5ever" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" +dependencies = [ + "log", + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1776,6 +1971,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nom" version = "8.0.0" @@ -1946,6 +2147,58 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project" version = "1.1.10" @@ -2044,6 +2297,22 @@ dependencies = [ "zerocopy 0.8.25", ] +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "prettyplease" version = "0.2.32" @@ -2186,6 +2455,7 @@ dependencies = [ "async-compression", "axum", "axum-extra", + "axum-test", "chrono", "clap", "common", @@ -2195,6 +2465,7 @@ dependencies = [ "rand 0.9.1", "rand_core 0.9.3", "ron", + "scraper", "serde", "sqlx", "strum", @@ -2261,6 +2532,15 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "reserve-port" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3747658ee2585ecf5607fa9887c92eff61b362ff5253dbf797dfeb73d33d78" +dependencies = [ + "thiserror 2.0.12", +] + [[package]] name = "ring" version = "0.17.14" @@ -2308,6 +2588,21 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rust-multipart-rfc7578_2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c839d037155ebc06a571e305af66ff9fd9063a6e662447051737e1ac75beea41" +dependencies = [ + "bytes", + "futures-core", + "futures-util", + "http 1.3.1", + "mime", + "rand 0.9.1", + "thiserror 2.0.12", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -2401,6 +2696,40 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scraper" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527e65d9d888567588db4c12da1087598d0f6f8b346cc2c5abc91f05fc2dffe2" +dependencies = [ + "cssparser", + "ego-tree", + "getopts", + "html5ever", + "precomputed-hash", + "selectors", + "tendril", +] + +[[package]] +name = "selectors" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd568a4c9bb598e291a08244a5c1f5a8a6650bee243b5b0f8dbb3d9cc1d87fe8" +dependencies = [ + "bitflags 2.9.0", + "cssparser", + "derive_more", + "fxhash", + "log", + "new_debug_unreachable", + "phf", + "phf_codegen", + "precomputed-hash", + "servo_arc", + "smallvec", +] + [[package]] name = "serde" version = "1.0.219" @@ -2479,6 +2808,15 @@ dependencies = [ "serde", ] +[[package]] +name = "servo_arc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae65c4249478a2647db249fb43e23cec56a2c8974a427e7bd8cb5a1d0964921a" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "sha1" version = "0.10.6" @@ -2541,6 +2879,12 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -2810,6 +3154,31 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", +] + [[package]] name = "stringprep" version = "0.1.5" @@ -2916,6 +3285,17 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + [[package]] name = "terminal_size" version = "0.4.2" @@ -3239,6 +3619,12 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "typed-arena" version = "2.0.2" @@ -3284,6 +3670,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + [[package]] name = "unicode_categories" version = "0.1.1" @@ -3313,6 +3705,12 @@ version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a1f0175e03a0973cf4afd476bef05c26e228520400eb1fd473ad417b1c00ffb" +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf16_iter" version = "1.0.5" @@ -3359,6 +3757,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -3785,6 +4192,12 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "yoke" version = "0.7.5" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index a5beac3..615aff4 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -49,3 +49,7 @@ lettre = { version = "0.11", default-features = false, features = [ ] } thiserror = "2" + +[dev-dependencies] +axum-test = "17" +scraper = "0.23" diff --git a/backend/src/data/db/mod.rs b/backend/src/data/db/mod.rs index 0e19a8b..10b9553 100644 --- a/backend/src/data/db/mod.rs +++ b/backend/src/data/db/mod.rs @@ -59,7 +59,6 @@ impl Connection { Self::new_from_file(path).await } - #[cfg(test)] pub async fn new_in_memory() -> Result { Self::create_connection(SqlitePoolOptions::new().connect("sqlite::memory:").await?).await } diff --git a/backend/src/log.rs b/backend/src/log.rs index a2dbe30..a35056a 100644 --- a/backend/src/log.rs +++ b/backend/src/log.rs @@ -29,13 +29,16 @@ const TRACING_LEVEL: tracing::Level = tracing::Level::INFO; const TRACING_DISPLAY_THREAD: bool = false; #[derive(Clone)] -pub struct Log { - _guard: Arc, - directory: PathBuf, +pub enum Log { + FileAndStdout { + _guard: Arc, + directory: PathBuf, + }, + StdoutOnly, } impl Log { - pub fn new

(directory: P) -> Self + pub fn new_to_directory

(directory: P) -> Self where P: AsRef, { @@ -68,51 +71,69 @@ impl Log { .with(layer_stdout) .init(); - Log { + Log::FileAndStdout { _guard: Arc::new(guard), directory: directory.as_ref().to_path_buf(), } } - pub fn file_names(&self) -> std::io::Result> { - fn dir_entry_to_string(entry: Result) -> String { - entry.map_or_else( - |err| format!("Unable to read entry: {}", err), - |entry| { - entry - .path() - .file_name() - .map_or("Unable to read filename".into(), |filename| { - filename - .to_str() - .map_or("Unable to read filename".into(), |filename| { - filename.to_string() - }) - }) - }, - ) - } + pub fn new_stdout_only() -> Self { + let layer_stdout = tracing_subscriber::fmt::layer() + .with_writer(std::io::stdout.with_max_level(TRACING_LEVEL)) + .with_thread_ids(TRACING_DISPLAY_THREAD) + .with_thread_names(TRACING_DISPLAY_THREAD); - Ok(self - .directory - .read_dir()? - .map(dir_entry_to_string) - .sorted() - .rev() - .collect()) + tracing_subscriber::Registry::default() + .with(layer_stdout) + .init(); + + Log::StdoutOnly + } + + pub fn file_names(&self) -> std::io::Result> { + match self { + Log::FileAndStdout { _guard, directory } => { + fn dir_entry_to_string(entry: Result) -> String { + entry.map_or_else( + |err| format!("Unable to read entry: {}", err), + |entry| { + entry.path().file_name().map_or( + "Unable to read filename".into(), + |filename| { + filename + .to_str() + .map_or("Unable to read filename".into(), |filename| { + filename.to_string() + }) + }, + ) + }, + ) + } + + Ok(directory + .read_dir()? + .map(dir_entry_to_string) + .sorted() + .rev() + .collect()) + } + Log::StdoutOnly => Ok(vec![]), + } } /// Reads the content of a log file and return it as a vector of lines. pub fn read_content(&self, filename: &str) -> std::io::Result> { - let filepath = self.directory.join(filename); - if filepath.is_file() { - let file = File::open(filepath)?; - Ok(BufReader::new(file) - .lines() - .map(|l| l.unwrap_or_default()) - .collect()) - } else { - Ok(vec![]) + match self { + Log::FileAndStdout { _guard, directory } => { + let filepath = directory.join(filename); + let file = File::open(filepath)?; + Ok(BufReader::new(file) + .lines() + .map(|l| l.unwrap_or_default()) + .collect()) + } + Log::StdoutOnly => Ok(vec![]), } } diff --git a/backend/src/main.rs b/backend/src/main.rs index 1f56a0a..d1eb736 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -15,7 +15,7 @@ use recipes::{ #[tokio::main] async fn main() -> Result<(), Box> { let config = config::load(); - let log = Log::new(&config.logs_directory); + let log = Log::new_to_directory(&config.logs_directory); event!(Level::INFO, "Configuration: {:?}", config); diff --git a/backend/tests/http.rs b/backend/tests/http.rs new file mode 100644 index 0000000..958840d --- /dev/null +++ b/backend/tests/http.rs @@ -0,0 +1,78 @@ +use std::error::Error; + +use axum_test::TestServer; +use scraper::Html; + +use recipes::{app, config, data::db, log}; + +#[tokio::test] +async fn homepage() -> Result<(), Box> { + // Arrange. + let state = common_state().await?; + let user_id = create_user(&state.db_connection, "president@spaceball.planet", "12345").await?; + let _recipe_id = create_recipe(&state.db_connection, user_id, "spaghetti").await?; + let server = TestServer::new(app::make_service(state))?; + + // Act. + let response = server.get("/").await; + + // Assert. + response.assert_status_ok(); + // TODO: check if 'spaghetti' is in the list. + let document = Html::parse_document(&response.text()); + assert_eq!(document.errors.len(), 0); + + // println!("{:?}", document.errors); + // println!("{:?}", response); + + Ok(()) +} + +async fn create_user( + db_connection: &db::Connection, + email: &str, + password: &str, +) -> Result> { + if let db::user::SignUpResult::UserCreatedWaitingForValidation(token) = db_connection + .sign_up(email, password, chrono::Weekday::Mon) + .await? + { + if let db::user::ValidationResult::Ok(_, user_id) = db_connection + .validation( + &token, + chrono::Duration::hours(1), + "127.0.0.1", + "Mozilla/5.0", + ) + .await? + { + Ok(user_id) + } else { + Err(Box::::from("Unable to validate user")) + } + } else { + Err(Box::::from("Unable to sign up")) + } +} + +async fn create_recipe( + db_connection: &db::Connection, + user_id: i64, + title: &str, +) -> Result> { + let recipe_id = db_connection.create_recipe(user_id).await?; + db_connection.set_recipe_title(recipe_id, title).await?; + db_connection.set_recipe_is_public(recipe_id, true).await?; + Ok(recipe_id) +} + +async fn common_state() -> Result> { + let db_connection = db::Connection::new_in_memory().await?; + let config = config::Config::default(); + let log = log::Log::new_stdout_only(); + Ok(app::AppState { + config, + db_connection, + log, + }) +}