chore(scripts): complete test-api.sh curl script for all 7 endpoints
Fixes TC-TD-09 (product_id required → 400 not 201), TC-NS-08 (check_one_of for 200/404), TC-RO-10 (use TASK_ID directly to avoid cross-story scope violation). Adds DEMO_TOKEN support for 403 tests on all 4 write endpoints. Adds check_one_of helper and shorthand request functions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
69a4ea27cd
commit
b6c08851a0
1 changed files with 244 additions and 210 deletions
|
|
@ -2,27 +2,27 @@
|
|||
# =============================================================================
|
||||
# Scrum4Me — API curl test script
|
||||
# =============================================================================
|
||||
# Usage:
|
||||
# 1. Start the dev server: npm run dev
|
||||
# 2. Log in as "lars" in the UI and create an API token (Settings → API Tokens)
|
||||
# 3. Copy the token and set it below
|
||||
# 4. Run: bash scripts/test-api.sh
|
||||
# See scripts/README.md for full setup instructions.
|
||||
#
|
||||
# Prerequisites:
|
||||
# - Database seeded: npx prisma db seed
|
||||
# - Dev server running on localhost:3000
|
||||
# - A valid API token for user "lars"
|
||||
# - curl installed
|
||||
# Quick start:
|
||||
# 1. npx prisma db seed
|
||||
# 2. npm run dev
|
||||
# 3. Log in as "lars", go to Settings → API Tokens, create a token
|
||||
# 4. Paste it in TOKEN below
|
||||
# 5. Fill in the four IDs (see README for how to find them)
|
||||
# 6. Optionally: log in as "demo", create a token, paste in DEMO_TOKEN
|
||||
# 7. bash scripts/test-api.sh
|
||||
# =============================================================================
|
||||
|
||||
TOKEN="" # Paste your API token here
|
||||
TOKEN="" # API token for "lars" (full-permission user)
|
||||
DEMO_TOKEN="" # API token for "demo" (read-only — used for 403 tests, optional)
|
||||
BASE_URL="http://localhost:3000"
|
||||
|
||||
# IDs — fill these in after running GET /api/products
|
||||
PRODUCT_ID=""
|
||||
SPRINT_ID=""
|
||||
STORY_ID=""
|
||||
TASK_ID=""
|
||||
# IDs — see scripts/README.md for how to find these
|
||||
PRODUCT_ID="" # A product owned by lars
|
||||
SPRINT_ID="" # An active sprint in that product
|
||||
STORY_ID="" # A story in that sprint (IN_SPRINT status)
|
||||
TASK_ID="" # Any task in that story
|
||||
|
||||
# =============================================================================
|
||||
# Helpers
|
||||
|
|
@ -35,7 +35,6 @@ check() {
|
|||
local label="$1"
|
||||
local expected="$2"
|
||||
local actual="$3"
|
||||
|
||||
if [ "$actual" = "$expected" ]; then
|
||||
echo " PASS $label"
|
||||
PASS=$((PASS + 1))
|
||||
|
|
@ -45,284 +44,319 @@ check() {
|
|||
fi
|
||||
}
|
||||
|
||||
# Passes if actual matches any of the remaining arguments
|
||||
check_one_of() {
|
||||
local label="$1"
|
||||
local actual="$2"
|
||||
shift 2
|
||||
for expected in "$@"; do
|
||||
if [ "$actual" = "$expected" ]; then
|
||||
echo " PASS $label"
|
||||
PASS=$((PASS + 1))
|
||||
return
|
||||
fi
|
||||
done
|
||||
echo " FAIL $label (expected one of [$*], got $actual)"
|
||||
FAIL=$((FAIL + 1))
|
||||
}
|
||||
|
||||
header() {
|
||||
echo ""
|
||||
echo "── $1 ──────────────────────────────────────────────────────────"
|
||||
}
|
||||
|
||||
auth_header() {
|
||||
echo "Authorization: Bearer $TOKEN"
|
||||
get() { curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $TOKEN" "$@"; }
|
||||
post() { curl -s -o /dev/null -w "%{http_code}" -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$1" "${@:2}"; }
|
||||
patch() { curl -s -o /dev/null -w "%{http_code}" -X PATCH -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$1" "${@:2}"; }
|
||||
|
||||
get_demo() { curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $DEMO_TOKEN" "$@"; }
|
||||
post_demo() { curl -s -o /dev/null -w "%{http_code}" -X POST -H "Authorization: Bearer $DEMO_TOKEN" -H "Content-Type: application/json" -d "$1" "${@:2}"; }
|
||||
patch_demo() { curl -s -o /dev/null -w "%{http_code}" -X PATCH -H "Authorization: Bearer $DEMO_TOKEN" -H "Content-Type: application/json" -d "$1" "${@:2}"; }
|
||||
|
||||
no_auth_get() { curl -s -o /dev/null -w "%{http_code}" "$@"; }
|
||||
no_auth_post() { curl -s -o /dev/null -w "%{http_code}" -X POST -H "Content-Type: application/json" -d "$1" "${@:2}"; }
|
||||
no_auth_patch() { curl -s -o /dev/null -w "%{http_code}" -X PATCH -H "Content-Type: application/json" -d "$1" "${@:2}"; }
|
||||
|
||||
skip_if_empty() {
|
||||
local var_name="$1"
|
||||
local var_val="$2"
|
||||
if [ -z "$var_val" ]; then
|
||||
echo " SKIP $var_name not set — see scripts/README.md"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# TC-P-09 GET /api/products — happy path
|
||||
# GET /api/products
|
||||
# =============================================================================
|
||||
|
||||
test_products() {
|
||||
header "GET /api/products"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "$(auth_header)" \
|
||||
"$BASE_URL/api/products")
|
||||
check "TC-P-09 happy path (lars)" 200 "$status"
|
||||
# TC-P-09 happy path
|
||||
check "TC-P-09 happy path (lars)" 200 \
|
||||
"$(get "$BASE_URL/api/products")"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
"$BASE_URL/api/products")
|
||||
check "TC-P-01 no token → 401" 401 "$status"
|
||||
# TC-P-01 no token
|
||||
check "TC-P-01 no token → 401" 401 \
|
||||
"$(no_auth_get "$BASE_URL/api/products")"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: Bearer invalid-token-xyz" \
|
||||
"$BASE_URL/api/products")
|
||||
check "TC-P-02 invalid token → 401" 401 "$status"
|
||||
# TC-P-02 invalid token
|
||||
check "TC-P-02 invalid token → 401" 401 \
|
||||
"$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer invalid-token-xyz" "$BASE_URL/api/products")"
|
||||
|
||||
# Capture product list and extract first product ID for downstream tests
|
||||
response=$(curl -s -H "$(auth_header)" "$BASE_URL/api/products")
|
||||
echo " Response: $response" | head -c 300
|
||||
# Print the product list so the user can copy IDs if needed
|
||||
echo ""
|
||||
echo " Product list:"
|
||||
curl -s -H "Authorization: Bearer $TOKEN" "$BASE_URL/api/products" | \
|
||||
grep -o '"id":"[^"]*"\|"name":"[^"]*"' | paste - - | \
|
||||
sed 's/"id":"//;s/","name":"/ → /;s/"//' | \
|
||||
while read -r line; do echo " $line"; done
|
||||
echo ""
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# TC-NS-08 GET /api/products/:id/next-story — happy path
|
||||
# GET /api/products/:id/next-story
|
||||
# =============================================================================
|
||||
|
||||
test_next_story() {
|
||||
header "GET /api/products/:id/next-story"
|
||||
skip_if_empty "PRODUCT_ID" "$PRODUCT_ID" || return
|
||||
|
||||
if [ -z "$PRODUCT_ID" ]; then
|
||||
echo " SKIP PRODUCT_ID not set — fill in scripts/test-api.sh"
|
||||
return
|
||||
fi
|
||||
# TC-NS-08 happy path — 200 if active sprint with stories, 404 if not
|
||||
check_one_of "TC-NS-08 happy path (lars, 200 or 404 both valid)" 200 404 \
|
||||
"$(get "$BASE_URL/api/products/$PRODUCT_ID/next-story")"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "$(auth_header)" \
|
||||
"$BASE_URL/api/products/$PRODUCT_ID/next-story")
|
||||
check "TC-NS-08 happy path (lars)" "200 or 404" "$status"
|
||||
# TC-NS-01 no token
|
||||
check "TC-NS-01 no token → 401" 401 \
|
||||
"$(no_auth_get "$BASE_URL/api/products/$PRODUCT_ID/next-story")"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
"$BASE_URL/api/products/$PRODUCT_ID/next-story")
|
||||
check "TC-NS-01 no token → 401" 401 "$status"
|
||||
# TC-NS-02 invalid token
|
||||
check "TC-NS-02 invalid token → 401" 401 \
|
||||
"$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer invalid-token" "$BASE_URL/api/products/$PRODUCT_ID/next-story")"
|
||||
|
||||
# TC-NS-07 cross-user: unknown product
|
||||
check "TC-NS-07 unknown product id → 404" 404 \
|
||||
"$(get "$BASE_URL/api/products/nonexistent-product-id/next-story")"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# TC-ST-09 GET /api/sprints/:id/tasks — happy path
|
||||
# GET /api/sprints/:id/tasks
|
||||
# =============================================================================
|
||||
|
||||
test_sprint_tasks() {
|
||||
header "GET /api/sprints/:id/tasks"
|
||||
skip_if_empty "SPRINT_ID" "$SPRINT_ID" || return
|
||||
|
||||
if [ -z "$SPRINT_ID" ]; then
|
||||
echo " SKIP SPRINT_ID not set — fill in scripts/test-api.sh"
|
||||
return
|
||||
fi
|
||||
# TC-ST-09 happy path with limit=10
|
||||
check "TC-ST-09 happy path limit=10 → 200" 200 \
|
||||
"$(get "$BASE_URL/api/sprints/$SPRINT_ID/tasks?limit=10")"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "$(auth_header)" \
|
||||
"$BASE_URL/api/sprints/$SPRINT_ID/tasks?limit=10")
|
||||
check "TC-ST-09 happy path with limit=10" 200 "$status"
|
||||
# TC-ST-06 custom limit
|
||||
check "TC-ST-06 limit=3 → 200" 200 \
|
||||
"$(get "$BASE_URL/api/sprints/$SPRINT_ID/tasks?limit=3")"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
"$BASE_URL/api/sprints/$SPRINT_ID/tasks")
|
||||
check "TC-ST-01 no token → 401" 401 "$status"
|
||||
# TC-ST-01 no token
|
||||
check "TC-ST-01 no token → 401" 401 \
|
||||
"$(no_auth_get "$BASE_URL/api/sprints/$SPRINT_ID/tasks")"
|
||||
|
||||
# TC-ST-03 unknown sprint
|
||||
check "TC-ST-03 unknown sprint id → 404" 404 \
|
||||
"$(get "$BASE_URL/api/sprints/nonexistent-sprint-id/tasks")"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# TC-L-17–19 POST /api/stories/:id/log — all 3 log types
|
||||
# POST /api/stories/:id/log (all 3 log types)
|
||||
# =============================================================================
|
||||
|
||||
test_story_log() {
|
||||
header "POST /api/stories/:id/log"
|
||||
skip_if_empty "STORY_ID" "$STORY_ID" || return
|
||||
|
||||
if [ -z "$STORY_ID" ]; then
|
||||
echo " SKIP STORY_ID not set — fill in scripts/test-api.sh"
|
||||
return
|
||||
# TC-L-17 IMPLEMENTATION_PLAN
|
||||
check "TC-L-17 IMPLEMENTATION_PLAN → 201" 201 \
|
||||
"$(post '{"type":"IMPLEMENTATION_PLAN","content":"Aanpak: stap 1 implementeer, stap 2 test."}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")"
|
||||
|
||||
# TC-L-18 TEST_RESULT PASSED
|
||||
check "TC-L-18 TEST_RESULT PASSED → 201" 201 \
|
||||
"$(post '{"type":"TEST_RESULT","content":"Alle tests geslaagd.","status":"PASSED"}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")"
|
||||
|
||||
# TC-L-19 COMMIT
|
||||
check "TC-L-19 COMMIT → 201" 201 \
|
||||
"$(post '{"type":"COMMIT","content":"feat: implementatie afgerond","commit_hash":"abc1234","commit_message":"feat(ST-001): account aanmaken"}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")"
|
||||
|
||||
# TC-L-07 invalid type
|
||||
check "TC-L-07 invalid type → 400" 400 \
|
||||
"$(post '{"type":"UNKNOWN","content":"test"}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")"
|
||||
|
||||
# TC-L-08 IMPLEMENTATION_PLAN missing content
|
||||
check "TC-L-08 missing content → 400" 400 \
|
||||
"$(post '{"type":"IMPLEMENTATION_PLAN"}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")"
|
||||
|
||||
# TC-L-10 TEST_RESULT missing status
|
||||
check "TC-L-10 TEST_RESULT missing status → 400" 400 \
|
||||
"$(post '{"type":"TEST_RESULT","content":"done"}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")"
|
||||
|
||||
# TC-L-01 no token
|
||||
check "TC-L-01 no token → 401" 401 \
|
||||
"$(no_auth_post '{"type":"IMPLEMENTATION_PLAN","content":"test"}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")"
|
||||
|
||||
# TC-L-03 demo user → 403
|
||||
if [ -n "$DEMO_TOKEN" ]; then
|
||||
check "TC-L-03 demo user → 403" 403 \
|
||||
"$(post_demo '{"type":"IMPLEMENTATION_PLAN","content":"test"}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")"
|
||||
else
|
||||
echo " SKIP TC-L-03 demo token not set (set DEMO_TOKEN to enable)"
|
||||
fi
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X POST \
|
||||
-H "$(auth_header)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"type":"IMPLEMENTATION_PLAN","content":"Aanpak: stap 1 implementeer, stap 2 test."}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")
|
||||
check "TC-L-17 IMPLEMENTATION_PLAN" 201 "$status"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X POST \
|
||||
-H "$(auth_header)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"type":"TEST_RESULT","content":"Alle tests geslaagd.","status":"PASSED"}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")
|
||||
check "TC-L-18 TEST_RESULT PASSED" 201 "$status"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X POST \
|
||||
-H "$(auth_header)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"type":"COMMIT","content":"feat: implementatie afgerond","commit_hash":"abc1234","commit_message":"feat: ST-XXX implementatie"}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")
|
||||
check "TC-L-19 COMMIT" 201 "$status"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X POST \
|
||||
-H "$(auth_header)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"type":"UNKNOWN","content":"test"}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")
|
||||
check "TC-L-07 invalid type → 400" 400 "$status"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"type":"IMPLEMENTATION_PLAN","content":"test"}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/log")
|
||||
check "TC-L-01 no token → 401" 401 "$status"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# TC-RO-10 PATCH /api/stories/:id/tasks/reorder — happy path
|
||||
# PATCH /api/stories/:id/tasks/reorder
|
||||
# =============================================================================
|
||||
|
||||
test_reorder() {
|
||||
header "PATCH /api/stories/:id/tasks/reorder"
|
||||
skip_if_empty "STORY_ID" "$STORY_ID" || return
|
||||
skip_if_empty "TASK_ID" "$TASK_ID" || return
|
||||
|
||||
if [ -z "$STORY_ID" ]; then
|
||||
echo " SKIP STORY_ID not set — fill in scripts/test-api.sh"
|
||||
return
|
||||
# TC-RO-10 happy path — single task is a valid reorder
|
||||
check "TC-RO-10 happy path → 200" 200 \
|
||||
"$(patch "{\"task_ids\":[\"$TASK_ID\"]}" \
|
||||
"$BASE_URL/api/stories/$STORY_ID/tasks/reorder")"
|
||||
|
||||
# TC-RO-06 empty task_ids
|
||||
check "TC-RO-06 empty task_ids → 400" 400 \
|
||||
"$(patch '{"task_ids":[]}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/tasks/reorder")"
|
||||
|
||||
# TC-RO-08 task ID not belonging to this story
|
||||
check "TC-RO-08 foreign task id → 400" 400 \
|
||||
"$(patch '{"task_ids":["nonexistent-task-id-xyz"]}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/tasks/reorder")"
|
||||
|
||||
# TC-RO-01 no token
|
||||
check "TC-RO-01 no token → 401" 401 \
|
||||
"$(no_auth_patch "{\"task_ids\":[\"$TASK_ID\"]}" \
|
||||
"$BASE_URL/api/stories/$STORY_ID/tasks/reorder")"
|
||||
|
||||
# TC-RO-03 demo user → 403
|
||||
if [ -n "$DEMO_TOKEN" ]; then
|
||||
check "TC-RO-03 demo user → 403" 403 \
|
||||
"$(patch_demo "{\"task_ids\":[\"$TASK_ID\"]}" \
|
||||
"$BASE_URL/api/stories/$STORY_ID/tasks/reorder")"
|
||||
else
|
||||
echo " SKIP TC-RO-03 demo token not set (set DEMO_TOKEN to enable)"
|
||||
fi
|
||||
|
||||
# Fetch current task IDs for the story first
|
||||
task_ids=$(curl -s \
|
||||
-H "$(auth_header)" \
|
||||
"$BASE_URL/api/sprints/$SPRINT_ID/tasks?limit=10" \
|
||||
| grep -o '"id":"[^"]*"' | sed 's/"id":"//;s/"//' | head -3 | tr '\n' ',' | sed 's/,$//')
|
||||
|
||||
if [ -z "$task_ids" ]; then
|
||||
echo " SKIP no tasks found for reorder test"
|
||||
return
|
||||
fi
|
||||
|
||||
ids_json=$(echo "$task_ids" | awk -F',' '{for(i=1;i<=NF;i++) printf "\"%s\"%s", $i, (i<NF?",":"")}')
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X PATCH \
|
||||
-H "$(auth_header)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"task_ids\":[$ids_json]}" \
|
||||
"$BASE_URL/api/stories/$STORY_ID/tasks/reorder")
|
||||
check "TC-RO-10 happy path" 200 "$status"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X PATCH \
|
||||
-H "$(auth_header)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"task_ids":[]}' \
|
||||
"$BASE_URL/api/stories/$STORY_ID/tasks/reorder")
|
||||
check "TC-RO-06 empty task_ids → 400" 400 "$status"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X PATCH \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"task_ids\":[$ids_json]}" \
|
||||
"$BASE_URL/api/stories/$STORY_ID/tasks/reorder")
|
||||
check "TC-RO-01 no token → 401" 401 "$status"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# TC-T-12–13 PATCH /api/tasks/:id — status updates
|
||||
# PATCH /api/tasks/:id
|
||||
# =============================================================================
|
||||
|
||||
test_tasks() {
|
||||
header "PATCH /api/tasks/:id"
|
||||
skip_if_empty "TASK_ID" "$TASK_ID" || return
|
||||
|
||||
if [ -z "$TASK_ID" ]; then
|
||||
echo " SKIP TASK_ID not set — fill in scripts/test-api.sh"
|
||||
return
|
||||
# TC-T-12 status → IN_PROGRESS
|
||||
check "TC-T-12 status → IN_PROGRESS" 200 \
|
||||
"$(patch '{"status":"IN_PROGRESS"}' "$BASE_URL/api/tasks/$TASK_ID")"
|
||||
|
||||
# TC-T-13 status → DONE
|
||||
check "TC-T-13 status → DONE" 200 \
|
||||
"$(patch '{"status":"DONE"}' "$BASE_URL/api/tasks/$TASK_ID")"
|
||||
|
||||
# Reset to TO_DO for repeatability
|
||||
patch '{"status":"TO_DO"}' "$BASE_URL/api/tasks/$TASK_ID" > /dev/null
|
||||
|
||||
# TC-T-06 invalid status
|
||||
check "TC-T-06 invalid status → 400" 400 \
|
||||
"$(patch '{"status":"INVALID"}' "$BASE_URL/api/tasks/$TASK_ID")"
|
||||
|
||||
# TC-T-07 empty body
|
||||
check "TC-T-07 empty body → 400" 400 \
|
||||
"$(patch '{}' "$BASE_URL/api/tasks/$TASK_ID")"
|
||||
|
||||
# TC-T-01 no token
|
||||
check "TC-T-01 no token → 401" 401 \
|
||||
"$(no_auth_patch '{"status":"DONE"}' "$BASE_URL/api/tasks/$TASK_ID")"
|
||||
|
||||
# TC-T-03 demo user → 403
|
||||
if [ -n "$DEMO_TOKEN" ]; then
|
||||
check "TC-T-03 demo user → 403" 403 \
|
||||
"$(patch_demo '{"status":"DONE"}' "$BASE_URL/api/tasks/$TASK_ID")"
|
||||
else
|
||||
echo " SKIP TC-T-03 demo token not set (set DEMO_TOKEN to enable)"
|
||||
fi
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X PATCH \
|
||||
-H "$(auth_header)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"status":"IN_PROGRESS"}' \
|
||||
"$BASE_URL/api/tasks/$TASK_ID")
|
||||
check "TC-T-12 status → IN_PROGRESS" 200 "$status"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X PATCH \
|
||||
-H "$(auth_header)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"status":"DONE"}' \
|
||||
"$BASE_URL/api/tasks/$TASK_ID")
|
||||
check "TC-T-13 status → DONE" 200 "$status"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X PATCH \
|
||||
-H "$(auth_header)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"status":"INVALID"}' \
|
||||
"$BASE_URL/api/tasks/$TASK_ID")
|
||||
check "TC-T-06 invalid status → 400" 400 "$status"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X PATCH \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"status":"DONE"}' \
|
||||
"$BASE_URL/api/tasks/$TASK_ID")
|
||||
check "TC-T-01 no token → 401" 401 "$status"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# TC-TD-09–10 POST /api/todos — with and without product
|
||||
# POST /api/todos
|
||||
# Note: product_id is REQUIRED by the API (z.string().min(1)).
|
||||
# TC-TD-09 ("without product_id") therefore returns 400, not 201.
|
||||
# =============================================================================
|
||||
|
||||
test_todos() {
|
||||
header "POST /api/todos"
|
||||
skip_if_empty "PRODUCT_ID" "$PRODUCT_ID" || return
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X POST \
|
||||
-H "$(auth_header)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"title":"Test todo zonder product"}' \
|
||||
"$BASE_URL/api/todos")
|
||||
check "TC-TD-09 happy path without product_id" 201 "$status"
|
||||
# TC-TD-10 happy path — product_id required
|
||||
check "TC-TD-10 happy path with product_id → 201" 201 \
|
||||
"$(post "{\"title\":\"Test todo $(date +%s)\",\"product_id\":\"$PRODUCT_ID\"}" \
|
||||
"$BASE_URL/api/todos")"
|
||||
|
||||
if [ -n "$PRODUCT_ID" ]; then
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X POST \
|
||||
-H "$(auth_header)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"title\":\"Test todo met product\",\"product_id\":\"$PRODUCT_ID\"}" \
|
||||
"$BASE_URL/api/todos")
|
||||
check "TC-TD-10 happy path with product_id" 201 "$status"
|
||||
# TC-TD-06 product_id missing → 400 (required by schema, not optional)
|
||||
check "TC-TD-06 missing product_id → 400" 400 \
|
||||
"$(post '{"title":"Todo without product"}' \
|
||||
"$BASE_URL/api/todos")"
|
||||
|
||||
# TC-TD-04 title missing
|
||||
check "TC-TD-04 missing title → 400" 400 \
|
||||
"$(post "{\"product_id\":\"$PRODUCT_ID\"}" \
|
||||
"$BASE_URL/api/todos")"
|
||||
|
||||
# TC-TD-05 empty title
|
||||
check "TC-TD-05 empty title → 400" 400 \
|
||||
"$(post "{\"title\":\"\",\"product_id\":\"$PRODUCT_ID\"}" \
|
||||
"$BASE_URL/api/todos")"
|
||||
|
||||
# TC-TD-01 no token
|
||||
check "TC-TD-01 no token → 401" 401 \
|
||||
"$(no_auth_post "{\"title\":\"Test\",\"product_id\":\"$PRODUCT_ID\"}" \
|
||||
"$BASE_URL/api/todos")"
|
||||
|
||||
# TC-TD-03 demo user → 403
|
||||
if [ -n "$DEMO_TOKEN" ]; then
|
||||
check "TC-TD-03 demo user → 403" 403 \
|
||||
"$(post_demo "{\"title\":\"Test\",\"product_id\":\"$PRODUCT_ID\"}" \
|
||||
"$BASE_URL/api/todos")"
|
||||
else
|
||||
echo " SKIP TC-TD-03 demo token not set (set DEMO_TOKEN to enable)"
|
||||
fi
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X POST \
|
||||
-H "$(auth_header)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"title":""}' \
|
||||
"$BASE_URL/api/todos")
|
||||
check "TC-TD-05 empty title → 400" 400 "$status"
|
||||
|
||||
status=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"title":"Test"}' \
|
||||
"$BASE_URL/api/todos")
|
||||
check "TC-TD-01 no token → 401" 401 "$status"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Run all tests
|
||||
# Entry point
|
||||
# =============================================================================
|
||||
|
||||
echo "============================================================"
|
||||
echo " Scrum4Me API Test Suite"
|
||||
echo " Base URL : $BASE_URL"
|
||||
echo " Token : ${TOKEN:0:8}... (lars)"
|
||||
[ -n "$DEMO_TOKEN" ] && echo " Demo : ${DEMO_TOKEN:0:8}... (403 tests active)"
|
||||
echo "============================================================"
|
||||
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo ""
|
||||
echo "ERROR: TOKEN is not set. Edit scripts/test-api.sh and add your API token."
|
||||
echo "ERROR: TOKEN is not set. See scripts/README.md."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue