diff --git a/Cargo.lock b/Cargo.lock index 03635db..0659a49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -540,9 +540,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" +checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" dependencies = [ "clap_builder", "clap_derive", @@ -550,9 +550,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" +checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" dependencies = [ "anstream", "anstyle", @@ -640,6 +640,35 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const_format" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c990efc7a285731f9a4378d81aff2f0e85a2c8781a05ef0f8baa8dac54d0ff48" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e026b6ce194a874cb9cf32cd5772d1ef9767cc8fcb5765948d74f37a9d8b2bf6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cookie" version = "0.18.1" @@ -1024,7 +1053,6 @@ dependencies = [ "futures", "gloo", "ron", - "scanf", "serde", "serde_html_form", "thiserror 2.0.12", @@ -1681,9 +1709,9 @@ dependencies = [ [[package]] name = "lettre" -version = "0.11.15" +version = "0.11.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759bc2b8eabb6a30b235d6f716f7f36479f4b38cbe65b8747aefee51f89e8437" +checksum = "87ffd14fa289730e3ad68edefdc31f603d56fe716ec38f2076bb7410e09147c2" dependencies = [ "async-trait", "base64", @@ -1705,7 +1733,7 @@ dependencies = [ "tokio", "tokio-rustls", "url", - "webpki-roots 0.26.11", + "webpki-roots", ] [[package]] @@ -2400,10 +2428,10 @@ dependencies = [ "rand 0.9.1", "rand_core 0.9.3", "ron", - "scanf", "scraper", "serde", "sqlx", + "sscanf", "strum", "thiserror 2.0.12", "tokio", @@ -2619,15 +2647,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scanf" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2388de1e65f8545db637b467e3a8ed3c85357ff098c16aa4e9493561e49d03" -dependencies = [ - "nom", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -3062,6 +3081,33 @@ dependencies = [ "url", ] +[[package]] +name = "sscanf" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbd1009b536a04035c8ffcf967496c7726c6b4971c9939b20ad085ac9377d4f0" +dependencies = [ + "const_format", + "lazy_static", + "regex", + "sscanf_macro", +] + +[[package]] +name = "sscanf_macro" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cffce0630a574bbcda2476cf733363c7e077001c386b0dea87b77eb397ca1a37" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "regex-syntax 0.6.29", + "strsim", + "syn", + "unicode-width", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -3204,9 +3250,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", "getrandom 0.3.3", @@ -3429,9 +3475,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" +checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" dependencies = [ "bitflags 2.9.0", "bytes", @@ -3590,10 +3636,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] -name = "unicode-width" -version = "0.1.14" +name = "unicode-segmentation" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unicode_categories" @@ -3794,15 +3852,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.0", -] - [[package]] name = "webpki-roots" version = "1.0.0" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 6160daf..7358004 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -56,4 +56,4 @@ axum-test = "17" cookie = "0.18" scraper = "0.23" mockall = "0.13" -scanf = "1.2" +sscanf = "0.4" diff --git a/backend/src/services/mod.rs b/backend/src/services/mod.rs index 9f324aa..792a0ca 100644 --- a/backend/src/services/mod.rs +++ b/backend/src/services/mod.rs @@ -13,7 +13,6 @@ use crate::{ data::db, html_templates::*, log::Log, - ron_utils, translation::Sentence, }; diff --git a/backend/tests/http.rs b/backend/tests/http.rs index fa80c9f..3fef86f 100644 --- a/backend/tests/http.rs +++ b/backend/tests/http.rs @@ -1,11 +1,14 @@ use std::{error::Error, sync::Arc}; +use axum::http; use axum_test::TestServer; +use common::ron_api; use cookie::Cookie; use scraper::{ElementRef, Html, Selector}; +use serde::Serialize; +use sscanf::sscanf; use recipes::{app, email}; -use serde::Serialize; mod utils; @@ -109,7 +112,6 @@ pub struct SignUpFormData { #[tokio::test] async fn sign_up() -> Result<(), Box> { - use scanf::sscanf; use std::{cell::RefCell, rc::Rc}; // Arrange. @@ -124,12 +126,12 @@ async fn sign_up() -> Result<(), Box> { }) .times(1) .returning_st(move |_email_sender, _email_receiver, _title, message| { - sscanf!( + let url = sscanf!( message, - "Follow this link to confirm your inscription, http://127.0.0.1:8000{}", - *validation_url_clone.borrow_mut() + "Follow this link to confirm your inscription, http://127.0.0.1:8000{String}" ) .unwrap(); + *validation_url_clone.borrow_mut() = url; Ok(()) }); @@ -219,8 +221,113 @@ async fn sign_in() -> Result<(), Box> { // Assert. response.assert_status_see_other(); // Redirection after successful sign in. response.assert_text(""); - // English is the default language. response.assert_header("location", "/?user_message=16&user_message_icon=0"); Ok(()) } + +#[tokio::test] +async fn create_recipe_and_edit_it() -> Result<(), Box> { + // Arrange. + let state = utils::common_state().await?; + let _user_id = utils::create_user( + &state.db_connection, + "president@spaceball.planet", + "12345678", + ) + .await?; + let token = utils::sign_in( + &state.db_connection, + "president@spaceball.planet", + "12345678", + ) + .await?; + let server = TestServer::new(app::make_service(state))?; + + // Act. + let cookie = Cookie::new("auth_token", token); + + let response = server.get("/recipe/new").add_cookie(cookie.clone()).await; + response.assert_status_see_other(); + + let location = response.header("location").to_str().unwrap().to_string(); + let recipe_id = sscanf!(&location, "/en/recipe/edit/{i64}").unwrap(); + + let response = server.get(&location).add_cookie(cookie.clone()).await; + response.assert_status_ok(); + + let response = server + .patch("/ron-api/recipe/title") + .add_cookie(cookie.clone()) + .add_header(http::header::CONTENT_TYPE, common::consts::MIME_TYPE_RON) + .bytes( + ron_api::to_string(ron_api::SetRecipeTitle { + recipe_id, + title: "AAA".into(), + }) + .unwrap() + .into(), + ) + .await; + response.assert_status_ok(); + + let response = server + .patch("/ron-api/recipe/description") + .add_cookie(cookie.clone()) + .add_header(http::header::CONTENT_TYPE, common::consts::MIME_TYPE_RON) + .bytes( + ron_api::to_string(ron_api::SetRecipeDescription { + recipe_id, + description: "BBB".into(), + }) + .unwrap() + .into(), + ) + .await; + response.assert_status_ok(); + + let response = server + .patch("/ron-api/recipe/servings") + .add_cookie(cookie.clone()) + .add_header(http::header::CONTENT_TYPE, common::consts::MIME_TYPE_RON) + .bytes( + ron_api::to_string(ron_api::SetRecipeServings { + recipe_id, + servings: Some(42), + }) + .unwrap() + .into(), + ) + .await; + response.assert_status_ok(); + + // TODO: Set other recipe fields. + + // Assert. + let response = server + .get(&format!("/recipe/edit/{}", recipe_id)) + .add_cookie(cookie.clone()) + .await; + response.assert_status_ok(); + + let document = Html::parse_document(&response.text()); + if !document.errors.is_empty() { + panic!("{:?}", document.errors); + } + + let title_selector = Selector::parse("#input-title").unwrap(); + let element_title = document.select(&title_selector).next().unwrap(); + assert_eq!(element_title.attr("value").unwrap(), "AAA"); + + let description_selector = Selector::parse("#text-area-description").unwrap(); + let element_description = document.select(&description_selector).next().unwrap(); + assert_eq!(element_description.inner_html(), "BBB"); + + let servings_selector = Selector::parse("#input-servings").unwrap(); + let element_servings = document.select(&servings_selector).next().unwrap(); + assert_eq!(element_servings.attr("value").unwrap(), "42"); + + // dbg!(response); + + Ok(()) +}