Files

186 lines
5.9 KiB
Rust

use book_manager::app::App;
use loco_rs::testing::prelude::*;
use serial_test::serial;
use super::prepare_data;
#[tokio::test]
#[serial]
async fn can_list_books_with_pagination() {
request::<App, _, _>(|request, _ctx| async move {
// First test if auth endpoint works (to verify routing is working)
let auth_response = request.get("/api/auth/current").await;
println!("Auth endpoint status: {}", auth_response.status_code());
// Now test books endpoint
let response = request.get("/api/books").await;
let status = response.status_code();
let body = response.text();
println!("Books endpoint status: {}", status);
println!("Books response (first 300 chars): {}", &body[..body.len().min(300)]);
// The route should return 200 with JSON, not HTML
assert_eq!(
status,
200,
"List books request should succeed"
);
// Check if it's JSON (not HTML)
assert!(
body.trim_start().starts_with('{'),
"Response should be JSON, but got: {}",
&body[..body.len().min(100)]
);
// Try to parse as JSON
let json: serde_json::Value = serde_json::from_str(&body)
.expect("Response should be valid JSON");
// Verify response structure
assert!(json.get("books").is_some(), "Response should contain 'books' field");
assert!(json.get("total").is_some(), "Response should contain 'total' field");
assert!(json.get("page").is_some(), "Response should contain 'page' field");
assert!(json.get("per_page").is_some(), "Response should contain 'per_page' field");
assert!(json.get("total_pages").is_some(), "Response should contain 'total_pages' field");
// Verify default values
assert_eq!(json["page"], 1, "Default page should be 1");
assert_eq!(json["per_page"], 12, "Default per_page should be 12");
})
.await;
}
#[tokio::test]
#[serial]
async fn can_list_books_with_custom_pagination() {
request::<App, _, _>(|request, _ctx| async move {
// Test custom pagination parameters
let response = request.get("/api/books?page=2&per_page=5").await;
assert_eq!(
response.status_code(),
200,
"List books with custom pagination should succeed"
);
let json: serde_json::Value = response.json();
assert_eq!(json["page"], 2, "Page should be 2");
assert_eq!(json["per_page"], 5, "Per page should be 5");
})
.await;
}
#[tokio::test]
#[serial]
async fn can_get_single_book() {
request::<App, _, _>(|request, ctx| async move {
// First create a test book
let user = prepare_data::init_user_login(&request, &ctx).await;
let book_payload = serde_json::json!({
"title": "Test Book",
"author": "Test Author",
"description": "A test book description",
"content": "This is the content of the test book."
});
let (auth_key, auth_value) = prepare_data::auth_header(&user.token);
let create_response = request
.post("/api/books")
.add_header(auth_key, auth_value.clone())
.json(&book_payload)
.await;
assert_eq!(
create_response.status_code(),
200,
"Create book request should succeed"
);
let created_book: serde_json::Value = create_response.json();
let book_id = created_book["id"].as_i64().unwrap();
// Now get the book by ID
let get_response = request.get(&format!("/api/books/{}", book_id)).await;
assert_eq!(
get_response.status_code(),
200,
"Get single book request should succeed"
);
let retrieved_book: serde_json::Value = get_response.json();
assert_eq!(retrieved_book["title"], "Test Book");
assert_eq!(retrieved_book["author"], "Test Author");
assert_eq!(retrieved_book["description"], "A test book description");
})
.await;
}
#[tokio::test]
#[serial]
async fn can_create_book_with_auth() {
request::<App, _, _>(|request, ctx| async move {
let user = prepare_data::init_user_login(&request, &ctx).await;
let book_payload = serde_json::json!({
"title": "Rust Programming",
"author": "Steve Klabnik",
"description": "Learn Rust programming",
"content": "Rust is a systems programming language..."
});
let (auth_key, auth_value) = prepare_data::auth_header(&user.token);
let response = request
.post("/api/books")
.add_header(auth_key, auth_value)
.json(&book_payload)
.await;
assert_eq!(
response.status_code(),
200,
"Create book request should succeed with authentication"
);
let json: serde_json::Value = response.json();
assert_eq!(json["title"], "Rust Programming");
assert_eq!(json["author"], "Steve Klabnik");
assert!(json.get("id").is_some(), "Created book should have an ID");
})
.await;
}
#[tokio::test]
#[serial]
async fn cannot_create_book_without_auth() {
request::<App, _, _>(|request, _ctx| async move {
let book_payload = serde_json::json!({
"title": "Unauthorized Book",
"author": "No Auth",
"content": "This should fail"
});
let response = request
.post("/api/books")
.json(&book_payload)
.await;
// Should return 401 Unauthorized or similar error
assert_ne!(
response.status_code(),
200,
"Create book should fail without authentication"
);
})
.await;
}