From 83a463ee41a66e5c859106a88c466423d107f118 Mon Sep 17 00:00:00 2001 From: ittokun <73953416+ittokun@users.noreply.github.com> Date: Wed, 17 May 2023 01:20:43 +0900 Subject: [PATCH] feat: :sparkles: Add post tests Issue: #44 --- src/db/crud/mutation.rs | 2 +- tests/post_tests.rs | 176 +++++++++++++++++++++++++++++++++++++++ tests/utils/json_data.rs | 67 +++++++++++++++ tests/utils/setup.rs | 18 +++- 4 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 tests/post_tests.rs diff --git a/src/db/crud/mutation.rs b/src/db/crud/mutation.rs index 1decef3..7fe607c 100644 --- a/src/db/crud/mutation.rs +++ b/src/db/crud/mutation.rs @@ -28,7 +28,7 @@ impl Mutation { let post: post::ActiveModel = Post::find_by_id(id) .one(db) .await? - .ok_or(DbErr::Custom("Cannot Find Post".to_owned())) + .ok_or(DbErr::RecordNotFound("Cannot Find Post".to_owned())) .map(Into::into)?; post::ActiveModel { diff --git a/tests/post_tests.rs b/tests/post_tests.rs new file mode 100644 index 0000000..a35cb97 --- /dev/null +++ b/tests/post_tests.rs @@ -0,0 +1,176 @@ +use actix_web::test::{init_service, read_body_json, TestRequest}; +use actix_web::App; +use serde_json::Value; + +use api_ittoku_tech::db::post; +use api_ittoku_tech::routes; + +mod utils; + +use utils::prelude::*; + +#[actix_web::test] +async fn post_list() { + let app = init_service( + App::new() + .app_data(app_state().await) + .configure(routes::init), + ) + .await; + let resp = TestRequest::get().uri("/posts").send_request(&app).await; + assert!(resp.status().is_success()); +} + +#[actix_web::test] +async fn post_create() { + let app = init_service( + App::new() + .app_data(app_state().await) + .configure(routes::init), + ) + .await; + // Empty post data + let post_data = NEW_POST_EMPTY.to_owned(); + let resp = TestRequest::post() + .uri("/posts") + .set_json(post_data) + .send_request(&app) + .await; + assert!(resp.status().is_client_error()); + let resp: Value = read_body_json(resp).await; + let resp_empty = RESP_POST_EMPTY.to_owned(); + assert_eq!(resp, resp_empty); + // Too long post data + let post_data = NEW_POST_TOO_LONG.to_owned(); + let resp = TestRequest::post() + .uri("/posts") + .set_json(post_data) + .send_request(&app) + .await; + assert!(resp.status().is_client_error()); + let resp: Value = read_body_json(resp).await; + let resp_too_long = RESP_POST_TOO_LONG.to_owned(); + assert_eq!(resp, resp_too_long); + // success to create post + let post_data = NEW_POST.to_owned(); + let resp = TestRequest::post() + .uri("/posts") + .set_json(&post_data) + .send_request(&app) + .await; + assert!(resp.status().is_success()); + let resp: Value = read_body_json(resp).await; + assert_eq!(resp["title"], post_data["title"]); + delete_post(resp["id"].as_i64().unwrap() as i32).await; +} + +#[actix_web::test] +async fn post_detail() { + let app = init_service( + App::new() + .app_data(app_state().await) + .configure(routes::init), + ) + .await; + let post = create_post().await; + // post not found + let resp = TestRequest::get() + .uri("/posts/hoge") + .send_request(&app) + .await; + assert!(resp.status().is_client_error()); + let resp_not_found = RESP_NOTFOUND.to_owned(); + let resp: Value = read_body_json(resp).await; + assert_eq!(resp, resp_not_found); + // success to get post + let resp = TestRequest::get() + .uri(&format!("/posts/{}", post.id)) + .send_request(&app) + .await; + assert!(resp.status().is_success()); + let resp: post::Model = read_body_json(resp).await; + assert_eq!(resp, post); + delete_post(resp.id).await; +} + +#[actix_web::test] +async fn post_update() { + let app = init_service( + App::new() + .app_data(app_state().await) + .configure(routes::init), + ) + .await; + let post = create_post().await; + // Empty post data + let post_data = NEW_POST_EMPTY.to_owned(); + let resp = TestRequest::patch() + .uri(&format!("/posts/{}", post.id)) + .set_json(post_data) + .send_request(&app) + .await; + assert!(resp.status().is_client_error()); + let resp: Value = read_body_json(resp).await; + let resp_empty = RESP_POST_EMPTY.to_owned(); + assert_eq!(resp, resp_empty); + // Too long post data + let post_data = NEW_POST_TOO_LONG.to_owned(); + let resp = TestRequest::patch() + .uri(&format!("/posts/{}", post.id)) + .set_json(post_data) + .send_request(&app) + .await; + assert!(resp.status().is_client_error()); + let resp: Value = read_body_json(resp).await; + let resp_too_long = RESP_POST_TOO_LONG.to_owned(); + assert_eq!(resp, resp_too_long); + // post not found + let post_data = NEW_POST_UPDATED.to_owned(); + let resp = TestRequest::patch() + .uri("/posts/hoge") + .set_json(&post_data) + .send_request(&app) + .await; + assert!(resp.status().is_client_error()); + let resp_not_found = RESP_NOTFOUND.to_owned(); + let resp: Value = read_body_json(resp).await; + assert_eq!(resp, resp_not_found); + // success to update post + let resp = TestRequest::patch() + .uri(&format!("/posts/{}", post.id)) + .set_json(&post_data) + .send_request(&app) + .await; + assert!(resp.status().is_success()); + let resp: Value = read_body_json(resp).await; + assert_eq!(resp["title"], post_data["title"]); + delete_post(resp["id"].as_i64().unwrap() as i32).await; +} + +#[actix_web::test] +async fn post_delete() { + let app = init_service( + App::new() + .app_data(app_state().await) + .configure(routes::init), + ) + .await; + let post = create_post().await; + // post not found + let resp = TestRequest::delete() + .uri("/posts/hoge") + .send_request(&app) + .await; + assert!(resp.status().is_client_error()); + let resp_not_found = RESP_NOTFOUND.to_owned(); + let resp: Value = read_body_json(resp).await; + assert_eq!(resp, resp_not_found); + // success to delete post + let resp = TestRequest::delete() + .uri(&format!("/posts/{}", post.id)) + .send_request(&app) + .await; + assert!(resp.status().is_success()); + let resp: post::Model = read_body_json(resp).await; + assert_eq!(resp, post); +} diff --git a/tests/utils/json_data.rs b/tests/utils/json_data.rs index ecacffe..3ced81e 100644 --- a/tests/utils/json_data.rs +++ b/tests/utils/json_data.rs @@ -1,6 +1,7 @@ use once_cell::sync::Lazy; use serde_json::{json, Value}; +#[allow(dead_code)] pub static RESP_ROOT: Lazy = Lazy::new(|| { json!({ "post_detail_url": "http://0.0.0.0:8080/posts/{id}", @@ -8,8 +9,74 @@ pub static RESP_ROOT: Lazy = Lazy::new(|| { }) }); +#[allow(dead_code)] pub static RESP_NOTFOUND: Lazy = Lazy::new(|| json!({"status": 404, "message": "Not Found".to_string()})); +#[allow(dead_code)] pub static RESP_INVALID_JSON: Lazy = Lazy::new(|| json!({"status": 400, "message": "Invalid JSON Data".to_string()})); + +#[allow(dead_code)] +pub static NEW_POST: Lazy = Lazy::new(|| { + json!({ + "title": "test title", + "text": "test text", + }) +}); + +#[allow(dead_code)] +pub static NEW_POST_UPDATED: Lazy = Lazy::new(|| { + json!({ + "title": "test title updated", + "text": "test text updated", + }) +}); + +#[allow(dead_code)] +pub static NEW_POST_EMPTY: Lazy = Lazy::new(|| { + json!({ + "title": "", + "text": "", + }) +}); + +#[allow(dead_code)] +pub static NEW_POST_TOO_LONG: Lazy = Lazy::new(|| { + json!({ + "title": "x".repeat(257), + "text": "x".repeat(65537), + }) +}); + +#[allow(dead_code)] +pub static RESP_POST_EMPTY: Lazy = Lazy::new(|| { + json!({ + "errors": [ + { + "status": 422, + "message": "title cannot be empty", + }, + { + "status": 422, + "message": "text cannot be empty", + }, + ] + }) +}); + +#[allow(dead_code)] +pub static RESP_POST_TOO_LONG: Lazy = Lazy::new(|| { + json!({ + "errors": [ + { + "status": 422, + "message": "title cannot be longer than 256 characters", + }, + { + "status": 422, + "message": "text cannot be longer than 65536 characters", + }, + ] + }) +}); diff --git a/tests/utils/setup.rs b/tests/utils/setup.rs index ec7b487..13353d0 100644 --- a/tests/utils/setup.rs +++ b/tests/utils/setup.rs @@ -1,4 +1,4 @@ -use api_ittoku_tech::db::database_connection; +use api_ittoku_tech::db::{database_connection, post, Mutation}; use api_ittoku_tech::AppState; use actix_web::web; @@ -7,3 +7,19 @@ pub async fn app_state() -> web::Data { let conn = database_connection().await.unwrap(); web::Data::new(AppState { conn }) } + +#[allow(dead_code)] +pub async fn create_post() -> post::Model { + let conn = database_connection().await.unwrap(); + let post_data = post::NewModel { + title: "test title".to_owned(), + text: "test text".to_owned(), + }; + Mutation::create_post(&conn, post_data).await.unwrap() +} + +#[allow(dead_code)] +pub async fn delete_post(id: i32) -> post::Model { + let conn = database_connection().await.unwrap(); + Mutation::delete_post_by_id(&conn, id).await.unwrap() +}