186 lines
5.9 KiB
Rust
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;
|
|
}
|