diff --git a/imphnen-iam/src/v1/roles/roles_repository.rs b/imphnen-iam/src/v1/roles/roles_repository.rs index 90743c3..c5eb645 100644 --- a/imphnen-iam/src/v1/roles/roles_repository.rs +++ b/imphnen-iam/src/v1/roles/roles_repository.rs @@ -116,7 +116,7 @@ impl<'a> RolesRepository<'a> { pub async fn query_create_role( &self, payload: RolesRequestCreateDto, - ) -> Result { + ) -> Result { let now = Instant::now(); let db = &self.state.surrealdb_ws; let role_id = Uuid::new_v4().to_string(); @@ -134,7 +134,7 @@ impl<'a> RolesRepository<'a> { updated_at: Some(crate::get_iso_date()), }; let _: Option = db - .create((&ResourceEnum::Roles.to_string(), role_id)) + .create((&ResourceEnum::Roles.to_string(), role_id.clone())) .content(role) .await?; let elapsed = now.elapsed(); @@ -143,7 +143,8 @@ impl<'a> RolesRepository<'a> { { println!("Query 'query_create_role' took: {elapsed:.2?}"); } - Ok("Role with permissions created successfully".into()) + // After successful creation, fetch the created role + self.query_role_by_id(role_id).await } #[instrument(skip(self, id, data), err)] diff --git a/imphnen-iam/src/v1/roles/roles_service.rs b/imphnen-iam/src/v1/roles/roles_service.rs index b21df84..d998e1b 100644 --- a/imphnen-iam/src/v1/roles/roles_service.rs +++ b/imphnen-iam/src/v1/roles/roles_service.rs @@ -3,6 +3,7 @@ use crate::{ AppState, MetaRequestDto, ResponseListSuccessDto, ResponseSuccessDto, common_response, success_list_response, success_response, validate_request, }; +use imphnen_utils::success_created_response; use axum::{http::StatusCode, response::Response}; pub struct RolesService; @@ -48,7 +49,7 @@ impl RolesService { } } match repo.query_create_role(payload).await { - Ok(msg) => common_response(StatusCode::CREATED, &msg), + Ok(created_role) => success_created_response(ResponseSuccessDto { data: created_role }), Err(e) => common_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()), } } diff --git a/imphnen-iam/src/v1/users/users_schema.rs b/imphnen-iam/src/v1/users/users_schema.rs index da4308c..f58dbac 100644 --- a/imphnen-iam/src/v1/users/users_schema.rs +++ b/imphnen-iam/src/v1/users/users_schema.rs @@ -247,7 +247,7 @@ impl UsersSchema { password, phone_number: user.phone_number, phone_for_verification: None, - is_active: false, + is_active: user.is_active, mentor_id: None, // Regular users should not have a mentor_id by default gender: None, birthdate: None, diff --git a/imphnen-iam/src/v1/users/users_service.rs b/imphnen-iam/src/v1/users/users_service.rs index 586df76..ebdc85b 100644 --- a/imphnen-iam/src/v1/users/users_service.rs +++ b/imphnen-iam/src/v1/users/users_service.rs @@ -5,11 +5,10 @@ use super::{ use imphnen_entities::UsersDetailQueryDto; use crate::{ AppState, MetaRequestDto, ResponseListSuccessDto, UsersRepository, UsersSchema, -}; -use crate::{ ResponseSuccessDto, common_response, success_list_response, success_response, validate_request, }; +use imphnen_utils::success_created_response; use axum::{http::StatusCode, response::Response, extract::Multipart}; use imphnen_libs::{ResourceEnum, hash_password, verify_password, MinioConfig, FileType, decode_base64_file, extract_content_type_from_data_url, create_minio_service_from_config}; use imphnen_utils::make_thing_from_enum; @@ -130,8 +129,16 @@ pub trait UsersServiceTrait: Send + Sync + 'static { { return common_response(StatusCode::BAD_REQUEST, "User already exists"); } - match repo.query_create_user(UsersSchema::create(new_user)).await { - Ok(msg) => common_response(StatusCode::CREATED, &msg), + match repo.query_create_user(UsersSchema::create(new_user.clone())).await { + Ok(_msg) => { + // After successful creation, fetch the created user + match repo.query_user_by_email(new_user.email).await { + Ok(created_user) => success_created_response(ResponseSuccessDto { + data: UserDto::from(&created_user), + }), + Err(e) => common_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()), + } + } Err(err) => { common_response(StatusCode::INTERNAL_SERVER_ERROR, &err.to_string()) } diff --git a/tests/src/dimentorin/mentors/mentors_service_test.rs b/tests/src/dimentorin/mentors/mentors_service_test.rs index 9c15205..6f33411 100644 --- a/tests/src/dimentorin/mentors/mentors_service_test.rs +++ b/tests/src/dimentorin/mentors/mentors_service_test.rs @@ -6,7 +6,8 @@ mod tests { mentors_service::MentorsService, mentors_dto::{ MentorUserRegisterRequestDto, MentorUpdateRequestDto, MentorVerifyRequestDto, - IdentityAndVerification, ProfessionalProfile, MentoringLogistics + IdentityAndVerification, ProfessionalProfile, MentoringLogistics, + MentorRegisterResponseDto, MentorListResponseDto, MentorDetailResponseDto }, MentorsRepository }; @@ -67,6 +68,13 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON response + let mentor_response: MentorRegisterResponseDto = response.json().await.unwrap(); + assert!(!mentor_response.id.is_empty(), "Response ID should not be empty"); + assert_eq!(mentor_response.status, "pending", "Expected mentor status to be 'pending'"); + assert!(!mentor_response.created_at.is_empty(), "Created at should not be empty"); + assert!(!mentor_response.updated_at.is_empty(), "Updated at should not be empty"); // Verify mentor was created in database let mentor = mentor_repo.query_mentor_by_email(email.clone(), false).await; @@ -143,6 +151,16 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON response + let mentor_list: Vec = response.json().await.unwrap(); + assert!(!mentor_list.is_empty(), "Mentor list should not be empty"); + + let mentor = &mentor_list[0]; + assert!(!mentor.id.is_empty(), "Mentor ID should not be empty"); + assert_eq!(mentor.status, "pending", "Expected mentor status to be 'pending'"); + assert!(!mentor.created_at.is_empty(), "Created at should not be empty"); + assert!(!mentor.updated_at.is_empty(), "Updated at should not be empty"); // Clean up let user = user_repo.query_user_by_email(email.clone()).await.unwrap(); @@ -205,6 +223,15 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON response + let mentor_response: MentorDetailResponseDto = response.json().await.unwrap(); + assert!(!mentor_response.id.is_empty(), "Mentor ID should not be empty"); + assert!(!mentor_response.user_id.is_empty(), "User ID should not be empty"); + assert_eq!(mentor_response.status, "pending", "Expected mentor status to be 'pending'"); + assert!(!mentor_response.created_at.is_empty(), "Created at should not be empty"); + assert!(!mentor_response.updated_at.is_empty(), "Updated at should not be empty"); + assert_eq!(mentor_response.current_role, "Senior Engineer", "Expected current role to be 'Senior Engineer'"); // Clean up let user = user_repo.query_user_by_email(email.clone()).await.unwrap(); @@ -291,6 +318,14 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON response + let mentor_response: MentorDetailResponseDto = response.json().await.unwrap(); + assert!(!mentor_response.id.is_empty(), "Mentor ID should not be empty"); + assert!(!mentor_response.user_id.is_empty(), "User ID should not be empty"); + assert_eq!(mentor_response.status, "pending", "Expected mentor status to be 'pending'"); + assert_eq!(mentor_response.current_role, "Lead Engineer", "Expected current role to be 'Lead Engineer' after update"); + assert_eq!(mentor_response.legal_name, Some("Updated Legal Name".to_string()), "Expected legal name to be updated"); // Verify mentor was updated let updated_mentor = mentor_repo.query_mentor_by_id(&mentor.id, false).await.unwrap(); @@ -423,6 +458,11 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON response + let mentor_response: MentorDetailResponseDto = response.json().await.unwrap(); + assert!(!mentor_response.id.is_empty(), "Mentor ID should not be empty"); + assert_eq!(mentor_response.status, "verified", "Expected mentor status to be 'verified'"); // Verify mentor was verified let updated_mentor = mentor_repo.query_mentor_by_id(&mentor.id, false).await.unwrap(); @@ -441,6 +481,10 @@ mod tests { // Should return forbidden (mentor profile not found) assert_eq!(response.status(), StatusCode::FORBIDDEN); + + // Verify error response structure + let error_response: serde_json::Value = response.json().await.unwrap(); + assert!(error_response.is_object(), "Error response should be an object"); } #[tokio::test] @@ -457,6 +501,10 @@ mod tests { // Should return forbidden assert_eq!(response.status(), StatusCode::FORBIDDEN); + + // Verify error response structure + let error_response: serde_json::Value = response.json().await.unwrap(); + assert!(error_response.is_object(), "Error response should be an object"); } #[tokio::test] @@ -479,6 +527,14 @@ mod tests { // Should return not found assert_eq!(response.status(), StatusCode::NOT_FOUND); + + // Verify error response structure + let error_response: serde_json::Value = response.json().await.unwrap(); + assert!(error_response.is_object(), "Error response should be an object"); + + // Verify error response structure + let error_response: serde_json::Value = response.json().await.unwrap(); + assert!(error_response.is_object(), "Error response should be an object"); } #[tokio::test] @@ -741,6 +797,11 @@ mod tests { let response = MentorsService::register_mentor(&app_state, mentor_dto).await; assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON response + let mentor_response: MentorRegisterResponseDto = response.json().await.unwrap(); + assert!(!mentor_response.id.is_empty(), "Response ID should not be empty"); + assert_eq!(mentor_response.status, "pending", "Expected mentor status to be 'pending'"); // Clean up let user = user_repo.query_user_by_email(email.clone()).await.unwrap(); @@ -792,6 +853,13 @@ mod tests { let response = MentorsService::register_mentor(&app_state, mentor_dto).await; assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON response + let mentor_response: MentorDetailResponseDto = response.json().await.unwrap(); + assert!(!mentor_response.id.is_empty(), "Mentor ID should not be empty"); + assert!(!mentor_response.user_id.is_empty(), "User ID should not be empty"); + assert_eq!(mentor_response.legal_name, Some("Updated Name".to_string()), "Expected legal name to be updated"); + assert_eq!(mentor_response.current_role, "Lead Engineer".to_string(), "Expected current role to be updated"); // Clean up let user = user_repo.query_user_by_email(email.clone()).await.unwrap(); diff --git a/tests/src/gacha/gacha_claims_service_test.rs b/tests/src/gacha/gacha_claims_service_test.rs index adc14d6..d0d24bd 100644 --- a/tests/src/gacha/gacha_claims_service_test.rs +++ b/tests/src/gacha/gacha_claims_service_test.rs @@ -2,13 +2,14 @@ mod tests { use crate::{generate_unique_email, get_role_id, setup_all_test_environment, UsersRepository}; use axum::http::StatusCode; - use imphnen_entities::AppState; + use imphnen_entities::{AppState, ResponseSuccessDto}; use imphnen_gacha::v1::gacha_claims::gacha_claims_service::GachaClaimService; - use imphnen_gacha::v1::gacha_claims::gacha_claims_dto::GachaClaimRequestDto; + use imphnen_gacha::v1::gacha_claims::gacha_claims_dto::{GachaClaimItemDto, GachaClaimRequestDto}; use imphnen_gacha::v1::gacha_items::gacha_items_service::GachaItemService; use imphnen_gacha::v1::gacha_items::gacha_items_dto::GachaItemRequestDto; use imphnen_gacha::GachaClaimRepository; use imphnen_iam::users_service::UsersService; + use serde_json::json; #[tokio::test] async fn test_get_gacha_claim_by_id_service() { @@ -47,6 +48,10 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::NOT_FOUND); + + // Parse and verify error JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Error message should be a string"); // Clean up let _ = user_repo.query_delete_user(user.id.id.to_raw()).await; @@ -88,6 +93,10 @@ mod tests { // Since item doesn't exist, it should fail assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR); + + // Parse and verify error JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Error message should be a string"); // Clean up let _ = user_repo.query_delete_user(user.id.id.to_raw()).await; @@ -107,6 +116,14 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::BAD_REQUEST); + + // Parse and verify error JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Error message should be a string"); + + // Parse and verify error JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Error message should be a string"); } #[tokio::test] diff --git a/tests/src/gacha/gacha_credits_controller_test.rs b/tests/src/gacha/gacha_credits_controller_test.rs index e4c7d4a..3e7cc68 100644 --- a/tests/src/gacha/gacha_credits_controller_test.rs +++ b/tests/src/gacha/gacha_credits_controller_test.rs @@ -2,11 +2,12 @@ mod tests { use crate::{generate_unique_email, get_role_id, setup_all_test_environment, UsersRepository}; use axum::{http::StatusCode, response::Response}; - use imphnen_entities::{AppState, MetaRequestDto}; + use imphnen_entities::{AppState, MetaRequestDto, ResponseSuccessDto, ResponseListSuccessDto}; use imphnen_gacha::{ gacha_credits_controller::GachaCreditsController, gacha_credits_dto::{GachaCreditsCreateRequestDto, GachaCreditsUpdateRequestDto}, }; + use serde_json::json; use imphnen_iam::users_service::UsersService; use imphnen_utils::{generate_otp, hash_password, make_thing_from_enum, get_iso_date}; use surrealdb::Uuid; @@ -45,6 +46,10 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Success message should be a string"); // Clean up let _ = user_repo.query_delete_user(user.id.id.to_raw()).await; @@ -94,6 +99,10 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON content + let response_body: ResponseListSuccessDto = response.json().await.unwrap(); + assert!(!response_body.data.is_null(), "Response data should not be null"); // Clean up let _ = user_repo.query_delete_user(user.id.id.to_raw()).await; @@ -138,6 +147,10 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON content + let response_body: ResponseSuccessDto = response.json().await.unwrap(); + assert!(!response_body.data.is_null(), "Response data should not be null"); // Clean up let _ = user_repo.query_delete_user(user.id.id.to_raw()).await; @@ -189,6 +202,18 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Success message should be a string"); + + // Parse and verify JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Success message should be a string"); + + // Parse and verify JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Success message should be a string"); // Clean up let _ = user_repo.query_delete_user(user.id.id.to_raw()).await; diff --git a/tests/src/gacha/gacha_items_service_test.rs b/tests/src/gacha/gacha_items_service_test.rs index cc0080e..f02f52d 100644 --- a/tests/src/gacha/gacha_items_service_test.rs +++ b/tests/src/gacha/gacha_items_service_test.rs @@ -2,9 +2,10 @@ mod tests { use crate::setup_all_test_environment; use axum::http::StatusCode; - use imphnen_entities::{AppState, MetaRequestDto}; + use imphnen_entities::{AppState, MetaRequestDto, ResponseSuccessDto, ResponseListSuccessDto}; use imphnen_gacha::v1::gacha_items::gacha_items_service::GachaItemService; use imphnen_gacha::v1::gacha_items::gacha_items_dto::{GachaItemRequestDto, GachaItemUpdateRequestDto}; + use imphnen_gacha::v1::gacha_items::gacha_items_dto::GachaItemDto; use imphnen_gacha::GachaItemRepository; #[tokio::test] @@ -32,6 +33,12 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON content + let response_body: ResponseListSuccessDto> = response.json().await.unwrap(); + assert!(!response_body.data.is_empty(), "Response data should not be empty"); + assert!(response_body.data.iter().any(|item| item.name == "Test Item List"), "Expected item not found in response"); + assert!(response_body.data.iter().all(|item| !item.id.is_empty() && !item.name.is_empty()), "Required fields should not be empty"); // Clean up let items = item_repo.query_gacha_item_list(MetaRequestDto::default()).await.unwrap().data; @@ -58,6 +65,12 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON content + let response_body: ResponseSuccessDto = response.json().await.unwrap(); + assert!(!response_body.data.id.is_empty(), "ID should not be empty"); + assert_eq!(response_body.data.name, "Test Item By ID", "Item name should match"); + assert!(!response_body.data.is_deleted, "Item should not be deleted"); // Clean up let _ = item_repo.query_delete_gacha_item(item.id.id.to_raw()).await; @@ -72,6 +85,10 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::NOT_FOUND); + + // Parse and verify error JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Error message should be a string"); } #[tokio::test] @@ -90,6 +107,10 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::CREATED); + + // Parse and verify JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Success message should be a string"); // Verify item was created let items = item_repo.query_gacha_item_list(MetaRequestDto::default()).await.unwrap().data; @@ -115,6 +136,14 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::BAD_REQUEST); + + // Parse and verify error JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Error message should be a string"); + + // Parse and verify error JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Error message should be a string"); } #[tokio::test] @@ -156,6 +185,12 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); + + // Parse and verify JSON content + let response_body: ResponseSuccessDto = response.json().await.unwrap(); + assert!(!response_body.data.id.is_empty(), "ID should not be empty"); + assert_eq!(response_body.data.name, "Updated Test Item", "Updated item name should match"); + assert_eq!(response_body.data.image_url, "https://example.com/updated.png", "Updated image URL should match"); // Verify item was updated let updated_item = item_repo.query_gacha_item_by_id(item.id.id.to_raw()).await.unwrap(); @@ -179,6 +214,14 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::NOT_FOUND); + + // Parse and verify error JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Error message should be a string"); + + // Parse and verify error JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Error message should be a string"); } #[tokio::test] @@ -204,6 +247,10 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::BAD_REQUEST); + + // Parse and verify error JSON content + let response_body: serde_json::Value = response.json().await.unwrap(); + assert!(response_body["message"].is_string(), "Error message should be a string"); // Clean up let _ = item_repo.query_delete_gacha_item(item.id.id.to_raw()).await; diff --git a/tests/src/iam/auth/auth_controller_test.rs b/tests/src/iam/auth/auth_controller_test.rs index b080fbc..d6c2af7 100644 --- a/tests/src/iam/auth/auth_controller_test.rs +++ b/tests/src/iam/auth/auth_controller_test.rs @@ -67,9 +67,14 @@ mod tests { let login_response: ResponseSuccessDto = crate::common::response_helpers::parse_response(response, 8192).await; let data_val = login_response.data.expect("login should return data"); - // Try to deserialize token structure + + // Parse and verify token data let token_obj: TokenDto = serde_json::from_value(data_val).expect("login data must be TokenDto"); - assert!(!token_obj.access_token.is_empty(), "access_token must be present"); + assert!(!token_obj.access_token.is_empty(), "access_token must be present and non-empty"); + assert!(!token_obj.refresh_token.is_empty(), "refresh_token must be present and non-empty"); + assert!(!token_obj.user.id.is_empty(), "user id must be present and non-empty"); + assert_eq!(token_obj.user.email, email, "user email must match login email"); + assert_eq!(token_obj.user.fullname, "Test User Controller", "user fullname must match registered user"); // Clean up let user = repo.query_user_by_email(email.clone()).await.unwrap(); diff --git a/tests/src/iam/auth/auth_service_test.rs b/tests/src/iam/auth/auth_service_test.rs index c060e09..6c75ecc 100644 --- a/tests/src/iam/auth/auth_service_test.rs +++ b/tests/src/iam/auth/auth_service_test.rs @@ -47,7 +47,11 @@ mod tests { assert_eq!(response.status(), StatusCode::OK); let login_response: ResponseSuccessDto = crate::common::response_helpers::parse_response(response, 8192).await; - assert!(login_response.data.is_some()); + assert!(login_response.data.is_some(), "Login response must contain data"); + + let token_data: TokenDto = serde_json::from_value(login_response.data.clone().unwrap()).expect("Login data must be TokenDto"); + assert!(!token_data.access_token.is_empty(), "Access token must be present"); + assert!(!token_data.refresh_token.is_empty(), "Refresh token must be present"); // Clean up let user = repo.query_user_by_email(email.clone()).await.unwrap(); @@ -103,8 +107,10 @@ mod tests { // Verify user was created in database (should be inactive until OTP verification) let repo = UsersRepository::new(&app_state); let created_user = repo.query_user_by_email(email.clone()).await.unwrap(); - assert_eq!(created_user.email, email); - assert_eq!(created_user.is_active, false); + assert_eq!(created_user.email, email, "Registered user email must match"); + assert_eq!(created_user.fullname, "Test User Service", "Registered user fullname must match"); + assert_eq!(created_user.is_active, false, "Registered user should be inactive until verification"); + assert!(!created_user.id.id.to_raw().is_empty(), "Registered user must have non-empty id"); // Clean up let _ = repo.query_delete_user(created_user.id.id.to_raw()).await; @@ -145,7 +151,8 @@ mod tests { // Verify user was activated in database let updated_user = repo.query_user_by_email(email.clone()).await.unwrap(); - assert_eq!(updated_user.is_active, true); + assert_eq!(updated_user.is_active, true, "User should be activated after verification"); + assert_eq!(updated_user.email, email, "User email should remain unchanged"); // Clean up let _ = repo.query_delete_user(updated_user.id.id.to_raw()).await; diff --git a/tests/src/iam/permissions/permissions_controller_test.rs b/tests/src/iam/permissions/permissions_controller_test.rs index 5a1eb42..5146983 100644 --- a/tests/src/iam/permissions/permissions_controller_test.rs +++ b/tests/src/iam/permissions/permissions_controller_test.rs @@ -29,19 +29,20 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::CREATED); - // Verify response body contains success message - let msg: imphnen_entities::MessageResponseDto = + // Verify response body contains permission data + let created_permission: PermissionsSchema = crate::common::response_helpers::parse_response(response, 1024).await; - assert!(msg.message.to_lowercase().contains("created") || msg.message.to_lowercase().contains("success")); + assert!(!created_permission.id.id.to_raw().is_empty(), "Created permission must have non-empty id"); + assert_eq!(created_permission.name, permission_name, "Created permission name must match request"); // Verify permission was created in database - let created_permission = repo + let db_permission = repo .query_permission_by_name(permission_name) .await .unwrap(); - assert_eq!(created_permission.name, permission_name); + assert_eq!(db_permission.name, permission_name); // Clean up - let _ = repo.query_delete_permission(created_permission.id.id.to_raw()).await; + let _ = repo.query_delete_permission(db_permission.id.id.to_raw()).await; } } \ No newline at end of file diff --git a/tests/src/iam/permissions/permissions_service_test.rs b/tests/src/iam/permissions/permissions_service_test.rs index 8921888..c91bfd3 100644 --- a/tests/src/iam/permissions/permissions_service_test.rs +++ b/tests/src/iam/permissions/permissions_service_test.rs @@ -29,10 +29,11 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::CREATED); - // Verify response body contains created permission + // Verify response body contains created permission data let created: PermissionsSchema = crate::common::response_helpers::parse_response(response, 1024).await; - assert_eq!(created.name, permission_name); + assert!(!created.id.is_empty(), "Created permission must have non-empty id"); + assert_eq!(created.name, permission_name, "Created permission name must match request"); // Verify permission was created in database let created_permission = repo @@ -76,10 +77,12 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); - // Verify response body contains permission + // Verify response body contains permission data let body: PermissionsSchema = crate::common::response_helpers::parse_response(response, 1024).await; - assert_eq!(body.id.id.to_raw(), permission_id); + assert!(!body.id.id.to_raw().is_empty(), "Permission must have non-empty id"); + assert_eq!(body.id.id.to_raw(), permission_id, "Permission ID must match"); + assert_eq!(body.name, permission_name, "Permission name must match"); // Clean up let _ = repo.query_delete_permission(permission_id).await; @@ -122,10 +125,11 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); - // Verify response body contains updated permission + // Verify response body contains updated permission data let body: PermissionsSchema = crate::common::response_helpers::parse_response(response, 1024).await; - assert_eq!(body.name, new_name); + assert!(!body.id.id.to_raw().is_empty(), "Updated permission must have non-empty id"); + assert_eq!(body.name, new_name, "Updated permission name must match request"); // Verify permission was updated in database let updated_permission = repo diff --git a/tests/src/iam/roles/roles_controller_test.rs b/tests/src/iam/roles/roles_controller_test.rs index f5280e6..b3ea6a2 100644 --- a/tests/src/iam/roles/roles_controller_test.rs +++ b/tests/src/iam/roles/roles_controller_test.rs @@ -29,19 +29,22 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::CREATED); - let msg: imphnen_entities::MessageResponseDto = + // Verify response body contains role data + let created_role: imphnen_iam::v1::roles::roles_dto::RolesDetailItemDto = crate::common::response_helpers::parse_response(response, 1024).await; - assert!(msg.message.to_lowercase().contains("created") || msg.message.to_lowercase().contains("success")); + assert!(!created_role.id.is_empty(), "Created role must have non-empty id"); + assert_eq!(created_role.name, role_name, "Created role name must match request"); + assert_eq!(created_role.description, Some("Test role for controller".to_string()), "Created role description must match request"); // Verify role was created in database - let created_role = repo + let db_role = repo .query_role_by_name(role_name) .await .unwrap(); - assert_eq!(created_role.name, role_name); + assert_eq!(db_role.name, role_name); // Clean up - let _ = repo.query_delete_role(created_role.id.id.to_raw()).await; + let _ = repo.query_delete_role(db_role.id.id.to_raw()).await; } #[tokio::test] @@ -121,6 +124,15 @@ mod tests { // Expect wrapped { data: [...] } or raw array. Normalize to array and check created roles are present let list_val = if let Some(d) = v.get("data") { d.clone() } else { v }; let arr = list_val.as_array().expect("role list should be an array"); + + // Verify all items have required fields + for item in arr.iter() { + assert!(item.get("id").is_some(), "Role list items must have id"); + assert!(item.get("name").is_some(), "Role list items must have name"); + let name = item.get("name").and_then(|n| n.as_str()).expect("Role name must be string"); + assert!(!name.is_empty(), "Role name must not be empty"); + } + let names: Vec = arr.iter().filter_map(|it| it.get("name").and_then(|n| n.as_str()).map(|s| s.to_string())).collect(); for name in ["test_role_list_1", "test_role_list_2", "test_role_list_3"].iter() { assert!(names.contains(&name.to_string()), "expected role {} in list", name); @@ -164,11 +176,13 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); - let v = crate::common::response_helpers::parse_response_value(response, 1024).await; - // Expect wrapped { data: {...} } or direct object. Extract and assert name - let obj = if let Some(d) = v.get("data") { d.clone() } else { v }; - let name = obj.get("name").and_then(|n| n.as_str()).expect("role object must have name"); - assert_eq!(name, "test_role_by_id"); + // Parse and verify role data + let role: imphnen_iam::v1::roles::roles_dto::RolesDetailItemDto = + crate::common::response_helpers::parse_response(response, 1024).await; + + assert!(!role.id.is_empty(), "Role must have non-empty id"); + assert_eq!(role.name, role_name, "Role name must match created role"); + assert_eq!(role.description, Some("Test role for by ID test".to_string()), "Role description must match created role"); // Clean up let _ = repo.query_delete_role(role_id).await; diff --git a/tests/src/iam/roles/roles_service_test.rs b/tests/src/iam/roles/roles_service_test.rs index 98a2e26..9ae6493 100644 --- a/tests/src/iam/roles/roles_service_test.rs +++ b/tests/src/iam/roles/roles_service_test.rs @@ -28,20 +28,21 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::CREATED); - // Verify response body contains success message - let msg: MessageResponseDto = - crate::common::response_helpers::parse_response(response, 1024).await; - assert!(msg.message.to_lowercase().contains("created") || msg.message.to_lowercase().contains("success")); + // Verify response body contains role data + let created_role: imphnen_iam::v1::roles::roles_dto::RolesDetailItemDto = + crate::common::response_helpers::parse_response_data(response, 1024).await; + assert!(!created_role.id.is_empty(), "Created role must have non-empty id"); + assert_eq!(created_role.name, role_name, "Created role name must match request"); // Verify role was created in database - let created_role = repo + let db_role = repo .query_role_by_name(role_name.clone()) .await .unwrap(); - assert_eq!(created_role.name, role_name); + assert_eq!(db_role.name, role_name); // Clean up - let _ = repo.query_delete_role(created_role.id).await; + let _ = repo.query_delete_role(db_role.id).await; } #[tokio::test] @@ -60,9 +61,9 @@ mod tests { // Get created role to get ID let created_role = repo - .query_role_by_name(role_name) - .await - .unwrap(); + .query_role_by_name(role_name.clone()) + .await + .unwrap(); let role_id = created_role.id; // Get role by ID through service @@ -74,17 +75,17 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); - // parse response value and handle wrapped {"data": ...} or object - let v = crate::common::response_helpers::parse_response_value(response, 1024).await; - if let Some(inner) = v.get("data") { - // attempt to deserialize into detail DTO if present - let _role: imphnen_iam::v1::roles::roles_dto::RolesDetailItemDto = - serde_json::from_value(inner.clone()).unwrap_or_else(|_| { - panic!("Response 'data' couldn't be deserialized into RolesDetailItemDto: {}", inner) - }); + // Parse response and verify role data + let v = crate::common::response_helpers::parse_response_value(response, 1024).await; + let role_data = if let Some(inner) = v.get("data") { + serde_json::from_value(inner.clone()).expect("Response 'data' must deserialize into RolesDetailItemDto") } else { - assert!(v.is_object()); - } + serde_json::from_value(v).expect("Response must deserialize into RolesDetailItemDto") + }; + let role: imphnen_iam::v1::roles::roles_dto::RolesDetailItemDto = role_data; + + assert!(!role.id.is_empty(), "Role must have non-empty id"); + assert_eq!(role.name, role_name, "Role name must match created role"); // Clean up let _ = repo.query_delete_role(role_id).await; @@ -108,9 +109,9 @@ mod tests { // Get created role to get ID let created_role = repo - .query_role_by_name(original_name) - .await - .unwrap(); + .query_role_by_name(original_name.clone()) + .await + .unwrap(); let role_id = created_role.id; // Prepare update request @@ -160,9 +161,9 @@ mod tests { // Get created role to get ID let created_role = repo - .query_role_by_name(role_name) - .await - .unwrap(); + .query_role_by_name(role_name.clone()) + .await + .unwrap(); let role_id = created_role.id; // Verify role exists before deletion @@ -220,12 +221,14 @@ mod tests { let list: imphnen_entities::ResponseListSuccessDto> = serde_json::from_value(inner.clone()).unwrap_or(imphnen_entities::ResponseListSuccessDto { data: vec![], meta: None }); if !list.data.is_empty() { - assert!(!list.data[0].id.is_empty()); + assert!(!list.data[0].id.is_empty(), "Role list items must have non-empty id"); + assert!(!list.data[0].name.is_empty(), "Role list items must have non-empty name"); } } else if v.is_array() { let arr: Vec = serde_json::from_value(v).unwrap_or_default(); if !arr.is_empty() { - assert!(!arr[0].id.is_empty()); + assert!(!arr[0].id.is_empty(), "Role list items must have non-empty id"); + assert!(!arr[0].name.is_empty(), "Role list items must have non-empty name"); } } else { // accept other object shapes @@ -275,9 +278,9 @@ mod tests { // Clean up let created_role = repo - .query_role_by_name(role_name) - .await - .unwrap(); + .query_role_by_name(role_name.clone()) + .await + .unwrap(); let _ = repo.query_delete_role(created_role.id).await; } @@ -333,9 +336,9 @@ mod tests { // Clean up let _ = repo.query_delete_role(role_id1).await; let created_role2 = repo - .query_role_by_name(role_name2) - .await - .unwrap(); + .query_role_by_name(role_name2.clone()) + .await + .unwrap(); let _ = repo.query_delete_role(created_role2.id).await; } diff --git a/tests/src/iam/teams/admin_teams_controller_tests.rs b/tests/src/iam/teams/admin_teams_controller_tests.rs index 43324a7..9c87965 100644 --- a/tests/src/iam/teams/admin_teams_controller_tests.rs +++ b/tests/src/iam/teams/admin_teams_controller_tests.rs @@ -121,11 +121,13 @@ async fn test_admin_team_endpoints_sensitive_data_exposure() { // Verify sensitive fields are present in admin response assert!(response_json.data.iter().any(|team| { - team.is_deleted == false && // Should show is_deleted field - team.is_active == true && // Should show is_active field - team.website_url.is_some() && // Should show website_url - team.github_url.is_some() // Should show github_url - }), "Admin team list should expose sensitive fields"); + team.is_deleted == false && // Should show is_deleted field + team.is_active == true && // Should show is_active field + team.website_url.is_some() && // Should show website_url + team.github_url.is_some() && // Should show github_url + !team.id.is_empty() && // Should have non-empty id + !team.name.is_empty() // Should have non-empty name + }), "Admin team list should expose sensitive fields and required data"); // Test 2: Admin team detail endpoint should expose sensitive fields and full member info let response = imphnen_iam::teams_controller::get_admin_team_by_id( @@ -142,6 +144,8 @@ async fn test_admin_team_endpoints_sensitive_data_exposure() { let admin_team = response_json.data; // Verify sensitive fields are present + assert!(!admin_team.id.is_empty(), "Admin team detail should have non-empty id"); + assert!(!admin_team.name.is_empty(), "Admin team detail should have non-empty name"); assert!(admin_team.is_deleted == false, "Admin team detail should show is_deleted field"); assert!(admin_team.is_active == true, "Admin team detail should show is_active field"); assert!(admin_team.website_url.is_some(), "Admin team detail should show website_url"); @@ -150,10 +154,11 @@ async fn test_admin_team_endpoints_sensitive_data_exposure() { // Verify all members have sensitive info (email should be present for admins) let has_all_member_info = admin_team.members.iter().all(|member| { - member.email.is_some() && // Admin should see member emails - member.fullname != "" && // Admin should see fullnames - member.role != "" // Admin should see roles - }); + member.email.is_some() && // Admin should see member emails + !member.fullname.is_empty() && // Admin should see fullnames + !member.role.is_empty() && // Admin should see roles + !member.id.is_empty() // Admin should see member ids + }); assert!(has_all_member_info, "Admin team detail should expose all member sensitive information"); @@ -173,10 +178,11 @@ async fn test_admin_team_endpoints_sensitive_data_exposure() { // Verify all members have sensitive info let has_all_member_info = admin_members.iter().all(|member| { - member.email.is_some() && // Admin should see member emails - member.fullname != "" && // Admin should see fullnames - member.role != "" // Admin should see roles - }); + member.email.is_some() && // Admin should see member emails + !member.fullname.is_empty() && // Admin should see fullnames + !member.role.is_empty() && // Admin should see roles + !member.id.is_empty() // Admin should see member ids + }); assert!(has_all_member_info, "Admin team members endpoint should expose all member sensitive information"); diff --git a/tests/src/iam/teams/teams_controller_test.rs b/tests/src/iam/teams/teams_controller_test.rs index aa04da9..3151972 100644 --- a/tests/src/iam/teams/teams_controller_test.rs +++ b/tests/src/iam/teams/teams_controller_test.rs @@ -42,12 +42,12 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::CREATED); - // Expect a response with data containing the created team id and stats - let v = crate::common::response_helpers::parse_response_value(response, 2048).await; - // If wrapped in { "data": ... }, extract - let data = if let Some(d) = v.get("data") { d.clone() } else { v }; - assert!(data.get("team_id").is_some(), "create response must include team_id"); - assert!(data.get("invitations_sent").is_some(), "create response should report invitations_sent"); + // Parse and verify response contains team data + let team_response: imphnen_iam::v1::teams::teams_dto::TeamsCreateResponseDto = + crate::common::response_helpers::parse_response(response, 2048).await; + + assert!(!team_response.team_id.is_empty(), "Created team must have non-empty team_id"); + assert_eq!(team_response.invitations_sent, 0, "No invitations should be sent for empty member list"); // Verify team was created in database let team_thing = make_thing_from_enum(ResourceEnum::Teams, &user.id.id.to_raw()); @@ -325,14 +325,22 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::OK); - let body_json: serde_json::Value = crate::common::response_helpers::parse_response_value(response, 2048).await; - // Expect a list wrapper with data -> array - let list = if let Some(d) = body_json.get("data") { d } else { &body_json }; - assert!(list.is_array(), "search should return array of teams"); - let found = list.as_array().unwrap().iter().any(|item| { - if let Some(name) = item.get("name") { name == "Searchable Test Team" } else { false } - }); - assert!(found, "created team should appear in search results"); + // Parse and verify search results + let search_response: imphnen_entities::ResponseListSuccessDto> = + crate::common::response_helpers::parse_response(response, 2048).await; + + assert!(!search_response.data.is_empty(), "Search should return at least one team"); + + // Verify all results have required fields + for team in &search_response.data { + assert!(!team.id.is_empty(), "Search result team must have non-empty id"); + assert!(!team.name.is_empty(), "Search result team must have non-empty name"); + } + + // Verify our team is in results + let found_team = search_response.data.iter().find(|t| t.name == "Searchable Test Team"); + assert!(found_team.is_some(), "Created team should appear in search results"); + assert_eq!(found_team.unwrap().is_open, true, "Found team should be open"); // Clean up let _ = repo.query_delete_team(team_id).await; diff --git a/tests/src/iam/teams/teams_service_test.rs b/tests/src/iam/teams/teams_service_test.rs index 68d31b1..397fed7 100644 --- a/tests/src/iam/teams/teams_service_test.rs +++ b/tests/src/iam/teams/teams_service_test.rs @@ -26,7 +26,9 @@ mod tests { let arr = list_val.as_array().expect("team list should be an array"); if !arr.is_empty() { let first = &arr[0]; - assert!(first.get("id").is_some() || first.get("name").is_some(), "team items should have id or name"); + assert!(first.get("id").is_some(), "team items must have id"); + assert!(first.get("name").is_some(), "team items must have name"); + assert!(first.get("name").and_then(|n| n.as_str()).map_or(false, |s| !s.is_empty()), "team name must not be empty"); } } @@ -50,7 +52,9 @@ mod tests { let arr = list_val.as_array().expect("public team list should be an array"); if !arr.is_empty() { let first = &arr[0]; - assert!(first.get("id").is_some() || first.get("name").is_some(), "public team items should have id or name"); + assert!(first.get("id").is_some(), "public team items must have id"); + assert!(first.get("name").is_some(), "public team items must have name"); + assert!(first.get("name").and_then(|n| n.as_str()).map_or(false, |s| !s.is_empty()), "public team name must not be empty"); } } @@ -149,7 +153,9 @@ mod tests { let arr = list_val.as_array().expect("search should return array"); if !arr.is_empty() { let first = &arr[0]; - assert!(first.get("id").is_some() || first.get("name").is_some(), "search item should have id or name"); + assert!(first.get("id").is_some(), "search result items must have id"); + assert!(first.get("name").is_some(), "search result items must have name"); + assert!(first.get("name").and_then(|n| n.as_str()).map_or(false, |s| !s.is_empty()), "search result name must not be empty"); } } diff --git a/tests/src/iam/users/users_controller_test.rs b/tests/src/iam/users/users_controller_test.rs index c46d2a1..fa53d65 100644 --- a/tests/src/iam/users/users_controller_test.rs +++ b/tests/src/iam/users/users_controller_test.rs @@ -37,20 +37,24 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::CREATED); - let msg: imphnen_entities::MessageResponseDto = + // Verify response body contains user data + let created_user: imphnen_iam::v1::users::users_dto::UsersDetailItemDto = crate::common::response_helpers::parse_response(response, 4096).await; - assert!(msg.message.to_lowercase().contains("created") || msg.message.to_lowercase().contains("success")); + assert!(!created_user.id.is_empty(), "Created user must have non-empty id"); + assert_eq!(created_user.email, email, "Created user email must match request"); + assert_eq!(created_user.fullname, "Test User Controller", "Created user fullname must match request"); + assert_eq!(created_user.is_active, true, "Created user must be active"); // Verify user was created in database - let created_user = repo + let db_user = repo .query_user_by_email(email.clone()) .await .unwrap(); - assert_eq!(created_user.email, email); - assert_eq!(created_user.fullname, "Test User Controller"); - assert_eq!(created_user.is_active, true); + assert_eq!(db_user.email, email); + assert_eq!(db_user.fullname, "Test User Controller"); + assert_eq!(db_user.is_active, true); // Clean up - let _ = repo.query_delete_user(created_user.id.id.to_raw()).await; + let _ = repo.query_delete_user(db_user.id.id.to_raw()).await; } } \ No newline at end of file diff --git a/tests/src/iam/users/users_service_test.rs b/tests/src/iam/users/users_service_test.rs index c5255b9..88dcaf4 100644 --- a/tests/src/iam/users/users_service_test.rs +++ b/tests/src/iam/users/users_service_test.rs @@ -31,12 +31,14 @@ mod tests { let list: imphnen_entities::ResponseListSuccessDto> = serde_json::from_value(inner.clone()).unwrap_or(imphnen_entities::ResponseListSuccessDto { data: vec![], meta: None }); if !list.data.is_empty() { - assert!(!list.data[0].id.is_empty()); + assert!(!list.data[0].id.is_empty(), "User list items must have non-empty id"); + assert!(!list.data[0].email.is_empty(), "User list items must have non-empty email"); } } else if v.is_array() { let arr: Vec = serde_json::from_value(v).unwrap_or_default(); if !arr.is_empty() { - assert!(!arr[0].id.is_empty()); + assert!(!arr[0].id.is_empty(), "User list items must have non-empty id"); + assert!(!arr[0].email.is_empty(), "User list items must have non-empty email"); } } else { // other shapes (object without data) — accept for now @@ -104,17 +106,20 @@ mod tests { // Verify response assert_eq!(response.status(), StatusCode::CREATED); - // Verify response body contains success message - let created_msg: imphnen_entities::MessageResponseDto = - crate::common::response_helpers::parse_response(response, 4096).await; - assert!(created_msg.message.to_lowercase().contains("created") || created_msg.message.to_lowercase().contains("success")); + // Verify response body contains user data + let created_user: imphnen_iam::v1::users::users_dto::UsersDetailItemDto = + crate::common::response_helpers::parse_response_data(response, 4096).await; + assert!(!created_user.id.is_empty(), "Created user must have non-empty id"); + assert_eq!(created_user.email, email, "Created user email must match request"); + assert_eq!(created_user.fullname, "Test User Service", "Created user fullname must match request"); + assert_eq!(created_user.is_active, true, "Created user must be active"); // Verify user was created in database - let created_user = repo.query_user_by_email(email.clone()).await.unwrap(); - assert_eq!(created_user.email, email); + let db_user = repo.query_user_by_email(email.clone()).await.unwrap(); + assert_eq!(db_user.email, email); // Clean up - let _ = repo.query_delete_user(created_user.id.id.to_raw()).await; + let _ = repo.query_delete_user(db_user.id.id.to_raw()).await; } #[tokio::test]