testover · release

Ship a change, step by step

From an edit to a live update at testover.pages.dev: bump the version and change log, run the tests, commit, push and watch the deploy, with commands you can copy straight into a terminal.

In one line: pushing to main = deploying. If the change touches docs/, app/, .github/pages/, scripts/build-pages.mjs or README.md, the site is published automatically.

The flow at a glance

The steps in order. If a test fails, loop back and fix it; never push past a red run.

The release flowEdit, bump the version and change log, run the tests locally; if they pass, commit and push to main. Smoke CI and Publish site then run side by side and the site updates.Edit code / docsBump version + write change logapp/index.htmlRun the tests locallyunit · smoke · characterization · visualAll green?noRead the errorfix and rerunyesgit commitgit push origin mainSmoke (CI)unit + smoke + characterizationPublish sitewhen docs/ app/ … changedSite updated at testover.pages.devcheck the version badge and /status/

1 · Version and change log

The number on the badge in the bottom-right corner of the site comes from the top entry of CHANGELOG in app/index.html and nowhere else; no other file needs editing.

  1. Use the date as the version (YYYY.MM.DD)

    Same shape as the existing ones, such as 2026.10.17. Use the real release date.

    # Today's date = the version
    date +%Y.%m.%d                          # bash / Git Bash
    Get-Date -Format yyyy.MM.dd             # PowerShell
    
    # See the top entry of CHANGELOG
    grep -n "version: '" app/index.html | head -3                          # bash
    Select-String "version: '" app/index.html | Select-Object -First 3     # PowerShell
  2. Add a new entry at the top of CHANGELOG

    The new entry goes at the top; the badge reads the first one. Write each item as a short English sentence (the UI is English), starting with an area such as Docs:, Tests: or Sign-in page:.

    const CHANGELOG = [
      { version: '2026.10.18', changes: [
        'Docs: added the user journey page (Thai and English)',
        'Docs: added the release guide (Thai and English)',
      ] },
      { version: '2026.10.17', changes: [ /* ... */ ] },
    ];
  3. Releasing twice on the same day

    A version is a date, so it cannot repeat. Add items to that day's entry instead of creating a new one.

  4. Check it in the app

    Run npm start and open http://localhost:3000. The bottom-right badge must show the new number. Press and hold for about 0.6 seconds (or focus it and press Enter/Space) to open the change log and confirm the new entry is on top.

No need to worry about screenshots: the visual tests mask the version badge (MASK_VERSION_BADGE) and no test checks the version text. package.json stays at 1.0.0; it is unrelated to the site version.

2 · Run the tests before pushing

CI repeats these anyway, but running them locally is faster feedback and keeps main green.

# Check state and pull first
git status -sb
git pull --rebase origin main
npm ci                              # first time / when package-lock changed
npm run test:unit                   # unit + contract
npm run test:smoke                  # main paths
npm run test:characterization       # recorded behaviour + golden master
npm run test:visual                 # screenshot compare (needs Docker running)
npm test                            # the whole suite (optional, before a big release)
npm run build:pages                 # try building dist/ as Pages does

If the visual test fails because the UI really changed

Baselines must be generated in Docker so they are Linux like CI (Windows images will not match). Regenerate them and look at the images before committing.

npm run test:visual:update          # regenerate baselines in Docker (Linux, same as CI)
git status -sb tests/__screenshots__    # look at the changed images before committing

If you edited docs

Test counts change often. Recount before quoting numbers in docs: npx playwright test --list · npm run test:unit

3 · Commit and push

Write commit messages as <type>: <description>, where type is feat, fix, refactor, docs, test, chore, perf or ci.

git status -sb                                 # what changed?
git add app/index.html docs/ .github/pages/    # name the files, no git add -A
git diff --cached --stat                       # one more look
git commit -m "feat: add the user journey and release guide pages (th/en)"
git push origin main
Careful: Always name files in git add so another task's files or secrets are not swept in. Never commit a webhook URL, CLOUDFLARE_API_TOKEN or .env; those live in GitHub Secrets only. Never git push --force to main.

4 · Deploy to Cloudflare Pages

Two workflows start by themselves after a push.

WorkflowStarts whenWhat it does
Smokeevery push to main and every PRunit + contract, smoke, characterization, then uploads the reports
Publish sitea push to main touching docs/**, app/**, .github/pages/**, scripts/build-pages.mjs, README.md or this workflow file · after Weekend E2E finishes · by handbuilds the site (npm run build:pages), adds the latest reports under /status/, stamps the commit on the hub page and runs wrangler pages deploy
gh run list --limit 5                   # see the runs that just started
gh run watch                            # pick one and follow it live
gh run list --workflow "Publish site" --limit 3

Only changed tests/ or unit/ and the site did not update?

That is expected: the paths do not match Publish site. Trigger it yourself if you want a deploy:

gh workflow run cloudflare-pages.yml --ref main    # deploy by hand (no new commit needed)
gh run watch

Confirm the new site is live

curl -sI https://testover.pages.dev/docs/release-guide.html | head -1   # expect 200
git rev-parse --short HEAD                                              # compare with the commit on /status/

The repo needs the secrets CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID (the project name comes from the variable CLOUDFLARE_PROJECT_NAME, default testover).

Rolling back a bad deploy

git revert <sha>                        # undo one commit without rewriting history
git push origin main                    # Publish site runs again by itself

The whole thing in one block

Steps 2–4 together (do step 1 by hand first). It stops at the first failing command.

# The full set for a release (Git Bash); edit the commit message first
set -e
git pull --rebase origin main
npm run test:unit && npm run test:smoke && npm run test:characterization
npm run build:pages
git add app/index.html docs/ .github/pages/
git commit -m "feat: <what changed>"
git push origin main
gh run watch

Rules when adding or editing docs

Common problems

SymptomLikely causeFix
push rejectedmain has new commitsgit pull --rebase origin main then push again
visual test red in CI, green locallybaselines made on Windows/Macnpm run test:visual:update (Docker)
Publish site did not runchanged files are outside the path filtergh workflow run cloudflare-pages.yml --ref main
Deploy step fails with a token/account errorsecret missing or expiredreset CLOUDFLARE_API_TOKEN / CLOUDFLARE_ACCOUNT_ID in Settings → Secrets
badge still shows the old versionbrowser cache, or the new entry is not firsthard refresh and check the order in CHANGELOG
reports on /status/ look oldreports come from the latest Weekend E2E run, not this commitnormal; see the report commit on the hub page
new doc page 404suppercase in the file name, or not deployed yetrename to lowercase and check the Publish site run

Read next