528 lines
17 KiB
Rust
528 lines
17 KiB
Rust
use crate::helpers::{TestApp, fake_newsletter_body, fake_post_body, when_sending_an_email};
|
|
use sqlx::PgPool;
|
|
use wiremock::ResponseTemplate;
|
|
use zero2prod::authentication::Role;
|
|
|
|
#[sqlx::test]
|
|
async fn admin_can_create_user(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, false).await;
|
|
|
|
let record = sqlx::query!("SELECT user_id FROM users WHERE username = $1", username)
|
|
.fetch_optional(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
assert!(record.is_some());
|
|
|
|
let html = app.get_admin_dashboard_html().await;
|
|
assert!(html.contains(username));
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn admin_can_create_admin_user(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, true).await;
|
|
|
|
let record = sqlx::query!(
|
|
r#"
|
|
SELECT role as "role: Role"
|
|
FROM users WHERE username = $1
|
|
"#,
|
|
username
|
|
)
|
|
.fetch_one(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
matches!(record.role, Role::Admin);
|
|
|
|
app.logout().await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
|
|
let html = app.get_admin_dashboard_html().await;
|
|
assert!(html.contains("Administration"));
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn admin_users_can_create_posts(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, true).await;
|
|
app.logout().await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
app.create_confirmed_subscriber().await;
|
|
when_sending_an_email()
|
|
.respond_with(ResponseTemplate::new(200))
|
|
.expect(1)
|
|
.mount(&app.email_server)
|
|
.await;
|
|
app.post_create_post(&fake_post_body()).await;
|
|
app.dispatch_all_pending_emails().await;
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn admin_users_can_send_emails(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, true).await;
|
|
app.logout().await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
app.create_confirmed_subscriber().await;
|
|
when_sending_an_email()
|
|
.respond_with(ResponseTemplate::new(200))
|
|
.expect(1)
|
|
.mount(&app.email_server)
|
|
.await;
|
|
app.post_newsletters(&fake_newsletter_body()).await;
|
|
app.dispatch_all_pending_emails().await;
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn admin_users_can_create_users(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, true).await;
|
|
app.logout().await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
|
|
let username = "other_user";
|
|
app.create_user(username, password, true).await;
|
|
let html = app.get_admin_dashboard_html().await;
|
|
assert!(html.contains(username));
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn admin_users_can_delete_contents(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, true).await;
|
|
app.logout().await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
|
|
app.create_confirmed_subscriber().await;
|
|
let (subscriber_id, email) = {
|
|
let record = sqlx::query!("SELECT id, email FROM subscriptions")
|
|
.fetch_one(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
(record.id, record.email)
|
|
};
|
|
let response = app.delete_subscriber(subscriber_id).await;
|
|
let text = response.text().await.unwrap();
|
|
assert!(text.contains(&email));
|
|
assert!(text.contains("has been deleted"));
|
|
|
|
app.create_user("other_user", password, true).await;
|
|
let user_id = {
|
|
let record = sqlx::query!("SELECT user_id FROM users")
|
|
.fetch_one(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
record.user_id
|
|
};
|
|
let response = app.delete_user(user_id).await;
|
|
let text = response.text().await.unwrap();
|
|
assert!(text.contains("The user has been deleted"));
|
|
|
|
app.post_create_post(&fake_post_body()).await;
|
|
let post_id = {
|
|
let record = sqlx::query!("SELECT post_id FROM posts")
|
|
.fetch_one(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
record.post_id
|
|
};
|
|
|
|
let comment_body = serde_json::json!({
|
|
"author": "author",
|
|
"content": "comment",
|
|
"idempotency_key": "key",
|
|
});
|
|
app.post_comment(&post_id, &comment_body).await;
|
|
let comment_id = {
|
|
let record = sqlx::query!("SELECT comment_id FROM comments")
|
|
.fetch_one(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
record.comment_id
|
|
};
|
|
let response = app.delete_comment(comment_id).await;
|
|
assert!(
|
|
response
|
|
.text()
|
|
.await
|
|
.unwrap()
|
|
.contains("The comment has been deleted")
|
|
);
|
|
|
|
let response = app.delete_post(post_id).await;
|
|
let text = response.text().await.unwrap();
|
|
assert!(text.contains("The post has been deleted"));
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn admin_functions_are_hidden_for_non_admin_users(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, false).await;
|
|
let record = sqlx::query!(
|
|
r#"
|
|
SELECT role as "role: Role"
|
|
FROM users WHERE username = $1
|
|
"#,
|
|
username
|
|
)
|
|
.fetch_one(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
matches!(record.role, Role::Writer);
|
|
app.logout().await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
let response = app.post_login(&login_body).await;
|
|
assert!(!response.text().await.unwrap().contains("Administration"));
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn writers_can_publish_posts_and_send_emails(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, false).await;
|
|
app.logout().await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
|
|
app.create_confirmed_subscriber().await;
|
|
when_sending_an_email()
|
|
.respond_with(ResponseTemplate::new(200))
|
|
.expect(2)
|
|
.mount(&app.email_server)
|
|
.await;
|
|
app.post_create_post(&fake_post_body()).await;
|
|
app.post_newsletters(&fake_newsletter_body()).await;
|
|
app.dispatch_all_pending_emails().await;
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn writers_cannot_perform_admin_functions(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, false).await;
|
|
app.post_create_post(&fake_post_body()).await;
|
|
let post_id = {
|
|
let record = sqlx::query!("SELECT post_id FROM posts")
|
|
.fetch_one(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
record.post_id
|
|
};
|
|
app.create_confirmed_subscriber().await;
|
|
let subscriber_id = {
|
|
let record = sqlx::query!("SELECT id FROM subscriptions")
|
|
.fetch_one(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
record.id
|
|
};
|
|
let comment_body = serde_json::json!({
|
|
"author": "author",
|
|
"content": "comment",
|
|
"idempotency_key": "key",
|
|
});
|
|
app.post_comment(&post_id, &comment_body).await;
|
|
let comment_id = {
|
|
let record = sqlx::query!("SELECT comment_id FROM comments")
|
|
.fetch_one(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
record.comment_id
|
|
};
|
|
|
|
app.logout().await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
|
|
let response = app.delete_subscriber(subscriber_id).await;
|
|
let html = response.text().await.unwrap();
|
|
assert!(html.contains("requires administrator privileges"));
|
|
let record = sqlx::query!("SELECT id FROM subscriptions")
|
|
.fetch_optional(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
assert!(record.is_some());
|
|
|
|
let response = app.delete_comment(comment_id).await;
|
|
let html = response.text().await.unwrap();
|
|
assert!(html.contains("requires administrator privileges"));
|
|
let record = sqlx::query!("SELECT comment_id FROM comments")
|
|
.fetch_optional(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
assert!(record.is_some());
|
|
|
|
let response = app.delete_post(post_id).await;
|
|
let html = response.text().await.unwrap();
|
|
assert!(html.contains("requires administrator privileges"));
|
|
let record = sqlx::query!("SELECT post_id FROM posts")
|
|
.fetch_optional(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
assert!(record.is_some());
|
|
|
|
let user_id = {
|
|
let record = sqlx::query!("SELECT user_id FROM users")
|
|
.fetch_one(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
record.user_id
|
|
};
|
|
let response = app.delete_user(user_id).await;
|
|
let html = response.text().await.unwrap();
|
|
assert!(html.contains("requires administrator privileges"));
|
|
|
|
let record = sqlx::query_scalar!("SELECT username FROM users WHERE user_id = $1", user_id)
|
|
.fetch_optional(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
assert!(record.is_some());
|
|
|
|
let username = "friend";
|
|
let password = "123456789abc";
|
|
let response = app.create_user(username, password, false).await;
|
|
let html = response.text().await.unwrap();
|
|
assert!(html.contains("requires administrator privileges"));
|
|
let record = sqlx::query!("SELECT user_id FROM users WHERE username = $1", username)
|
|
.fetch_optional(&app.connection_pool)
|
|
.await
|
|
.unwrap();
|
|
assert!(record.is_none());
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn user_can_change_his_display_name(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, false).await;
|
|
let user_id = app.get_user_id(username).await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
let full_name = "Alphonse Paix";
|
|
let edit_body = serde_json::json!( {
|
|
"user_id": user_id,
|
|
"username": username,
|
|
"full_name": full_name,
|
|
"bio": "",
|
|
});
|
|
let html = app.get_profile_html(username).await;
|
|
assert!(!html.contains(full_name));
|
|
let response = app.edit_profile(&edit_body).await;
|
|
assert!(dbg!(response.text().await.unwrap()).contains("Your profile has been updated"));
|
|
let html = app.get_profile_html(username).await;
|
|
assert!(html.contains(full_name));
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn user_can_change_his_bio(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, false).await;
|
|
let user_id = app.get_user_id(username).await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
let bio = "This is me";
|
|
let edit_body = serde_json::json!( {
|
|
"user_id": user_id,
|
|
"username": username,
|
|
"full_name": "",
|
|
"bio": bio,
|
|
});
|
|
let html = app.get_profile_html(username).await;
|
|
assert!(!html.contains(bio));
|
|
let response = app.edit_profile(&edit_body).await;
|
|
assert!(dbg!(response.text().await.unwrap()).contains("Your profile has been updated"));
|
|
let html = app.get_profile_html(username).await;
|
|
assert!(html.contains(bio));
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn user_can_change_his_username(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, false).await;
|
|
let user_id = app.get_user_id(username).await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
let new_username = "alphonsepaix";
|
|
let edit_body = serde_json::json!( {
|
|
"user_id": user_id,
|
|
"username": new_username,
|
|
"full_name": "",
|
|
"bio": "",
|
|
});
|
|
let html = app.get_profile_html(username).await;
|
|
assert!(html.contains(username));
|
|
let response = app.edit_profile(&edit_body).await;
|
|
assert!(dbg!(response.text().await.unwrap()).contains("Your profile has been updated"));
|
|
let html = app.get_profile_html(username).await;
|
|
assert!(html.contains("404"));
|
|
let html = app.get_profile_html(new_username).await;
|
|
assert!(html.contains(new_username));
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn user_cannot_change_other_profiles(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, false).await;
|
|
let other_user_id = app.get_user_id("admin").await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
let new_username = "alphonsepaix";
|
|
let edit_body = serde_json::json!( {
|
|
"user_id": other_user_id,
|
|
"username": new_username,
|
|
"full_name": "",
|
|
"bio": "",
|
|
});
|
|
let response = app.edit_profile(&edit_body).await;
|
|
assert!(
|
|
response
|
|
.text()
|
|
.await
|
|
.unwrap()
|
|
.contains("You are not authorized")
|
|
);
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn user_cannot_take_an_existing_username(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, false).await;
|
|
let user_id = app.get_user_id(username).await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
let edit_body = serde_json::json!( {
|
|
"user_id": user_id,
|
|
"username": "admin",
|
|
"full_name": "",
|
|
"bio": "",
|
|
});
|
|
let response = app.edit_profile(&edit_body).await;
|
|
assert!(
|
|
response
|
|
.text()
|
|
.await
|
|
.unwrap()
|
|
.contains("This username is already taken")
|
|
);
|
|
let html = app.get_profile_html(username).await;
|
|
assert!(html.contains(username));
|
|
}
|
|
|
|
#[sqlx::test]
|
|
async fn invalid_fields_are_rejected(connection_pool: PgPool) {
|
|
let app = TestApp::spawn(connection_pool).await;
|
|
app.admin_login().await;
|
|
let username = "alphonse";
|
|
let password = "123456789abc";
|
|
app.create_user(username, password, false).await;
|
|
let user_id = app.get_user_id(username).await;
|
|
let login_body = serde_json::json!({
|
|
"username": username,
|
|
"password": password
|
|
});
|
|
app.post_login(&login_body).await;
|
|
|
|
let test_cases = [(
|
|
serde_json::json!({
|
|
"user_id": user_id,
|
|
"username": "ab",
|
|
"full_name": "",
|
|
"bio": "",
|
|
}),
|
|
"Username must be at least 3 characters",
|
|
"the username was too short",
|
|
)];
|
|
for (invalid_body, expected_error_message, explaination) in test_cases {
|
|
let html = app.edit_profile(&invalid_body).await;
|
|
assert!(
|
|
html.text().await.unwrap().contains(expected_error_message),
|
|
"The API did not reject the changes when {}",
|
|
explaination
|
|
);
|
|
}
|
|
}
|