init commit
This commit is contained in:
218
tests/requests/auth.rs
Normal file
218
tests/requests/auth.rs
Normal file
@@ -0,0 +1,218 @@
|
||||
use insta::{assert_debug_snapshot, with_settings};
|
||||
use loco_rs::testing;
|
||||
use gabrielkaszewski_rs::{app::App, models::users};
|
||||
use rstest::rstest;
|
||||
use serial_test::serial;
|
||||
|
||||
use super::prepare_data;
|
||||
|
||||
// TODO: see how to dedup / extract this to app-local test utils
|
||||
// not to framework, because that would require a runtime dep on insta
|
||||
macro_rules! configure_insta {
|
||||
($($expr:expr),*) => {
|
||||
let mut settings = insta::Settings::clone_current();
|
||||
settings.set_prepend_module_to_snapshot(false);
|
||||
settings.set_snapshot_suffix("auth_request");
|
||||
let _guard = settings.bind_to_scope();
|
||||
};
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn can_register() {
|
||||
configure_insta!();
|
||||
|
||||
testing::request::<App, _, _>(|request, ctx| async move {
|
||||
let email = "test@loco.com";
|
||||
let payload = serde_json::json!({
|
||||
"name": "loco",
|
||||
"email": email,
|
||||
"password": "12341234"
|
||||
});
|
||||
|
||||
let _response = request.post("/api/auth/register").json(&payload).await;
|
||||
let saved_user = users::Model::find_by_email(&ctx.db, email).await;
|
||||
|
||||
with_settings!({
|
||||
filters => testing::cleanup_user_model()
|
||||
}, {
|
||||
assert_debug_snapshot!(saved_user);
|
||||
});
|
||||
|
||||
with_settings!({
|
||||
filters => testing::cleanup_email()
|
||||
}, {
|
||||
assert_debug_snapshot!(ctx.mailer.unwrap().deliveries());
|
||||
});
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case("login_with_valid_password", "12341234")]
|
||||
#[case("login_with_invalid_password", "invalid-password")]
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn can_login_with_verify(#[case] test_name: &str, #[case] password: &str) {
|
||||
configure_insta!();
|
||||
|
||||
testing::request::<App, _, _>(|request, ctx| async move {
|
||||
let email = "test@loco.com";
|
||||
let register_payload = serde_json::json!({
|
||||
"name": "loco",
|
||||
"email": email,
|
||||
"password": "12341234"
|
||||
});
|
||||
|
||||
//Creating a new user
|
||||
_ = request
|
||||
.post("/api/auth/register")
|
||||
.json(®ister_payload)
|
||||
.await;
|
||||
|
||||
let user = users::Model::find_by_email(&ctx.db, email).await.unwrap();
|
||||
let verify_payload = serde_json::json!({
|
||||
"token": user.email_verification_token,
|
||||
});
|
||||
request.post("/api/auth/verify").json(&verify_payload).await;
|
||||
|
||||
//verify user request
|
||||
let response = request
|
||||
.post("/api/auth/login")
|
||||
.json(&serde_json::json!({
|
||||
"email": email,
|
||||
"password": password
|
||||
}))
|
||||
.await;
|
||||
|
||||
// Make sure email_verified_at is set
|
||||
assert!(users::Model::find_by_email(&ctx.db, email)
|
||||
.await
|
||||
.unwrap()
|
||||
.email_verified_at
|
||||
.is_some());
|
||||
|
||||
with_settings!({
|
||||
filters => testing::cleanup_user_model()
|
||||
}, {
|
||||
assert_debug_snapshot!(test_name, (response.status_code(), response.text()));
|
||||
});
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn can_login_without_verify() {
|
||||
configure_insta!();
|
||||
|
||||
testing::request::<App, _, _>(|request, _ctx| async move {
|
||||
let email = "test@loco.com";
|
||||
let password = "12341234";
|
||||
let register_payload = serde_json::json!({
|
||||
"name": "loco",
|
||||
"email": email,
|
||||
"password": password
|
||||
});
|
||||
|
||||
//Creating a new user
|
||||
_ = request
|
||||
.post("/api/auth/register")
|
||||
.json(®ister_payload)
|
||||
.await;
|
||||
|
||||
//verify user request
|
||||
let response = request
|
||||
.post("/api/auth/login")
|
||||
.json(&serde_json::json!({
|
||||
"email": email,
|
||||
"password": password
|
||||
}))
|
||||
.await;
|
||||
|
||||
with_settings!({
|
||||
filters => testing::cleanup_user_model()
|
||||
}, {
|
||||
assert_debug_snapshot!((response.status_code(), response.text()));
|
||||
});
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn can_reset_password() {
|
||||
configure_insta!();
|
||||
|
||||
testing::request::<App, _, _>(|request, ctx| async move {
|
||||
let login_data = prepare_data::init_user_login(&request, &ctx).await;
|
||||
|
||||
let forgot_payload = serde_json::json!({
|
||||
"email": login_data.user.email,
|
||||
});
|
||||
_ = request.post("/api/auth/forgot").json(&forgot_payload).await;
|
||||
|
||||
let user = users::Model::find_by_email(&ctx.db, &login_data.user.email)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(user.reset_token.is_some());
|
||||
assert!(user.reset_sent_at.is_some());
|
||||
|
||||
let new_password = "new-password";
|
||||
let reset_payload = serde_json::json!({
|
||||
"token": user.reset_token,
|
||||
"password": new_password,
|
||||
});
|
||||
|
||||
let reset_response = request.post("/api/auth/reset").json(&reset_payload).await;
|
||||
|
||||
let user = users::Model::find_by_email(&ctx.db, &user.email)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(user.reset_token.is_none());
|
||||
assert!(user.reset_sent_at.is_none());
|
||||
|
||||
assert_debug_snapshot!((reset_response.status_code(), reset_response.text()));
|
||||
|
||||
let response = request
|
||||
.post("/api/auth/login")
|
||||
.json(&serde_json::json!({
|
||||
"email": user.email,
|
||||
"password": new_password
|
||||
}))
|
||||
.await;
|
||||
|
||||
assert_eq!(response.status_code(), 200);
|
||||
|
||||
with_settings!({
|
||||
filters => testing::cleanup_email()
|
||||
}, {
|
||||
assert_debug_snapshot!(ctx.mailer.unwrap().deliveries());
|
||||
});
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn can_get_current_user() {
|
||||
configure_insta!();
|
||||
|
||||
testing::request::<App, _, _>(|request, ctx| async move {
|
||||
let user = prepare_data::init_user_login(&request, &ctx).await;
|
||||
|
||||
let (auth_key, auth_value) = prepare_data::auth_header(&user.token);
|
||||
let response = request
|
||||
.get("/api/auth/current")
|
||||
.add_header(auth_key, auth_value)
|
||||
.await;
|
||||
|
||||
with_settings!({
|
||||
filters => testing::cleanup_user_model()
|
||||
}, {
|
||||
assert_debug_snapshot!((response.status_code(), response.text()));
|
||||
});
|
||||
})
|
||||
.await;
|
||||
}
|
2
tests/requests/mod.rs
Normal file
2
tests/requests/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
mod auth;
|
||||
mod prepare_data;
|
57
tests/requests/prepare_data.rs
Normal file
57
tests/requests/prepare_data.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
use axum::http::{HeaderName, HeaderValue};
|
||||
use loco_rs::{app::AppContext, TestServer};
|
||||
use gabrielkaszewski_rs::{models::users, views::auth::LoginResponse};
|
||||
|
||||
const USER_EMAIL: &str = "test@loco.com";
|
||||
const USER_PASSWORD: &str = "1234";
|
||||
|
||||
pub struct LoggedInUser {
|
||||
pub user: users::Model,
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
pub async fn init_user_login(request: &TestServer, ctx: &AppContext) -> LoggedInUser {
|
||||
let register_payload = serde_json::json!({
|
||||
"name": "loco",
|
||||
"email": USER_EMAIL,
|
||||
"password": USER_PASSWORD
|
||||
});
|
||||
|
||||
//Creating a new user
|
||||
request
|
||||
.post("/api/auth/register")
|
||||
.json(®ister_payload)
|
||||
.await;
|
||||
let user = users::Model::find_by_email(&ctx.db, USER_EMAIL)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let verify_payload = serde_json::json!({
|
||||
"token": user.email_verification_token,
|
||||
});
|
||||
|
||||
request.post("/api/auth/verify").json(&verify_payload).await;
|
||||
|
||||
let response = request
|
||||
.post("/api/auth/login")
|
||||
.json(&serde_json::json!({
|
||||
"email": USER_EMAIL,
|
||||
"password": USER_PASSWORD
|
||||
}))
|
||||
.await;
|
||||
|
||||
let login_response: LoginResponse = serde_json::from_str(&response.text()).unwrap();
|
||||
|
||||
LoggedInUser {
|
||||
user: users::Model::find_by_email(&ctx.db, USER_EMAIL)
|
||||
.await
|
||||
.unwrap(),
|
||||
token: login_response.token,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn auth_header(token: &str) -> (HeaderName, HeaderValue) {
|
||||
let auth_header_value = HeaderValue::from_str(&format!("Bearer {}", &token)).unwrap();
|
||||
|
||||
(HeaderName::from_static("authorization"), auth_header_value)
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tests/requests/user.rs
|
||||
expression: "(response.status_code(), response.text())"
|
||||
---
|
||||
(
|
||||
200,
|
||||
"{\"pid\":\"PID\",\"name\":\"loco\",\"email\":\"test@loco.com\"}",
|
||||
)
|
@@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tests/requests/auth.rs
|
||||
expression: "(response.status_code(), response.text())"
|
||||
---
|
||||
(
|
||||
200,
|
||||
"{\"token\":\"TOKEN\",\"pid\":\"PID\",\"name\":\"loco\",\"is_verified\":false}",
|
||||
)
|
10
tests/requests/snapshots/can_register@auth_request-2.snap
Normal file
10
tests/requests/snapshots/can_register@auth_request-2.snap
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
source: tests/requests/auth.rs
|
||||
expression: ctx.mailer.unwrap().deliveries()
|
||||
---
|
||||
Deliveries {
|
||||
count: 1,
|
||||
messages: [
|
||||
"From: System <system@example.com>\r\nTo: test@loco.com\r\nSubject: Welcome =?utf-8?b?bG9jbwo=?=\r\nMIME-Version: 1.0\r\nDate: DATE\r\nContent-Type: multipart/alternative;\r\n boundary=\"IDENTIFIER\"\r\n\r\n--IDENTIFIER\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Transfer-Encoding: 7bit\r\n\r\nWelcome loco, you can now log in.\r\n Verify your account with the link below:\r\n\r\n http://localhost/verify#RANDOM_ID\r\n\r\n--IDENTIFIER\r\nContent-Type: text/html; charset=utf-8\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n;<html>\r\n\r\n<body>\r\n Dear loco,\r\n Welcome to Loco! You can now log in to your account.\r\n Before you get started, please verify your account by clicking the link b=\r\nelow:\r\n <a href=3D\"http://http://localhost:5150/verify#RANDOM_IDNTIFIER--\r\n",
|
||||
],
|
||||
}
|
25
tests/requests/snapshots/can_register@auth_request.snap
Normal file
25
tests/requests/snapshots/can_register@auth_request.snap
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
source: tests/requests/auth.rs
|
||||
expression: saved_user
|
||||
---
|
||||
Ok(
|
||||
Model {
|
||||
created_at: DATE,
|
||||
updated_at: DATE,
|
||||
id: ID
|
||||
pid: PID,
|
||||
email: "test@loco.com",
|
||||
password: "PASSWORD",
|
||||
api_key: "lo-PID",
|
||||
name: "loco",
|
||||
reset_token: None,
|
||||
reset_sent_at: None,
|
||||
email_verification_token: Some(
|
||||
"PID",
|
||||
),
|
||||
email_verification_sent_at: Some(
|
||||
DATE,
|
||||
),
|
||||
email_verified_at: None,
|
||||
},
|
||||
)
|
@@ -0,0 +1,11 @@
|
||||
---
|
||||
source: tests/requests/auth.rs
|
||||
expression: ctx.mailer.unwrap().deliveries()
|
||||
---
|
||||
Deliveries {
|
||||
count: 2,
|
||||
messages: [
|
||||
"From: System <system@example.com>\r\nTo: test@loco.com\r\nSubject: Welcome =?utf-8?b?bG9jbwo=?=\r\nMIME-Version: 1.0\r\nDate: DATE\r\nContent-Type: multipart/alternative;\r\n boundary=\"IDENTIFIER\"\r\n\r\n--IDENTIFIER\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Transfer-Encoding: 7bit\r\n\r\nWelcome loco, you can now log in.\r\n Verify your account with the link below:\r\n\r\n http://localhost/verify#RANDOM_ID\r\n\r\n--IDENTIFIER\r\nContent-Type: text/html; charset=utf-8\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n;<html>\r\n\r\n<body>\r\n Dear loco,\r\n Welcome to Loco! You can now log in to your account.\r\n Before you get started, please verify your account by clicking the link b=\r\nelow:\r\n <a href=3D\"http://http://localhost:5150/verify#RANDOM_IDNTIFIER--\r\n",
|
||||
"From: System <system@example.com>\r\nTo: test@loco.com\r\nSubject: Your reset password =?utf-8?b?bGluawo=?=\r\nMIME-Version: 1.0\r\nDate: DATE\r\nContent-Type: multipart/alternative;\r\n boundary=\"IDENTIFIER\"\r\n\r\n--IDENTIFIER\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Transfer-Encoding: 7bit\r\n\r\nReset your password with this link:\r\n\r\nhttp://localhost/reset#RANDOM_ID\r\n\r\n--IDENTIFIER\r\nContent-Type: text/html; charset=utf-8\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\n;<html>\r\n\r\n<body>\r\n Hey loco,\r\n Forgot your password? No worries! You can reset it by clicking the link b=\r\nelow:\r\n <a href=3D\"http://http://localhost:5150/reset#RANDOM_IDNTIFIER--\r\n",
|
||||
],
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tests/requests/auth.rs
|
||||
expression: "(reset_response.status_code(), reset_response.text())"
|
||||
---
|
||||
(
|
||||
200,
|
||||
"null",
|
||||
)
|
@@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tests/requests/auth.rs
|
||||
expression: "(response.status_code(), response.text())"
|
||||
---
|
||||
(
|
||||
401,
|
||||
"{\"error\":\"unauthorized\",\"description\":\"You do not have permission to access this resource\"}",
|
||||
)
|
@@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tests/requests/auth.rs
|
||||
expression: "(response.status_code(), response.text())"
|
||||
---
|
||||
(
|
||||
200,
|
||||
"{\"token\":\"TOKEN\",\"pid\":\"PID\",\"name\":\"loco\",\"is_verified\":true}",
|
||||
)
|
Reference in New Issue
Block a user