Comment posting is idempotent + tests
This commit is contained in:
163
tests/api/comments.rs
Normal file
163
tests/api/comments.rs
Normal file
@@ -0,0 +1,163 @@
|
||||
use crate::helpers::{TestApp, fake_post_body};
|
||||
use sqlx::PgPool;
|
||||
|
||||
#[sqlx::test]
|
||||
async fn visitor_can_leave_a_comment(connection_pool: PgPool) {
|
||||
let app = TestApp::spawn(connection_pool).await;
|
||||
app.admin_login().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
|
||||
};
|
||||
let comment_author = "Author";
|
||||
let comment_content = "Content";
|
||||
let comment_body = serde_json::json!({
|
||||
"author": comment_author,
|
||||
"content": comment_content,
|
||||
"idempotency_key": "key",
|
||||
});
|
||||
app.post_comment(&post_id, &comment_body).await;
|
||||
let post = app.get_post_html(post_id).await;
|
||||
assert!(post.contains(comment_author));
|
||||
assert!(post.contains(comment_content));
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn visitor_can_comment_anonymously(connection_pool: PgPool) {
|
||||
let app = TestApp::spawn(connection_pool).await;
|
||||
app.admin_login().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
|
||||
};
|
||||
let comment_content = "Content";
|
||||
let comment_body = serde_json::json!({
|
||||
"content": comment_content,
|
||||
"idempotency_key": "key",
|
||||
});
|
||||
app.post_comment(&post_id, &comment_body).await;
|
||||
let post = app.get_post_html(post_id).await;
|
||||
assert!(post.contains("Anonymous"));
|
||||
assert!(post.contains(comment_content));
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn comment_with_invalid_body_is_rejected(connection_pool: PgPool) {
|
||||
let app = TestApp::spawn(connection_pool).await;
|
||||
app.admin_login().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
|
||||
};
|
||||
let test_cases = [
|
||||
(
|
||||
serde_json::json!({ "idempotency_key": "key" }),
|
||||
"a missing content",
|
||||
),
|
||||
(
|
||||
serde_json::json!({ "idempotency_key": "key", "content": "" }),
|
||||
"an empty content",
|
||||
),
|
||||
];
|
||||
for (invalid_body, message) in test_cases {
|
||||
let response = app.post_comment(&post_id, &invalid_body).await;
|
||||
let html = response.text().await.unwrap();
|
||||
dbg!(&html);
|
||||
assert!(
|
||||
!html.contains("Your comment has been posted"),
|
||||
"The API did not reject the request when the body had {}",
|
||||
message
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn comment_is_deleted_when_post_is_deleted(connection_pool: PgPool) {
|
||||
let app = TestApp::spawn(connection_pool).await;
|
||||
app.admin_login().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
|
||||
};
|
||||
let comment_author = "Author";
|
||||
let comment_content = "Content";
|
||||
let comment_body = serde_json::json!({
|
||||
"author": comment_author,
|
||||
"content": comment_content,
|
||||
"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.delete_post(post_id).await;
|
||||
let record = sqlx::query!("SELECT * FROM comments WHERE comment_id = $1", comment_id)
|
||||
.fetch_optional(&app.connection_pool)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(record.is_none());
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn comment_posting_is_idempotent(connection_pool: PgPool) {
|
||||
let app = TestApp::spawn(connection_pool).await;
|
||||
app.admin_login().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
|
||||
};
|
||||
let comment_body = serde_json::json!({
|
||||
"author": "author",
|
||||
"content": "content",
|
||||
"idempotency_key": "key",
|
||||
});
|
||||
let response = app.post_comment(&post_id, &comment_body).await;
|
||||
assert!(
|
||||
response
|
||||
.text()
|
||||
.await
|
||||
.unwrap()
|
||||
.contains("Your comment has been posted")
|
||||
);
|
||||
let response = app.post_comment(&post_id, &comment_body).await;
|
||||
assert!(
|
||||
response
|
||||
.text()
|
||||
.await
|
||||
.unwrap()
|
||||
.contains("Your comment has been posted")
|
||||
);
|
||||
|
||||
let count = sqlx::query_scalar!("SELECT count(*) FROM comments")
|
||||
.fetch_one(&app.connection_pool)
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap_or(0);
|
||||
|
||||
assert_eq!(count, 1);
|
||||
}
|
||||
@@ -359,6 +359,18 @@ impl TestApp {
|
||||
.expect("Failed to execute request")
|
||||
}
|
||||
|
||||
pub async fn post_comment<Body>(&self, post_id: &Uuid, body: &Body) -> reqwest::Response
|
||||
where
|
||||
Body: serde::Serialize,
|
||||
{
|
||||
self.api_client
|
||||
.post(format!("{}/posts/{post_id}/comments", self.address))
|
||||
.form(body)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request")
|
||||
}
|
||||
|
||||
pub async fn delete_post(&self, post_id: Uuid) {
|
||||
self.api_client
|
||||
.delete(format!("{}/admin/posts/{}", self.address, post_id))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
mod admin_dashboard;
|
||||
mod change_password;
|
||||
mod comments;
|
||||
mod health_check;
|
||||
mod helpers;
|
||||
mod login;
|
||||
|
||||
Reference in New Issue
Block a user