diff --git a/backend/src/data/db/user.rs b/backend/src/data/db/user.rs index 6948143..4ee1c59 100644 --- a/backend/src/data/db/user.rs +++ b/backend/src/data/db/user.rs @@ -13,13 +13,15 @@ use crate::{ #[derive(Debug, Display)] pub enum SignUpResult { UserAlreadyExists, - UserCreatedWaitingForValidation(String), // Validation token. + /// Validation token. + UserCreatedWaitingForValidation(String), } #[derive(Debug, Display)] pub enum UpdateUserResult { EmailAlreadyTaken, - UserUpdatedWaitingForRevalidation(String), // Validation token. + /// Validation token. + UserUpdatedWaitingForRevalidation(String), Ok, } @@ -27,7 +29,7 @@ pub enum UpdateUserResult { pub enum ValidationResult { UnknownUser, ValidationExpired, - /// Returns token and user id. + /// Returns login token and user id. Ok(String, i64), } @@ -36,7 +38,7 @@ pub enum SignInResult { UserNotFound, WrongPassword, AccountNotValidated, - /// Returns token and user id. + /// Returns login token and user id. Ok(String, i64), } diff --git a/backend/tests/http.rs b/backend/tests/http.rs index 958840d..4978b7b 100644 --- a/backend/tests/http.rs +++ b/backend/tests/http.rs @@ -1,16 +1,20 @@ use std::error::Error; use axum_test::TestServer; -use scraper::Html; +use cookie::Cookie; +use scraper::{ElementRef, Html, Selector}; -use recipes::{app, config, data::db, log}; +use recipes::app; + +mod utils; #[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 state = utils::common_state().await?; + let user_id = + utils::create_user(&state.db_connection, "president@spaceball.planet", "12345").await?; + let _recipe_id = utils::create_recipe(&state.db_connection, user_id, "spaghetti").await?; let server = TestServer::new(app::make_service(state))?; // Act. @@ -18,61 +22,73 @@ async fn homepage() -> Result<(), Box> { // 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); + let first_recipe_title = + Selector::parse("#recipes-list .recipes-list-public .recipe-item").unwrap(); + let elements: Vec = document.select(&first_recipe_title).collect(); + assert_eq!(elements.len(), 1); + assert_eq!(elements[0].inner_html(), "spaghetti"); 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")) - } +#[tokio::test] +async fn recipe_view() -> Result<(), Box> { + // Arrange. + let state = utils::common_state().await?; + let user_id = + utils::create_user(&state.db_connection, "president@spaceball.planet", "12345").await?; + let recipe_id = utils::create_recipe(&state.db_connection, user_id, "spaghetti").await?; + let server = TestServer::new(app::make_service(state))?; + + // Act. + let response = server.get(&format!("/recipe/view/{}", recipe_id)).await; + + // Assert. + response.assert_status_ok(); + + let document = Html::parse_document(&response.text()); + assert_eq!(document.errors.len(), 0); + + let recipe_title = Selector::parse("#recipe-view .recipe-title").unwrap(); + let elements: Vec = document.select(&recipe_title).collect(); + assert_eq!(elements.len(), 1); + assert_eq!(elements[0].inner_html(), "spaghetti"); + + Ok(()) } -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) -} +#[tokio::test] +async fn user_edit() -> Result<(), Box> { + // Arrange. + let state = utils::common_state().await?; + let _user_id = + utils::create_user(&state.db_connection, "president@spaceball.planet", "12345").await?; + let token = utils::sign_in(&state.db_connection, "president@spaceball.planet", "12345").await?; + let server = TestServer::new(app::make_service(state))?; -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, - }) + // Act. + let response = server + .get("/user/edit") + .add_cookie(Cookie::new("auth_token", token)) + .await; + + // Assert. + response.assert_status_ok(); + + let document = Html::parse_document(&response.text()); + assert_eq!(document.errors.len(), 0); + + let user_email = Selector::parse("#input-email").unwrap(); + let elements: Vec = document.select(&user_email).collect(); + assert_eq!(elements.len(), 1); + assert_eq!( + elements[0].attr("value").unwrap(), + "president@spaceball.planet" + ); + + Ok(()) } diff --git a/backend/tests/utils.rs b/backend/tests/utils.rs new file mode 100644 index 0000000..ac5e905 --- /dev/null +++ b/backend/tests/utils.rs @@ -0,0 +1,58 @@ +use std::error::Error; + +use recipes::{app, config, data::db, log}; + +pub 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, + }) +} + +pub 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), "", "") + .await? + { + Ok(user_id) + } else { + Err(Box::::from("Unable to validate user")) + } + } else { + Err(Box::::from("Unable to sign up")) + } +} + +pub async fn sign_in( + db_connection: &db::Connection, + email: &str, + password: &str, +) -> Result> { + match db_connection.sign_in(email, password, "", "").await? { + db::user::SignInResult::Ok(token, _) => Ok(token), + _ => Err(Box::::from("Unable to sign in")), + } +} + +pub 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) +}