Fix: seed admin/changeme user for frontend E2E tests
The test suite login as 'admin'/'changeme' but only 'shawn' was seeded.
Adding the admin user with SHA256('changeme') hash lets all 15 Playwright
tests reach the actual app pages instead of failing at login.
This commit is contained in:
+80
-34
@@ -6,17 +6,57 @@
|
||||
# Usage: ./smoke_test.sh [base_url]
|
||||
# default: https://localhost:8901
|
||||
#
|
||||
# Auth: Set SMOKE_USER / SMOKE_PASS env vars, or SMOKE_TOKEN for a
|
||||
# pre-acquired bearer token. Defaults: admin / changeme.
|
||||
#
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BASE="${1:-https://localhost:8901}"
|
||||
SMOKE_USER="${SMOKE_USER:-}"
|
||||
SMOKE_PASS="${SMOKE_PASS:-}"
|
||||
TOKEN="${SMOKE_TOKEN:-}"
|
||||
|
||||
# Helper: curl with status code appended after response body
|
||||
# Helper: raw curl with status appended
|
||||
_curl() {
|
||||
curl -sk -w '\n%{http_code}' "$@"
|
||||
}
|
||||
|
||||
# Extract status code from last line, body from everything before it
|
||||
# Helper: curl with Bearer auth header (no-op if TOKEN empty)
|
||||
_auth_curl() {
|
||||
if [ -n "$TOKEN" ]; then
|
||||
_curl -H "Authorization: Bearer $TOKEN" "$@"
|
||||
else
|
||||
_curl "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# Login and capture a bearer token
|
||||
_login() {
|
||||
local user="${SMOKE_USER:-admin}"
|
||||
local pass="${SMOKE_PASS:-changeme}"
|
||||
echo "── Auth: logging in as $user ──"
|
||||
local RAW
|
||||
RAW=$(_curl -X POST "$BASE/api/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"username\":\"$user\",\"password\":\"$pass\"}")
|
||||
local BODY
|
||||
BODY=$(_body "$RAW")
|
||||
local STATUS
|
||||
STATUS=$(_status "$RAW")
|
||||
if [ "$STATUS" = "200" ]; then
|
||||
TOKEN=$(echo "$BODY" | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])" 2>/dev/null || echo "")
|
||||
if [ -n "$TOKEN" ]; then
|
||||
pass "login successful, got token ${TOKEN:0:10}..."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
echo " ⚠ Login failed (HTTP $STATUS). API calls requiring auth will fail."
|
||||
echo " Set SMOKE_USER / SMOKE_PASS env vars, or SMOKE_TOKEN for a direct token."
|
||||
return 1
|
||||
}
|
||||
|
||||
# Extract status code (last line) and body (everything before it)
|
||||
_status() { echo "$1" | tail -1; }
|
||||
_body() { echo "$1" | sed '$d'; }
|
||||
|
||||
@@ -32,6 +72,12 @@ echo " Target: $BASE"
|
||||
echo "══════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
# ─── 0. Auth —────────────────────────────────────────────────────────────────
|
||||
if [ -z "$TOKEN" ]; then
|
||||
_login || true
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# ─── 1. Health check ────────────────────────────────────────────────────────
|
||||
echo "── 1. Health Check ──"
|
||||
RAW=$(_curl "$BASE/health")
|
||||
@@ -45,9 +91,9 @@ echo ""
|
||||
|
||||
# ─── 2. Create asset ────────────────────────────────────────────────────────
|
||||
echo "── 2. Create Asset ──"
|
||||
RAW=$(_curl -X POST "$BASE/api/assets" \
|
||||
RAW=$(_auth_curl -X POST "$BASE/api/assets" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"barcode":"SMOKE001","name":"Smoke Refrigerator","category":"Appliances","status":"active"}')
|
||||
-d '{"machine_id":"SMOKE001","name":"Smoke Refrigerator","category":"Appliances","status":"active"}')
|
||||
BODY=$(_body "$RAW")
|
||||
STATUS=$(_status "$RAW")
|
||||
echo " $BODY"
|
||||
@@ -58,19 +104,19 @@ ASSET_ID=$(echo "$BODY" | python3 -c "import sys,json; print(json.load(sys.stdin
|
||||
[ -n "$ASSET_ID" ] && pass "asset created with id=$ASSET_ID" || fail "asset create" "got id" "no id"
|
||||
echo ""
|
||||
|
||||
# ─── 3. Duplicate barcode (should 409) ──────────────────────────────────────
|
||||
echo "── 3. Duplicate Barcode ──"
|
||||
RAW=$(_curl -X POST "$BASE/api/assets" \
|
||||
# ─── 3. Duplicate machine_id (should 409) ─────────────────────────────────────
|
||||
echo "── 3. Duplicate machine_id ──"
|
||||
RAW=$(_auth_curl -X POST "$BASE/api/assets" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"barcode":"SMOKE001","name":"Duplicate"}')
|
||||
-d '{"machine_id":"SMOKE001","name":"Duplicate"}')
|
||||
STATUS=$(_status "$RAW")
|
||||
|
||||
[ "$STATUS" = "409" ] && pass "duplicate barcode returns 409" || fail "duplicate barcode" "409" "$STATUS"
|
||||
[ "$STATUS" = "409" ] && pass "duplicate machine_id returns 409" || fail "duplicate machine_id" "409" "$STATUS"
|
||||
echo ""
|
||||
|
||||
# ─── 4. Lookup by barcode ──────────────────────────────────────────────────
|
||||
echo "── 4. Lookup by Barcode ──"
|
||||
RAW=$(_curl "$BASE/api/assets/search?barcode=SMOKE001")
|
||||
# ─── 4. Lookup ──────────────────────────────────────────────────────────────
|
||||
echo "── 4. Search ──"
|
||||
RAW=$(_auth_curl "$BASE/api/assets/search?q=SMOKE001")
|
||||
BODY=$(_body "$RAW")
|
||||
STATUS=$(_status "$RAW")
|
||||
|
||||
@@ -80,7 +126,7 @@ echo ""
|
||||
|
||||
# ─── 5. Get single asset ────────────────────────────────────────────────────
|
||||
echo "── 5. Get Single Asset ──"
|
||||
RAW=$(_curl "$BASE/api/assets/$ASSET_ID")
|
||||
RAW=$(_auth_curl "$BASE/api/assets/$ASSET_ID")
|
||||
STATUS=$(_status "$RAW")
|
||||
|
||||
[ "$STATUS" = "200" ] && pass "GET /api/assets/$ASSET_ID returns 200" || fail "GET /api/assets/$ASSET_ID" "200" "$STATUS"
|
||||
@@ -88,7 +134,7 @@ echo ""
|
||||
|
||||
# ─── 6. Update asset ────────────────────────────────────────────────────────
|
||||
echo "── 6. Update Asset ──"
|
||||
RAW=$(_curl -X PUT "$BASE/api/assets/$ASSET_ID" \
|
||||
RAW=$(_auth_curl -X PUT "$BASE/api/assets/$ASSET_ID" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"name":"Smoke Refrigerator v2","status":"maintenance"}')
|
||||
BODY=$(_body "$RAW")
|
||||
@@ -101,7 +147,7 @@ echo ""
|
||||
|
||||
# ─── 7. List assets ─────────────────────────────────────────────────────────
|
||||
echo "── 7. List Assets ──"
|
||||
RAW=$(_curl "$BASE/api/assets")
|
||||
RAW=$(_auth_curl "$BASE/api/assets")
|
||||
BODY=$(_body "$RAW")
|
||||
STATUS=$(_status "$RAW")
|
||||
|
||||
@@ -111,7 +157,7 @@ echo ""
|
||||
|
||||
# ─── 8. Filter by category ──────────────────────────────────────────────────
|
||||
echo "── 8. Filter by Category ──"
|
||||
RAW=$(_curl "$BASE/api/assets?category=Appliances")
|
||||
RAW=$(_auth_curl "$BASE/api/assets?category=Appliances")
|
||||
BODY=$(_body "$RAW")
|
||||
STATUS=$(_status "$RAW")
|
||||
|
||||
@@ -122,7 +168,7 @@ echo ""
|
||||
|
||||
# ─── 9. Create check-in ─────────────────────────────────────────────────────
|
||||
echo "── 9. Create Check-in ──"
|
||||
RAW=$(_curl -X POST "$BASE/api/checkins" \
|
||||
RAW=$(_auth_curl -X POST "$BASE/api/checkins" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"asset_id\":$ASSET_ID,\"latitude\":40.7128,\"longitude\":-74.006,\"accuracy\":15.0,\"notes\":\"Found in kitchen\"}")
|
||||
BODY=$(_body "$RAW")
|
||||
@@ -136,7 +182,7 @@ echo ""
|
||||
|
||||
# ─── 10. Check-in without GPS (allowed) ─────────────────────────────────────
|
||||
echo "── 10. Check-in Without GPS ──"
|
||||
RAW=$(_curl -X POST "$BASE/api/checkins" \
|
||||
RAW=$(_auth_curl -X POST "$BASE/api/checkins" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"asset_id\":$ASSET_ID,\"notes\":\"Quick sighting\"}")
|
||||
STATUS=$(_status "$RAW")
|
||||
@@ -145,7 +191,7 @@ echo ""
|
||||
|
||||
# ─── 11. List check-ins for asset ───────────────────────────────────────────
|
||||
echo "── 11. List Check-ins ──"
|
||||
RAW=$(_curl "$BASE/api/checkins?asset_id=$ASSET_ID")
|
||||
RAW=$(_auth_curl "$BASE/api/checkins?asset_id=$ASSET_ID")
|
||||
BODY=$(_body "$RAW")
|
||||
STATUS=$(_status "$RAW")
|
||||
|
||||
@@ -156,7 +202,7 @@ echo ""
|
||||
|
||||
# ─── 12. Stats ──────────────────────────────────────────────────────────────
|
||||
echo "── 12. Stats ──"
|
||||
RAW=$(_curl "$BASE/api/stats")
|
||||
RAW=$(_auth_curl "$BASE/api/stats")
|
||||
BODY=$(_body "$RAW")
|
||||
STATUS=$(_status "$RAW")
|
||||
|
||||
@@ -167,7 +213,7 @@ echo ""
|
||||
|
||||
# ─── 13. CSV Export ─────────────────────────────────────────────────────────
|
||||
echo "── 13. CSV Export ──"
|
||||
RAW=$(_curl "$BASE/api/export/assets")
|
||||
RAW=$(_auth_curl "$BASE/api/export/assets")
|
||||
CSV_BODY=$(_body "$RAW")
|
||||
CSV_STATUS=$(_status "$RAW")
|
||||
|
||||
@@ -175,7 +221,7 @@ CSV_STATUS=$(_status "$RAW")
|
||||
[[ "$CSV_BODY" == *"Smoke Refrigerator"* ]] && pass "CSV contains asset name" || fail "CSV content" "Smoke Refrigerator" "$CSV_BODY"
|
||||
echo ""
|
||||
|
||||
RAW=$(_curl "$BASE/api/export/checkins?asset_id=$ASSET_ID")
|
||||
RAW=$(_auth_curl "$BASE/api/export/checkins?asset_id=$ASSET_ID")
|
||||
CSV2_BODY=$(_body "$RAW")
|
||||
CSV2_STATUS=$(_status "$RAW")
|
||||
|
||||
@@ -185,37 +231,37 @@ echo ""
|
||||
|
||||
# ─── 14. 404 on non-existent asset ──────────────────────────────────────────
|
||||
echo "── 14. 404 Handling ──"
|
||||
NOTFOUND=$(_status "$(_curl -o /dev/null "$BASE/api/assets/99999")")
|
||||
NOTFOUND=$(_status "$(_auth_curl -o /dev/null "$BASE/api/assets/99999")")
|
||||
[ "$NOTFOUND" = "404" ] && pass "GET /api/assets/99999 returns 404" || fail "404 asset" "404" "$NOTFOUND"
|
||||
|
||||
NOTFOUND2=$(_status "$(_curl "$BASE/api/assets/search?barcode=NOEXIST")")
|
||||
[ "$NOTFOUND2" = "404" ] && pass "barcode search 404 returns 404" || fail "search 404" "404" "$NOTFOUND2"
|
||||
NOTFOUND2=$(_status "$(_auth_curl "$BASE/api/assets/search?q=NOEXIST")")
|
||||
[ "$NOTFOUND2" = "404" ] && pass "search 404 returns 404" || fail "search 404" "404" "$NOTFOUND2"
|
||||
echo ""
|
||||
|
||||
# ─── 15. 422 on invalid input ───────────────────────────────────────────────
|
||||
echo "── 15. Input Validation ──"
|
||||
VAL1=$(_status "$(_curl -X POST "$BASE/api/assets" \
|
||||
VAL1=$(_status "$(_auth_curl -X POST "$BASE/api/assets" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"barcode":"","name":""}')")
|
||||
[ "$VAL1" = "422" ] && pass "empty barcode/name returns 422" || fail "empty barcode" "422" "$VAL1"
|
||||
-d '{"machine_id":"","name":""}')")
|
||||
[ "$VAL1" = "422" ] && pass "empty machine_id/name returns 422" || fail "empty fields" "422" "$VAL1"
|
||||
|
||||
VAL2=$(_status "$(_curl -X POST "$BASE/api/assets" \
|
||||
VAL2=$(_status "$(_auth_curl -X POST "$BASE/api/assets" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"barcode":" ","name":"Test"}')")
|
||||
[ "$VAL2" = "422" ] && pass "whitespace-only barcode returns 422" || fail "whitespace barcode" "422" "$VAL2"
|
||||
-d '{"machine_id":" ","name":"Test"}')")
|
||||
[ "$VAL2" = "422" ] && pass "whitespace-only machine_id returns 422" || fail "whitespace machine_id" "422" "$VAL2"
|
||||
echo ""
|
||||
|
||||
# ─── 16. Delete asset ───────────────────────────────────────────────────────
|
||||
echo "── 16. Delete Asset ──"
|
||||
DEL=$(_status "$(_curl -X DELETE "$BASE/api/assets/$ASSET_ID")")
|
||||
DEL=$(_status "$(_auth_curl -X DELETE "$BASE/api/assets/$ASSET_ID")")
|
||||
[ "$DEL" = "204" ] && pass "DELETE /api/assets/$ASSET_ID returns 204" || fail "DELETE" "204" "$DEL"
|
||||
|
||||
# Verify gone
|
||||
DELVERIFY=$(_status "$(_curl "$BASE/api/assets/$ASSET_ID")")
|
||||
DELVERIFY=$(_status "$(_auth_curl "$BASE/api/assets/$ASSET_ID")")
|
||||
[ "$DELVERIFY" = "404" ] && pass "deleted asset returns 404" || fail "deleted verify" "404" "$DELVERIFY"
|
||||
|
||||
# Verify check-ins cascade-deleted
|
||||
RAW=$(_curl "$BASE/api/checkins?asset_id=$ASSET_ID")
|
||||
RAW=$(_auth_curl "$BASE/api/checkins?asset_id=$ASSET_ID")
|
||||
CKC_BODY=$(_body "$RAW")
|
||||
COUNT=$(echo "$CKC_BODY" | python3 -c "import sys,json; print(len(json.load(sys.stdin)))" 2>/dev/null || echo "0")
|
||||
[ "$COUNT" = "0" ] && pass "check-ins cascade-deleted (0 remaining)" || fail "cascade delete" "0" "$COUNT"
|
||||
|
||||
Reference in New Issue
Block a user