#!/usr/bin/env bash # End-to-end test: logs in, submits the post form, verifies entry is created on disk. # Requires GRAV_TEST_USER and GRAV_TEST_PASS (set in .env or environment). # Cleans up the test entry after the test. set -euo pipefail BASE_URL="${GRAV_BASE_URL:-http://localhost:8081}" USER="${GRAV_TEST_USER:-}" PASS="${GRAV_TEST_PASS:-}" TRACKER="user/pages/01.trips/japan-korea-2026/01.dailies" COOKIE_JAR="$(mktemp /tmp/grav-test-cookies.XXXXXX)" PASS_COUNT=0 FAIL_COUNT=0 TEST_SLUG="" cleanup() { rm -f "$COOKIE_JAR" if [ -n "$TEST_SLUG" ] && [ -d "$TRACKER/$TEST_SLUG" ]; then # Entry files are created by www-data inside Docker; use docker exec to remove if docker exec intotheeast_grav rm -rf "/var/www/html/$TRACKER/$TEST_SLUG" 2>/dev/null; then echo " [cleanup] Removed test entry: $TEST_SLUG" else rm -rf "$TRACKER/$TEST_SLUG" 2>/dev/null || \ echo " [cleanup] Warning: could not remove $TEST_SLUG (permission denied — remove manually)" fi fi } trap cleanup EXIT ok() { echo " ✓ $1"; PASS_COUNT=$((PASS_COUNT+1)); } fail() { echo " ✗ $1"; FAIL_COUNT=$((FAIL_COUNT+1)); } die() { echo ""; echo "FATAL: $1"; exit 1; } echo "" echo "Post form integration test — $BASE_URL" echo "────────────────────────────────────────" [ -n "$USER" ] || die "GRAV_TEST_USER not set. Add it to .env" [ -n "$PASS" ] || die "GRAV_TEST_PASS not set. Add it to .env" # ── Step 1: get login page + nonce ─────────────────────────────────────────── LOGIN_HTML=$(curl -sf -c "$COOKIE_JAR" -b "$COOKIE_JAR" "$BASE_URL/login") \ || die "Could not reach $BASE_URL/login" LOGIN_NONCE=$(echo "$LOGIN_HTML" | grep -o 'name="login-form-nonce" value="[^"]*"' | head -1 | sed 's/.*value="\([^"]*\)".*/\1/') [ -n "$LOGIN_NONCE" ] || die "Could not extract login form nonce — is the site running?" # ── Step 2: log in ─────────────────────────────────────────────────────────── LOGIN_STATUS=$(curl -sf -o /dev/null -w "%{http_code}" \ -c "$COOKIE_JAR" -b "$COOKIE_JAR" \ -L \ -d "username=${USER}&password=${PASS}&login-form-nonce=${LOGIN_NONCE}&task=login.login" \ "$BASE_URL/login") # After login, fetch /post and verify we see the post form (not the login form) # /post returns 200 for both auth and unauth users — check for form-nonce to confirm login POST_CHECK_HTML=$(curl -sf -c "$COOKIE_JAR" -b "$COOKIE_JAR" "$BASE_URL/post") \ || die "Could not reach $BASE_URL/post" POST_STATUS=$(echo "$POST_CHECK_HTML" | grep -c 'name="form-nonce"' || true) [ "$POST_STATUS" -gt 0 ] && ok "Login succeeded and /post is accessible" \ || die "Login failed (post form not visible) — check GRAV_TEST_USER / GRAV_TEST_PASS" # ── Step 3: extract post form nonce from already-fetched HTML ──────────────── POST_HTML="$POST_CHECK_HTML" POST_NONCE=$(echo "$POST_HTML" | grep -o 'name="form-nonce" value="[^"]*"' | head -1 | sed 's/.*value="\([^"]*\)".*/\1/') [ -n "$POST_NONCE" ] || die "Could not extract post form nonce" ok "Post form loaded and nonce extracted" # ── Step 4: submit test entry ──────────────────────────────────────────────── TEST_TITLE="Automated Test Entry" TEST_DATE=$(date "+%Y-%m-%d %H:%M") TEST_SLUG_EXPECTED=$(date "+%Y-%m-%d-%H%M")-automated-test-entry SUBMIT_BODY=$(curl -sf \ -c "$COOKIE_JAR" -b "$COOKIE_JAR" \ -d "data[title]=${TEST_TITLE}" \ -d "data[date]=${TEST_DATE}" \ -d "data[content]=This+is+an+automated+test+entry.+Safe+to+delete." \ -d "data[location_city]=Test+City" \ -d "data[location_country]=Test+Country" \ -d "form-nonce=${POST_NONCE}" \ -d "task=process" \ "$BASE_URL/post") ok "Form submitted" # ── Step 5: verify entry exists on disk ───────────────────────────────────── sleep 1 # give Grav a moment to write the file # Find an entry containing the test title — search all .md and .en.md files # add-page-by-form may produce date-based slugs in various formats ENTRY_FILE=$(grep -rl "$TEST_TITLE" "$TRACKER" --include="*.md" 2>/dev/null | head -1) if [ -n "$ENTRY_FILE" ]; then TEST_SLUG=$(basename "$(dirname "$ENTRY_FILE")") ok "Entry created on disk: $TEST_SLUG" # Verify file name is entry.md or entry.en.md (template-named file) ENTRY_BASENAME=$(basename "$ENTRY_FILE") if [ "$ENTRY_BASENAME" = "entry.md" ] || [ "$ENTRY_BASENAME" = "entry.en.md" ]; then ok "Entry file exists: $ENTRY_BASENAME" else fail "Entry file has unexpected name: $ENTRY_BASENAME (expected entry.md or entry.en.md)" fi # Verify the title is in the frontmatter if grep -q "$TEST_TITLE" "$ENTRY_FILE"; then ok "Title appears in entry frontmatter" else fail "Title not found in $ENTRY_BASENAME — frontmatter may be malformed" fi else fail "No entry created on disk — form processing failed silently" echo " Searched $TRACKER for files containing: $TEST_TITLE" fi # ── Result ─────────────────────────────────────────────────────────────────── echo "────────────────────────────────────────" echo " $PASS_COUNT passed, $FAIL_COUNT failed" echo "" [ $FAIL_COUNT -eq 0 ]