diff --git a/scripts/test-form-config.sh b/scripts/test-form-config.sh index 1f4f51c..9fc89d5 100755 --- a/scripts/test-form-config.sh +++ b/scripts/test-form-config.sh @@ -4,6 +4,7 @@ set -euo pipefail FORM="user/pages/02.post/post-form.md" +SITE="user/config/site.yaml" PASS=0 FAIL=0 ERRORS=() @@ -12,8 +13,13 @@ 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 + local desc="$1"; local pattern="$2"; local file="${3:-$FORM}" + if grep -q "$pattern" "$file"; then ok "$desc"; else fail "$desc"; fi +} + +check_absent() { + local desc="$1"; local pattern="$2"; local file="${3:-$FORM}" + if grep -q "$pattern" "$file"; then fail "$desc"; else ok "$desc"; fi } echo "" @@ -24,25 +30,43 @@ echo "──────────────────────── 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 /trips/japan-korea-2026/dailies" "parent: '/trips/japan-korea-2026/dailies'" -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" +# Parent is now injected server-side from site.active_trip by the cache-on-save +# plugin (U1). The form must NOT hardcode pageconfig.parent — that coupling was +# the silent-misfile bug this whole change removes. +check_absent "pageconfig.parent is NOT hardcoded (injected server-side from active_trip)" "^\s*parent:" +check_grep "pageconfig block exists in frontmatter" "^pageconfig:" +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" + +# The active trip — the server-side injection source — must be set in site.yaml. +check_grep "active_trip set in site.yaml (injection source)" "^active_trip:\s*\S" "$SITE" # 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" +# Core 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 "photos field present" "name: photos" +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" +# Fields exposed by U2 (weather picker + transport + advanced trio) +check_grep "weather_desc field present" "name: weather_desc" +check_grep "weather_temp_c field present" "name: weather_temp_c" +check_grep "transport_mode field present" "name: transport_mode" +check_grep "hero_image field present" "name: hero_image" +check_grep "force_connect field present" "name: force_connect" +check_grep "featured field present" "name: featured" + +# Photos must use the custom controlled picker (U4), not filepond/file — that is +# what lets post-form.js convert HEIC before upload. +check_grep "photos field uses the custom 'photos' type (HEIC pipeline)" "type: photos" + echo "────────────────────────────────────────" echo " $PASS passed, $FAIL failed" diff --git a/scripts/test-post.sh b/scripts/test-post.sh index 0faed8f..cca1e58 100755 --- a/scripts/test-post.sh +++ b/scripts/test-post.sh @@ -7,7 +7,11 @@ 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" +# Parent is injected server-side from site.active_trip (U1), so resolve the +# dailies dir from site.yaml rather than hardcoding a trip slug. +ACTIVE_TRIP=$(grep -E '^active_trip:' user/config/site.yaml | head -1 | sed -E "s/^active_trip:[[:space:]]*['\"]?//; s/['\"]?[[:space:]]*\$//") +TRIP_SLUG=$(basename "${ACTIVE_TRIP%/}") +TRACKER="user/pages/01.trips/${TRIP_SLUG:-italy-2026-demo}/01.dailies" COOKIE_JAR="$(mktemp /tmp/grav-test-cookies.XXXXXX)" PASS_COUNT=0 FAIL_COUNT=0 diff --git a/tests/fixtures/test-corrupt.heic b/tests/fixtures/test-corrupt.heic new file mode 100644 index 0000000..442a458 Binary files /dev/null and b/tests/fixtures/test-corrupt.heic differ diff --git a/tests/fixtures/test-photo.heic b/tests/fixtures/test-photo.heic new file mode 100644 index 0000000..5f7b2dc Binary files /dev/null and b/tests/fixtures/test-photo.heic differ diff --git a/tests/ui/helpers.js b/tests/ui/helpers.js index e88fae2..04e6f07 100644 --- a/tests/ui/helpers.js +++ b/tests/ui/helpers.js @@ -28,22 +28,31 @@ function resolveUserDir() { } /** - * Resolve the active dailies directory from the post-form.md pageconfig. + * Resolve the active trip slug from site.yaml `active_trip`. * - * The post form stores `pageconfig.parent` as a Grav route such as - * `/trips/italy-2026-demo/dailies`. We map that to the filesystem by - * scanning for a folder whose name ends with the trip slug. + * The post form no longer hardcodes `pageconfig.parent` — the write target is + * injected server-side from `site.active_trip` (see the cache-on-save plugin). + * `active_trip` is a full route ("/trips/italy-2026-demo") or a bare slug; both + * reduce to the trip slug here. + */ +function resolveActiveTripSlug(userDir) { + const sitePath = path.join(userDir, 'config/site.yaml'); + if (!fs.existsSync(sitePath)) return null; + const content = fs.readFileSync(sitePath, 'utf-8'); + const m = content.match(/^active_trip:\s*['"]?(\S+?)['"]?\s*$/m); + if (!m) return null; + return m[1] + .replace(/^\/?trips\//, '') // strip a leading /trips/ + .replace(/^\//, '') + .replace(/\/.*$/, ''); // keep only the slug segment +} + +/** + * Resolve the active dailies directory on disk from the active trip slug. */ function resolveDailiesDir(userDir) { - const postFormPath = path.join(userDir, 'pages/02.post/post-form.md'); - if (!fs.existsSync(postFormPath)) { - // fallback: search all trips for a dailies dir - return null; - } - const content = fs.readFileSync(postFormPath, 'utf-8'); - const m = content.match(/parent:\s*['"]?\/trips\/([^/'"]+)\/dailies/); - if (!m) return null; - const tripSlug = m[1]; + const tripSlug = resolveActiveTripSlug(userDir); + if (!tripSlug) return null; const tripsBase = path.join(userDir, 'pages/01.trips'); if (!fs.existsSync(tripsBase)) return null; @@ -62,31 +71,37 @@ const USER_DIR = resolveUserDir(); const TRACKER_DIR = resolveDailiesDir(USER_DIR) || path.join(USER_DIR, 'pages/01.trips/italy-2026-demo/01.dailies'); /** - * The Grav route to the active trip page, derived from the post-form.md - * pageconfig.parent value (the dailies container route, minus the trailing - * `/dailies`). Posted entries surface in this page's journal feed. + * The Grav route to the active trip page, derived from site.yaml `active_trip`. + * Posted entries surface in this page's journal feed. * Falls back to '/trips/italy-2026-demo'. */ function resolveActiveTripUrl() { - const postFormPath = path.join(USER_DIR, 'pages/02.post/post-form.md'); - if (!fs.existsSync(postFormPath)) return '/trips/italy-2026-demo'; - const content = fs.readFileSync(postFormPath, 'utf-8'); - const m = content.match(/parent:\s*['"]?(\/trips\/[^'"]+)\/dailies['"]?/); - return m ? m[1] : '/trips/italy-2026-demo'; + const slug = resolveActiveTripSlug(USER_DIR); + return slug ? '/trips/' + slug : '/trips/italy-2026-demo'; } const ACTIVE_TRIP_URL = resolveActiveTripUrl(); /** - * Wait for all filepond items to finish XHR upload. + * Type content into the EasyMDE editor. The underlying