fix: check-git-install pins only the layer's commit and builds the playground config

- the lockfile check counts only vue-journal-layer's commit, so the layer's
  own git dependency on vue-seo-layer no longer fails it
- the scratch app takes the playground's nuxt.config.ts and app.vue (the
  search route, one post per category page, the layout trail), which
  testing/expect-acme.txt is written against
- --self-test checks the lockfile reading
This commit is contained in:
Jakub Zych
2026-11-04 19:52:22 +01:00
parent 9e66cbed42
commit e8f307b248
2 changed files with 51 additions and 22 deletions

View File

@@ -282,7 +282,7 @@ A release is an annotated git tag (`v0.1.0`) on `main`, pushed to git.golem15.co
## Testing
- `pnpm test` runs the unit tests in `tests/*.test.ts` with `node --test` (Node strips the TypeScript types; no test framework dependency). They cover the pure helpers in `app/utils/`: route normalization and path filling, the client against a fake fetcher (including the suggest query), the search helpers (term rules, diacritic-insensitive marking, plural forms, combobox keys, and the suggestion controller's debounce, abort and stale-answer handling under mocked timers), pagination, the HTML sanitizer (the Journal plugin's FormatHTML cases, the bypasses from its code review, and the Blog Editor corpus in `tests/fixtures/editor-corpus.json`, a byte copy of the plugin's), the H1 demotion and the body pipeline order, the featured image srcsets (`tests/srcset.test.ts`), the embed expansion and its sanitize-first order, the post page view, SEO values (fallback meta, the title element, ItemList), path-form routes, the old purge route's helpers and browser revalidation (`tests/siteCache.test.ts`), and pl/en key and placeholder parity. The shared purge route and the body link steps are tested in vue-seo-layer. They need no build, network or database.
- `scripts/check-git-install.sh <tag>` installs the layer from the git tag into a scratch app, checks that `pnpm-lock.yaml` pins the tag's commit, runs `nuxt build`, and runs the SSR smoke against the build. Run it from a directory that is not inside a directory named `vue-journal-layer` (Nuxt treats such a path segment as the layer).
- `scripts/check-git-install.sh <tag>` installs the layer from the git tag into a scratch app built from the layer's playground config (`.playground/nuxt.config.ts` extending the installed layer, and its `app.vue`), checks that `pnpm-lock.yaml` pins the tag's commit for vue-journal-layer (its own git dependencies, such as vue-seo-layer, are ignored), runs `nuxt build`, and runs the SSR smoke against the build. `--self-test` checks the lockfile reading only. Run it from a directory that is not inside a directory named `vue-journal-layer` (Nuxt treats such a path segment as the layer).
- `testing/smoke-ssr.mjs --output <.output> --fixtures <dir> --expect <file> [--env KEY=VALUE]...` boots a fixture Journal and SEO API and the built server and checks each line of the expectations file: `STATUS PATH [contains=TEXT] [notcontains=TEXT] [count=TEXT:N] [type=PREFIX] [header=NAME: VALUE] [noheader=NAME] [headings=strict] [cardlinks=N]`, every option repeatable, and `resolves PATH N` (the SEO resolve calls so far for a path, `*` for all). `headings=strict` wants exactly one `<h1` and no skipped level, `cardlinks=N` exactly N links in each post card. It also checks that SSR requests forwarded `x-forwarded-for` and that categories were requested with `include_empty=1`. `pnpm smoke:ssr` runs `expect-acme.txt` and the expectation files for `postTitleTag` forced to `h1` and `p`, the new-tab hint off and `journal.breadcrumbs` off.
- `testing/purge-check.mjs --output <.output> --fixtures <dir> --kind post|category --slug <slug> --path <page path>` proves the [site cache purge](#site-cache-purge) on a built server whose route rules cache pages: it caches the page, changes the entity in a temporary copy of the fixtures, requires the cached page to stay unchanged, purges with a random token, and requires the change on the next request. It also checks `max-age=0` on the page and its 304, the purged `_payload.json`, a second purge after re-caching, `401` without or with a wrong token, `404` behind a proxy and `404` on a server without a token. The last line is `purge-check: ok (<n> checks)`.
- `testing/purge-token-check.mjs --output <.output> --fixtures <dir> --path <page path>` proves on a built server that the purge token never reaches a page. It starts the server three times with fresh random tokens: under `NUXT_CACHE_PURGE_TOKEN`, under the deprecated `NUXT_SITE_CACHE_PURGE_TOKEN` with `NUXT_SITE_CACHE_ALLOW_PROXIED=true`, and under both names with different values. Each time `/`, the page and its `_payload.json` (when served) must contain no token value and neither `cachePurgeToken` nor `cacheAllowProxied`, the shared purge route must accept the expected bearer and refuse the others, and the deprecation warning must appear once with the old names only. The last line is `purge-token-check: ok (<n> checks)`.

View File

@@ -1,10 +1,12 @@
#!/usr/bin/env bash
# Usage: scripts/check-git-install.sh <tag>
# scripts/check-git-install.sh --self-test (the lockfile check only)
#
# Proves the layer's distribution end to end: a scratch app installs
# vue-journal-layer from git+https://git.golem15.com/golem15/vue-journal-layer.git#<tag>
# anonymously, the lockfile pins the tag's commit, `nuxt build` succeeds, and
# the built server passes testing/expect-acme.txt against the fixture API.
# anonymously, the lockfile pins the tag's commit, `nuxt build` of the layer's
# playground config succeeds, and the built server passes
# testing/expect-acme.txt against the fixture API.
# Nothing outside a temporary directory is touched.
set -euo pipefail
@@ -12,6 +14,35 @@ REPO_URL="https://git.golem15.com/golem15/vue-journal-layer.git"
die() { echo "check-git-install: $*" >&2; exit 1; }
# lock_commits FILE prints the commits FILE pins for vue-journal-layer, one
# per line: the #<commit> of its git+https entries and the commit of a
# resolution whose repo is the layer's. Other git dependencies are ignored.
lock_commits() {
{
grep -oE 'vue-journal-layer\.git#[0-9a-f]{40}' "$1" | cut -d'#' -f2
grep -oE 'commit: [0-9a-f]{40}, repo: [^,}]*/vue-journal-layer\.git' "$1" | grep -oE '[0-9a-f]{40}'
} | sort -u
}
if [[ "${1:-}" == "--self-test" ]]; then
lock="$(mktemp)"
trap 'rm -f "$lock"' EXIT
j=1111111111111111111111111111111111111111
s=2222222222222222222222222222222222222222
cat >"$lock" <<LOCK
vue-journal-layer:
specifier: git+https://git.golem15.com/golem15/vue-journal-layer.git#v1.0.0
version: git+https://git.golem15.com/golem15/vue-journal-layer.git#$j(abcdef0123456789abcdef0123456789)
vue-journal-layer@git+https://git.golem15.com/golem15/vue-journal-layer.git#$j:
resolution: {commit: $j, repo: https://git.golem15.com/golem15/vue-journal-layer.git, type: git}
vue-seo-layer@git+https://git.golem15.com/golem15/vue-seo-layer.git#$s:
resolution: {commit: $s, repo: https://git.golem15.com/golem15/vue-seo-layer.git, type: git}
LOCK
[[ "$(lock_commits "$lock")" == "$j" ]] || die "self-test: lock_commits gave $(lock_commits "$lock" | tr '\n' ' '), want only $j"
echo "check-git-install: self-test ok"
exit 0
fi
TAG="${1:-}"
[[ -n "$TAG" ]] || die "usage: $0 <tag>"
@@ -58,30 +89,28 @@ allowBuilds:
vue-demi: true
YAML
cat >nuxt.config.ts <<'TS'
export default defineNuxtConfig({
extends: ['vue-journal-layer'],
compatibilityDate: '2025-07-15',
site: { url: 'https://acme.test', name: 'Acme Blog' },
i18n: {
strategy: 'prefix_except_default',
defaultLocale: 'en',
locales: [
{ code: 'en', language: 'en-US' },
{ code: 'pl', language: 'pl-PL' },
],
},
})
TS
GIT_TERMINAL_PROMPT=0 pnpm install || die "pnpm install failed"
# The lockfile must pin the tag's commit, not a branch.
LOCK_SHA="$(grep -oE "vue-journal-layer[^[:space:]]*[0-9a-f]{40}|commit: [0-9a-f]{40}" pnpm-lock.yaml | grep -oE '[0-9a-f]{40}' | sort -u)"
# The lockfile must pin the tag's commit, not a branch. Only the
# vue-journal-layer entries count: the layer's own git dependencies
# (vue-seo-layer) are pinned in the same file.
LOCK_SHA="$(lock_commits pnpm-lock.yaml)"
[[ -n "$LOCK_SHA" ]] || die "pnpm-lock.yaml records no commit for vue-journal-layer"
[[ "$(wc -l <<<"$LOCK_SHA")" -eq 1 ]] || die "pnpm-lock.yaml records more than one commit: $LOCK_SHA"
[[ "$(wc -l <<<"$LOCK_SHA")" -eq 1 ]] || die "pnpm-lock.yaml records more than one vue-journal-layer commit: $LOCK_SHA"
[[ "$LOCK_SHA" == "$TAG_SHA" ]] || die "pnpm-lock.yaml pins $LOCK_SHA, tag $TAG is $TAG_SHA"
# The scratch app is the layer's playground (its journal options, such as
# the search route and one post per category page, and its app.vue with the
# search box and the layout trail), which testing/expect-acme.txt is
# written against, extending the installed layer instead of '..'.
PLAYGROUND=node_modules/vue-journal-layer/.playground
[[ -f "$PLAYGROUND/nuxt.config.ts" && -f "$PLAYGROUND/app/app.vue" ]] \
|| die "the installed layer has no .playground/nuxt.config.ts and .playground/app/app.vue"
sed "s#extends: \['\.\.'\]#extends: ['vue-journal-layer']#" "$PLAYGROUND/nuxt.config.ts" >nuxt.config.ts
grep -q "extends: \['vue-journal-layer'\]" nuxt.config.ts || die "the playground's nuxt.config.ts does not extend '..'"
mkdir -p app
cp "$PLAYGROUND/app/app.vue" app/app.vue
pnpm exec nuxt build || die "nuxt build failed"
node node_modules/vue-journal-layer/testing/smoke-ssr.mjs \