Hurl tests for project api.

This commit is contained in:
Drew 2025-10-22 21:54:19 -07:00
parent 4895f7c4b7
commit d8094c4812
3 changed files with 406 additions and 5 deletions

View file

@ -1,7 +1,12 @@
use std::path::Path;
use axum::{Router, routing::get};
use axum_test::{TestServer, TestServerConfig, Transport};
use hurl::report::html::{Testcase, write_report};
use hurl::runner::{self, RunnerOptions, Value, VariableSet};
use hurl::util::logger::LoggerOptionsBuilder;
use hurl_core::input::Input;
use tower_http::trace::TraceLayer;
async fn create_app() -> Router {
use backend::database::{DatabaseConfig, create_pool};
@ -49,11 +54,14 @@ async fn run_hurl_test(hurl_file_path: &str) {
let logger_opts = LoggerOptionsBuilder::new().build();
let result = runner::run(&content, None, &runner_opts, &variables, &logger_opts).unwrap();
assert!(
result.success,
"Hurl test failed for {}: {:?}",
hurl_file_path, result
);
let input = Input::new(hurl_file_path);
let test_case = Testcase::from(&result, &input);
test_case
.write_html(&content, &result.entries, Path::new("reports/store"), &[])
.expect("Failed to write html files");
write_report(Path::new("reports/"), &vec![test_case]).expect("Failed to write report");
assert!(result.success, "Hurl test failed for {}", hurl_file_path);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
@ -75,3 +83,8 @@ async fn test_update_tasks_api() {
async fn test_delete_tasks_api() {
run_hurl_test("./tests/api/delete_tasks.hurl").await;
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_projects_api() {
run_hurl_test("./tests/api/projects.hurl").await;
}

View file

@ -0,0 +1,387 @@
# Project API Tests
# Test: Create a new project with all fields (POST /api/projects)
POST {{host}}/api/projects
Content-Type: application/json
{
"title": "Test Project Alpha",
"color": "#1976d2"
}
HTTP 201
[Captures]
project_id: jsonpath "$.id"
[Asserts]
jsonpath "$.title" == "Test Project Alpha"
jsonpath "$.color" == "#1976d2"
jsonpath "$.status" == "active"
jsonpath "$.folder_id" == null
jsonpath "$.sort_order" == 0
jsonpath "$.id" exists
jsonpath "$.created_at" exists
jsonpath "$.updated_at" exists
# Test: Create another new project
POST {{host}}/api/projects
Content-Type: application/json
{
"title": "Test Project Beta",
"color": "#ffffff"
}
HTTP 201
[Captures]
project_id_beta: jsonpath "$.id"
[Asserts]
jsonpath "$.title" == "Test Project Beta"
jsonpath "$.color" == "#ffffff"
jsonpath "$.status" == "active"
jsonpath "$.folder_id" == null
jsonpath "$.sort_order" == 1000
jsonpath "$.id" exists
jsonpath "$.created_at" exists
jsonpath "$.updated_at" exists
POST {{host}}/api/projects
Content-Type: application/json
{
"title": "Missing Color"
}
HTTP 422
[Asserts]
jsonpath "$.error" exists
# Test: Create project with invalid data (missing title)
POST {{host}}/api/projects
Content-Type: application/json
{
"color": "#ffffff"
}
HTTP 422
[Asserts]
jsonpath "$.error" exists
# Test: Create project with invalid data (invalid color)
POST {{host}}/api/projects
Content-Type: application/json
{
"title": "Invalid Color",
"color": "#ffffffasdf"
}
HTTP 422
[Asserts]
jsonpath "$.error" exists
# Test: Get a specific project by ID (GET /api/projects/{id})
GET {{host}}/api/projects/{{project_id}}
HTTP 200
[Asserts]
jsonpath "$.id" == "{{project_id}}"
jsonpath "$.title" == "Test Project Alpha"
jsonpath "$.color" == "#1976d2"
jsonpath "$.status" == "active"
jsonpath "$.folder_id" == null
jsonpath "$.created_at" exists
jsonpath "$.updated_at" exists
# Test: Get a minimal project by ID
GET {{host}}/api/projects/{{project_id_beta}}
HTTP 200
[Asserts]
jsonpath "$.id" == "{{project_id_beta}}"
jsonpath "$.title" == "Test Project Beta"
jsonpath "$.color" == "#ffffff"
jsonpath "$.status" == "active"
# Test: Get non-existent project
GET {{host}}/api/projects/00000000-0000-0000-0000-000000000000
HTTP 404
[Asserts]
jsonpath "$.error" exists
# Test: Get project with invalid UUID format
GET {{host}}/api/projects/invalid-uuid
HTTP 400
[Asserts]
jsonpath "$.error" exists
# Test: List all projects (GET /api/projects)
GET {{host}}/api/projects
HTTP 200
[Captures]
initial_count: jsonpath "$" count
[Asserts]
jsonpath "$" isCollection
jsonpath "$[*].id" contains "{{project_id}}"
jsonpath "$[*].id" contains "{{project_id_beta}}"
jsonpath "$[*].title" contains "Test Project Alpha"
jsonpath "$[*].title" contains "Test Project Beta"
# Test: Verify all projects have required fields
GET {{host}}/api/projects
HTTP 200
[Asserts]
jsonpath "$[?(@.id=='{{project_id}}')].title" exists
jsonpath "$[?(@.id=='{{project_id}}')].status" exists
jsonpath "$[?(@.id=='{{project_id}}')].created_at" exists
jsonpath "$[?(@.id=='{{project_id}}')].updated_at" exists
jsonpath "$[?(@.id=='{{project_id}}')].sort_order" exists
# Test: Update project title only (PUT /api/projects/{id})
PUT {{host}}/api/projects/{{project_id}}
Content-Type: application/json
{
"title": "Updated Project Alpha"
}
HTTP 200
[Captures]
first_updated_at: jsonpath "$.updated_at"
[Asserts]
jsonpath "$.id" == "{{project_id}}"
jsonpath "$.title" == "Updated Project Alpha"
jsonpath "$.color" == "#1976d2"
jsonpath "$.status" == "active"
# Test: Update status to done
PUT {{host}}/api/projects/{{project_id}}
Content-Type: application/json
{
"status": "done"
}
HTTP 200
[Asserts]
jsonpath "$.id" == "{{project_id}}"
jsonpath "$.status" == "done"
# Test: Update status to backlog
PUT {{host}}/api/projects/{{project_id}}
Content-Type: application/json
{
"status": "backlog"
}
HTTP 200
[Asserts]
jsonpath "$.id" == "{{project_id}}"
jsonpath "$.status" == "backlog"
# Test: Update color
PUT {{host}}/api/projects/{{project_id}}
Content-Type: application/json
{
"color": "#388e3c"
}
HTTP 200
[Asserts]
jsonpath "$.id" == "{{project_id}}"
jsonpath "$.color" == "#388e3c"
# Test: Update multiple fields together
PUT {{host}}/api/projects/{{project_id}}
Content-Type: application/json
{
"title": "Completely Updated Project",
"color": "#d32f2f",
"status": "active"
}
HTTP 200
[Asserts]
jsonpath "$.id" == "{{project_id}}"
jsonpath "$.title" == "Completely Updated Project"
jsonpath "$.color" == "#d32f2f"
jsonpath "$.status" == "active"
# Test: Update non-existent project
PUT {{host}}/api/projects/00000000-0000-0000-0000-000000000000
Content-Type: application/json
{
"title": "This should fail"
}
HTTP 404
[Asserts]
jsonpath "$.error" exists
# Test: Update with invalid UUID format
PUT {{host}}/api/projects/invalid-uuid-format
Content-Type: application/json
{
"title": "This should also fail"
}
HTTP 400
[Asserts]
jsonpath "$.error" exists
# Test: Update with empty title
PUT {{host}}/api/projects/{{project_id_beta}}
Content-Type: application/json
{
"title": ""
}
HTTP 422
[Asserts]
jsonpath "$.error" exists
# Test: Update with invalid status
PUT {{host}}/api/projects/{{project_id_beta}}
Content-Type: application/json
{
"status": "invalid_status"
}
HTTP 422
[Asserts]
jsonpath "$.error" exists
# Test: Update with invalid color format
PUT {{host}}/api/projects/{{project_id_beta}}
Content-Type: application/json
{
"color": "invalid-color"
}
HTTP 422
[Asserts]
jsonpath "$.error" exists
# Setup: Create a project to delete
POST {{host}}/api/projects
Content-Type: application/json
{
"title": "Project to Delete",
"color": "#222222"
}
HTTP 201
[Captures]
delete_project_id: jsonpath "$.id"
# Test: Delete project successfully (DELETE /api/projects/{id})
DELETE {{host}}/api/projects/{{delete_project_id}}
HTTP 204
# Test: Verify project is deleted (should return 404)
GET {{host}}/api/projects/{{delete_project_id}}
HTTP 404
[Asserts]
jsonpath "$.error" exists
# Setup: Create another project for additional delete tests
POST {{host}}/api/projects
Content-Type: application/json
{
"title": "Another Project to Delete",
"color": "#333333"
}
HTTP 201
[Captures]
another_delete_project_id: jsonpath "$.id"
# Test: Verify project exists before deletion
GET {{host}}/api/projects/{{another_delete_project_id}}
HTTP 200
[Asserts]
jsonpath "$.title" == "Another Project to Delete"
# Test: Delete the project
DELETE {{host}}/api/projects/{{another_delete_project_id}}
HTTP 204
# Test: Confirm project no longer exists
GET {{host}}/api/projects/{{another_delete_project_id}}
HTTP 404
[Asserts]
jsonpath "$.error" exists
# Test: Delete non-existent project
DELETE {{host}}/api/projects/00000000-0000-0000-0000-000000000000
HTTP 404
[Asserts]
jsonpath "$.error" exists
# Test: Delete with invalid UUID format
DELETE {{host}}/api/projects/invalid-uuid-format
HTTP 400
[Asserts]
jsonpath "$.error" exists
# Test: Multiple deletions of same project (idempotency test)
POST {{host}}/api/projects
Content-Type: application/json
{
"title": "Project for Idempotency Test",
"color": "#234567"
}
HTTP 201
[Captures]
idempotent_project_id: jsonpath "$.id"
# First deletion should succeed
DELETE {{host}}/api/projects/{{idempotent_project_id}}
HTTP 204
# Second deletion should return 404 (project already gone)
DELETE {{host}}/api/projects/{{idempotent_project_id}}
HTTP 404
[Asserts]
jsonpath "$.error" exists
# Test: List shows remaining projects after deletions
GET {{host}}/api/projects
HTTP 200
[Asserts]
jsonpath "$[*].id" contains "{{project_id}}"
jsonpath "$[*].id" contains "{{project_id_beta}}"
jsonpath "$[*].id" not contains "{{delete_project_id}}"
jsonpath "$[*].id" not contains "{{another_delete_project_id}}"
jsonpath "$[*].id" not contains "{{idempotent_project_id}}"
# Cleanup: Delete remaining test projects
DELETE {{host}}/api/projects/{{project_id}}
HTTP 204
DELETE {{host}}/api/projects/{{project_id_beta}}
HTTP 204
# Test: Verify all test projects are cleaned up
GET {{host}}/api/projects
HTTP 200
[Asserts]
jsonpath "$[*].id" not contains "{{project_id}}"
jsonpath "$[*].id" not contains "{{project_id_beta}}"