Hurl tests for project api.
This commit is contained in:
parent
4895f7c4b7
commit
d8094c4812
3 changed files with 406 additions and 5 deletions
1
backend/.gitignore
vendored
1
backend/.gitignore
vendored
|
|
@ -1,5 +1,6 @@
|
|||
target
|
||||
coverage
|
||||
reports
|
||||
|
||||
*.db
|
||||
*.db-shm
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
387
backend/tests/api/projects.hurl
Normal file
387
backend/tests/api/projects.hurl
Normal 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}}"
|
||||
Loading…
Add table
Add a link
Reference in a new issue