test: add form config validator and HTTP integration test
test-config: static YAML validator for post-form.md — checks that the add-page-by-form action name, pageconfig/pagefrontmatter blocks, and all required fields are correctly wired. Fast, no server needed. Catches the class of bug that caused silent post failures. test-post: end-to-end HTTP test — logs in, submits the form, verifies an entry.md was created on disk, then cleans up. Requires GRAV_TEST_USER and GRAV_TEST_PASS in .env (see .env.example). make test-config # fast, no credentials needed make test-post # full e2e, needs .env credentials make test # both Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,3 +19,8 @@ MAIN_REPO=https://gitea.example.com/org/travel-blog-intotheeast.git
|
|||||||
GITEA_HOST=gitea.example.com
|
GITEA_HOST=gitea.example.com
|
||||||
GITEA_USER=deploy-user
|
GITEA_USER=deploy-user
|
||||||
GITEA_TOKEN=your-gitea-personal-access-token
|
GITEA_TOKEN=your-gitea-personal-access-token
|
||||||
|
|
||||||
|
# Test credentials — used by 'make test-post' (must be a valid Grav site login user)
|
||||||
|
GRAV_TEST_USER=mischa
|
||||||
|
GRAV_TEST_PASS=your-grav-password
|
||||||
|
GRAV_BASE_URL=http://localhost:8081
|
||||||
|
|||||||
@@ -6,6 +6,16 @@ SSH := ssh -p $(REMOTE_PORT) $(REMOTE_USER)@$(REMOTE_HOST)
|
|||||||
WEBROOT ?= $(REMOTE_HOME)/public_html
|
WEBROOT ?= $(REMOTE_HOME)/public_html
|
||||||
SITE_CONFIG_DIR ?= $(REMOTE_HOME)/site-config
|
SITE_CONFIG_DIR ?= $(REMOTE_HOME)/site-config
|
||||||
|
|
||||||
|
# ── Tests ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
test-config:
|
||||||
|
@bash scripts/test-form-config.sh
|
||||||
|
|
||||||
|
test-post:
|
||||||
|
@bash scripts/test-post.sh
|
||||||
|
|
||||||
|
test: test-config test-post
|
||||||
|
|
||||||
# ── Local dev ──────────────────────────────────────────────────────────────────
|
# ── Local dev ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
start:
|
start:
|
||||||
|
|||||||
Executable
+56
@@ -0,0 +1,56 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Validates that post-form.md is wired correctly for the add-page-by-form plugin.
|
||||||
|
# Fast, no server needed. Catches the class of bug that caused silent post failures.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
FORM="user/pages/02.post/post-form.md"
|
||||||
|
PASS=0
|
||||||
|
FAIL=0
|
||||||
|
ERRORS=()
|
||||||
|
|
||||||
|
ok() { echo " ✓ $1"; PASS=$((PASS+1)); }
|
||||||
|
fail() { echo " ✗ $1"; FAIL=$((FAIL+1)); ERRORS+=("$1"); }
|
||||||
|
|
||||||
|
check_grep() {
|
||||||
|
local desc="$1"; local pattern="$2"
|
||||||
|
if grep -q "$pattern" "$FORM"; then ok "$desc"; else fail "$desc"; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Form config validator — $FORM"
|
||||||
|
echo "────────────────────────────────────────"
|
||||||
|
|
||||||
|
# Plugin trigger: must use add_page or addpage — NOT add-page-by-form
|
||||||
|
grep -q "add_page:\|addpage:" "$FORM" && ok "Process action is 'add_page' (plugin trigger)" \
|
||||||
|
|| fail "Process action must be 'add_page: true' — 'add-page-by-form' is not handled by the plugin"
|
||||||
|
|
||||||
|
# Config must be in frontmatter, not in the process block
|
||||||
|
check_grep "pageconfig block exists in frontmatter" "^pageconfig:"
|
||||||
|
check_grep "parent set to /tracker" "parent: '/tracker'"
|
||||||
|
check_grep "slug_field set (determines entry folder name)" "slug_field:"
|
||||||
|
check_grep "pagefrontmatter block exists in frontmatter" "^pagefrontmatter:"
|
||||||
|
check_grep "template: entry (creates entry.md filename)" "template: entry"
|
||||||
|
|
||||||
|
# Form name must stay 'new-entry' — cache-on-save plugin checks this exact string
|
||||||
|
check_grep "form name is 'new-entry' (required by cache-on-save plugin)" "name: new-entry"
|
||||||
|
|
||||||
|
# Required form fields
|
||||||
|
check_grep "title field present" "name: title"
|
||||||
|
check_grep "date field present" "name: date"
|
||||||
|
check_grep "content field present" "name: content"
|
||||||
|
check_grep "lat field present" "name: lat"
|
||||||
|
check_grep "lng field present" "name: lng"
|
||||||
|
check_grep "location_city field present" "name: location_city"
|
||||||
|
check_grep "location_country field present" "name: location_country"
|
||||||
|
|
||||||
|
echo "────────────────────────────────────────"
|
||||||
|
echo " $PASS passed, $FAIL failed"
|
||||||
|
|
||||||
|
if [ ${#ERRORS[@]} -gt 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Failed checks:"
|
||||||
|
for e in "${ERRORS[@]}"; do echo " → $e"; done
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
Executable
+121
@@ -0,0 +1,121 @@
|
|||||||
|
#!/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.tracker"
|
||||||
|
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
|
||||||
|
rm -rf "$TRACKER/$TEST_SLUG"
|
||||||
|
echo " [cleanup] Removed test entry: $TEST_SLUG"
|
||||||
|
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="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}&form-nonce=${LOGIN_NONCE}&task=login" \
|
||||||
|
"$BASE_URL/login")
|
||||||
|
|
||||||
|
# After login, check we can access /post (302 → 200 means logged in)
|
||||||
|
POST_STATUS=$(curl -sf -o /dev/null -w "%{http_code}" \
|
||||||
|
-c "$COOKIE_JAR" -b "$COOKIE_JAR" \
|
||||||
|
"$BASE_URL/post")
|
||||||
|
|
||||||
|
[ "$POST_STATUS" = "200" ] && ok "Login succeeded and /post is accessible" \
|
||||||
|
|| die "Login failed or /post returned $POST_STATUS — check GRAV_TEST_USER / GRAV_TEST_PASS"
|
||||||
|
|
||||||
|
# ── Step 3: get post form + nonce ────────────────────────────────────────────
|
||||||
|
POST_HTML=$(curl -sf -c "$COOKIE_JAR" -b "$COOKIE_JAR" "$BASE_URL/post") \
|
||||||
|
|| die "Could not fetch post form"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# Look for the entry — slug might have slight timestamp variation
|
||||||
|
FOUND=$(find "$TRACKER" -name "entry.md" -newer "$TRACKER/2026-06-17.entry/entry.md" \
|
||||||
|
-not -path "*/2026-*" 2>/dev/null | head -1)
|
||||||
|
|
||||||
|
# Also look for today's dated entries
|
||||||
|
FOUND_TODAY=$(find "$TRACKER" -maxdepth 1 -type d -name "$(date '+%Y-%m-%d')*" 2>/dev/null | head -1)
|
||||||
|
|
||||||
|
if [ -n "$FOUND_TODAY" ]; then
|
||||||
|
TEST_SLUG=$(basename "$FOUND_TODAY")
|
||||||
|
ok "Entry created on disk: $TEST_SLUG"
|
||||||
|
|
||||||
|
# Verify it has an entry.md inside
|
||||||
|
if [ -f "$TRACKER/$TEST_SLUG/entry.md" ]; then
|
||||||
|
ok "entry.md exists inside the entry folder"
|
||||||
|
else
|
||||||
|
fail "Entry folder exists but entry.md is missing"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify the title is in the frontmatter
|
||||||
|
if grep -q "$TEST_TITLE" "$TRACKER/$TEST_SLUG/entry.md"; then
|
||||||
|
ok "Title appears in entry frontmatter"
|
||||||
|
else
|
||||||
|
fail "Title not found in entry.md — frontmatter may be malformed"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fail "No entry created on disk — form processing failed silently"
|
||||||
|
echo " Expected a folder matching: $TRACKER/$(date '+%Y-%m-%d')-*/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Result ───────────────────────────────────────────────────────────────────
|
||||||
|
echo "────────────────────────────────────────"
|
||||||
|
echo " $PASS_COUNT passed, $FAIL_COUNT failed"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
[ $FAIL_COUNT -eq 0 ]
|
||||||
Reference in New Issue
Block a user