gantt-board/scripts/tests/refactor-cli-api.sh

286 lines
10 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
TMP_DIR="$(mktemp -d)"
MOCK_BIN="$TMP_DIR/mockbin"
MOCK_LOG="$TMP_DIR/mock-curl.log"
cleanup() {
rm -rf "$TMP_DIR"
}
trap cleanup EXIT
mkdir -p "$MOCK_BIN"
touch "$MOCK_LOG"
cat > "$MOCK_BIN/curl" <<'MOCK_CURL'
#!/bin/bash
set -euo pipefail
method="GET"
url=""
data=""
cookie_out=""
while [[ $# -gt 0 ]]; do
case "$1" in
-X)
method="$2"
shift 2
;;
--data|-d)
data="$2"
shift 2
;;
-c)
cookie_out="$2"
shift 2
;;
-b|-H|-w)
shift 2
;;
-s|-sS)
shift
;;
http://*|https://*)
url="$1"
shift
;;
*)
shift
;;
esac
done
if [[ -n "$cookie_out" ]]; then
mkdir -p "$(dirname "$cookie_out")"
touch "$cookie_out"
fi
echo "${method} ${url} ${data}" >> "${MOCK_CURL_LOG:?}"
respond() {
printf '%s\n%s\n' "$1" "$2"
}
case "${method} ${url}" in
"GET http://localhost:3000/api/projects")
respond '{"projects":[{"id":"p1","name":"Proj","description":"Demo","color":"#3b82f6"}]}' 200
;;
"GET http://localhost:3000/api/projects/p1")
respond '{"project":{"id":"p1","name":"Proj","description":"Demo","color":"#3b82f6"}}' 200
;;
"POST http://localhost:3000/api/projects")
respond '{"success":true,"project":{"id":"p2","name":"New Proj"}}' 200
;;
"PATCH http://localhost:3000/api/projects")
respond '{"success":true}' 200
;;
"DELETE http://localhost:3000/api/projects")
respond '{"success":true}' 200
;;
"GET http://localhost:3000/api/auth/users")
respond '{"users":[{"id":"u1","name":"Max","email":"max@example.com"}]}' 200
;;
"POST http://localhost:3000/api/auth/login")
respond '{"success":true}' 200
;;
"POST http://localhost:3000/api/auth/logout")
respond '{"success":true}' 200
;;
"GET http://localhost:3000/api/auth/session")
respond '{"authenticated":true}' 200
;;
"POST http://localhost:3000/api/auth/register")
respond '{"success":true}' 200
;;
"POST http://localhost:3000/api/auth/forgot-password")
respond '{"success":true}' 200
;;
"POST http://localhost:3000/api/auth/reset-password")
respond '{"success":true}' 200
;;
"PATCH http://localhost:3000/api/auth/account")
respond '{"success":true}' 200
;;
"GET http://localhost:3000/api/sprints"|\
"GET http://localhost:3000/api/sprints?inProgress=true&onDate="*)
respond '{"sprints":[{"id":"s1","name":"Sprint 1","status":"active","startDate":"2026-02-20","endDate":"2026-03-01"}]}' 200
;;
"GET http://localhost:3000/api/sprints/s1")
respond '{"sprint":{"id":"s1","name":"Sprint 1","status":"active","startDate":"2026-02-20","endDate":"2026-03-01"}}' 200
;;
"POST http://localhost:3000/api/sprints")
respond '{"success":true,"sprint":{"id":"s2","name":"Sprint 2"}}' 200
;;
"PATCH http://localhost:3000/api/sprints")
respond '{"success":true}' 200
;;
"DELETE http://localhost:3000/api/sprints")
respond '{"success":true}' 200
;;
"GET http://localhost:3000/api/sprints/current")
respond '{"sprint":{"id":"s1","name":"Sprint 1"}}' 200
;;
"POST http://localhost:3000/api/sprints/close")
respond '{"success":true}' 200
;;
"GET http://localhost:3000/api/tasks"|\
"GET http://localhost:3000/api/tasks?scope=all")
respond '{"tasks":[{"id":"t1","title":"Demo Task","status":"open","priority":"medium","type":"task","projectId":"p1","assigneeId":"u1","sprintId":"s1","comments":[],"tags":[],"attachments":[]}]}' 200
;;
"GET http://localhost:3000/api/tasks?taskId=t1&include=detail")
respond '{"tasks":[{"id":"t1","title":"Demo Task","status":"open","priority":"medium","type":"task","projectId":"p1","assigneeId":"u1","sprintId":"s1","comments":[],"tags":[],"attachments":[]}]}' 200
;;
"POST http://localhost:3000/api/tasks")
respond '{"success":true,"task":{"id":"t1"}}' 200
;;
"DELETE http://localhost:3000/api/tasks")
respond '{"success":true}' 200
;;
"POST http://localhost:3000/api/tasks/natural")
respond '{"success":true,"task":{"id":"t2","title":"Natural"}}' 200
;;
"GET http://localhost:3000/api/debug")
respond '{"ok":true}' 200
;;
*)
respond "{\"error\":\"Unhandled mock request: ${method} ${url}\"}" 500
;;
esac
MOCK_CURL
chmod +x "$MOCK_BIN/curl"
assert_log_contains() {
local expected="$1"
if ! grep -F "$expected" "$MOCK_LOG" >/dev/null 2>&1; then
echo "Expected mock curl log to contain: $expected" >&2
echo "Actual log:" >&2
cat "$MOCK_LOG" >&2
exit 1
fi
}
export HOME="$TMP_DIR/home"
export PATH="$MOCK_BIN:$PATH"
export MOCK_CURL_LOG="$MOCK_LOG"
export API_URL="http://localhost:3000/api"
ATTACH_FILE="$TMP_DIR/attachment.txt"
BULK_FILE="$TMP_DIR/tasks.json"
cat > "$ATTACH_FILE" <<'ATTACH_EOF'
refactor-test
ATTACH_EOF
cat > "$BULK_FILE" <<'BULK_EOF'
[
{
"title": "Bulk task",
"project": "Proj",
"assignee": "Max",
"sprint": "Sprint 1"
}
]
BULK_EOF
"$ROOT_DIR/scripts/task.sh" list --json >/dev/null
"$ROOT_DIR/scripts/task.sh" get t1 >/dev/null
"$ROOT_DIR/scripts/task.sh" current-sprint >/dev/null
"$ROOT_DIR/scripts/task.sh" create --title "API Task" --project "Proj" --assignee "Max" --sprint current --status todo --priority high >/dev/null
"$ROOT_DIR/scripts/task.sh" update t1 --status done --tags "api,refactor" --add-comment "done" >/dev/null
"$ROOT_DIR/scripts/task.sh" delete t1 >/dev/null
"$ROOT_DIR/scripts/task.sh" bulk-create "$BULK_FILE" >/dev/null
"$ROOT_DIR/scripts/project.sh" list --json >/dev/null
"$ROOT_DIR/scripts/project.sh" get "Proj" >/dev/null
"$ROOT_DIR/scripts/project.sh" create --name "New Proj" --description "Desc" --color "#ffffff" >/dev/null
"$ROOT_DIR/scripts/project.sh" update "Proj" --name "Renamed Proj" >/dev/null
"$ROOT_DIR/scripts/project.sh" delete "Proj" >/dev/null
"$ROOT_DIR/scripts/sprint.sh" list --json >/dev/null
"$ROOT_DIR/scripts/sprint.sh" list --active --json >/dev/null
"$ROOT_DIR/scripts/sprint.sh" get "Sprint 1" >/dev/null
"$ROOT_DIR/scripts/sprint.sh" create --name "Sprint 2" --goal "Ship" --start-date "2026-02-24" --end-date "2026-03-03" >/dev/null
"$ROOT_DIR/scripts/sprint.sh" update "Sprint 1" --status completed >/dev/null
"$ROOT_DIR/scripts/sprint.sh" close "Sprint 1" >/dev/null
"$ROOT_DIR/scripts/sprint.sh" delete "Sprint 1" >/dev/null
"$ROOT_DIR/scripts/gantt.sh" task list open >/dev/null
"$ROOT_DIR/scripts/gantt.sh" task get t1 >/dev/null
"$ROOT_DIR/scripts/gantt.sh" task create "From wrapper" todo high p1 >/dev/null
"$ROOT_DIR/scripts/gantt.sh" task natural "Create natural task" >/dev/null
"$ROOT_DIR/scripts/gantt.sh" task update t1 status done >/dev/null
"$ROOT_DIR/scripts/gantt.sh" task comment t1 "Looks good" >/dev/null
"$ROOT_DIR/scripts/gantt.sh" task attach t1 "$ATTACH_FILE" >/dev/null
"$ROOT_DIR/scripts/gantt.sh" task delete t1 >/dev/null
"$ROOT_DIR/scripts/gantt.sh" project list >/dev/null
"$ROOT_DIR/scripts/gantt.sh" project get p1 >/dev/null
"$ROOT_DIR/scripts/gantt.sh" project create "Wrapper Project" "Desc" "#111111" >/dev/null
"$ROOT_DIR/scripts/gantt.sh" project update p1 name "Renamed" >/dev/null
"$ROOT_DIR/scripts/gantt.sh" project delete p1 >/dev/null
"$ROOT_DIR/scripts/gantt.sh" sprint list >/dev/null
"$ROOT_DIR/scripts/gantt.sh" sprint get s1 >/dev/null
"$ROOT_DIR/scripts/gantt.sh" sprint create "Wrapper Sprint" "2026-02-24" "2026-03-03" "Goal" >/dev/null
"$ROOT_DIR/scripts/gantt.sh" sprint update s1 status completed >/dev/null
"$ROOT_DIR/scripts/gantt.sh" sprint close s1 >/dev/null
"$ROOT_DIR/scripts/gantt.sh" sprint delete s1 >/dev/null
"$ROOT_DIR/scripts/gantt.sh" auth login "max@example.com" "secret" >/dev/null
"$ROOT_DIR/scripts/gantt.sh" auth logout >/dev/null
"$ROOT_DIR/scripts/gantt.sh" auth session >/dev/null
"$ROOT_DIR/scripts/gantt.sh" auth register "new@example.com" "secret" "New User" >/dev/null
"$ROOT_DIR/scripts/gantt.sh" auth forgot-password "new@example.com" >/dev/null
"$ROOT_DIR/scripts/gantt.sh" auth reset-password "tok123" "newsecret" >/dev/null
"$ROOT_DIR/scripts/gantt.sh" auth account name "Renamed User" >/dev/null
"$ROOT_DIR/scripts/gantt.sh" auth users >/dev/null
"$ROOT_DIR/scripts/gantt.sh" debug >/dev/null
if [[ ! -f "$HOME/.config/gantt-board/cookies.txt" ]]; then
echo "Expected cookie file to be created at $HOME/.config/gantt-board/cookies.txt" >&2
exit 1
fi
assert_log_contains "GET http://localhost:3000/api/projects"
assert_log_contains "POST http://localhost:3000/api/projects"
assert_log_contains "PATCH http://localhost:3000/api/projects"
assert_log_contains "DELETE http://localhost:3000/api/projects"
assert_log_contains "GET http://localhost:3000/api/projects/p1"
assert_log_contains "GET http://localhost:3000/api/sprints"
assert_log_contains "GET http://localhost:3000/api/sprints?inProgress=true&onDate="
assert_log_contains "GET http://localhost:3000/api/sprints/s1"
assert_log_contains "GET http://localhost:3000/api/sprints/current"
assert_log_contains "POST http://localhost:3000/api/sprints"
assert_log_contains "PATCH http://localhost:3000/api/sprints"
assert_log_contains "POST http://localhost:3000/api/sprints/close"
assert_log_contains "DELETE http://localhost:3000/api/sprints"
assert_log_contains "GET http://localhost:3000/api/tasks"
assert_log_contains "GET http://localhost:3000/api/tasks?scope=all"
assert_log_contains "GET http://localhost:3000/api/tasks?taskId=t1&include=detail"
assert_log_contains "POST http://localhost:3000/api/tasks"
assert_log_contains "DELETE http://localhost:3000/api/tasks"
assert_log_contains "POST http://localhost:3000/api/tasks/natural"
assert_log_contains "POST http://localhost:3000/api/auth/login"
assert_log_contains "POST http://localhost:3000/api/auth/logout"
assert_log_contains "GET http://localhost:3000/api/auth/session"
assert_log_contains "POST http://localhost:3000/api/auth/register"
assert_log_contains "POST http://localhost:3000/api/auth/forgot-password"
assert_log_contains "POST http://localhost:3000/api/auth/reset-password"
assert_log_contains "PATCH http://localhost:3000/api/auth/account"
assert_log_contains "GET http://localhost:3000/api/auth/users"
assert_log_contains "GET http://localhost:3000/api/debug"
if rg -n --hidden -S "rest/v1|SUPABASE_URL|SERVICE_KEY|ANON_KEY|qnatchrjlpehiijwtreh" "$ROOT_DIR/scripts" --glob "!scripts/tests/*" >/dev/null 2>&1; then
echo "Direct Supabase references were found in scripts/" >&2
rg -n --hidden -S "rest/v1|SUPABASE_URL|SERVICE_KEY|ANON_KEY|qnatchrjlpehiijwtreh" "$ROOT_DIR/scripts" --glob "!scripts/tests/*" >&2
exit 1
fi
echo "CLI API passthrough tests passed"