Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ CHALENDIA_DATABASE_MAX_CONNECTIONS=5
# Log filter. Default: info
RUST_LOG=info

# --- Ozalid ---
# Where the journeys' captures are reviewed. Pushed from a developer's machine
# with `just ozalid-push`, before opening a pull request — never from CI, where
# it would already be too late to change what was captured.
# The token is a service token issued by the ozalid project. Never committed.
OZALID_URL=https://server.ozalid.org
OZALID_TOKEN=

# --- Compose ---
# Read by docker-compose.yaml, not by the application.

Expand Down
32 changes: 23 additions & 9 deletions docs/delivery-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,29 @@ In practice:

| Step | Command |
|---|---|
| Run the journeys and build the report | `just e2e` |
| Open it | `just e2e-open` |
| Record a verdict | edit `tools/e2e-report/reviews.json` |

An entry is keyed by `<spec>::<case title>` and carries `status`
(`reviewed` or `to-fix`, the latter with a mandatory `note`), `reviewedAt`, and
`specHash` — the hash of the spec file at review time, which is what sends the
case back to *to review* when the code it judged has changed. The file is
committed; the report itself is not.
| Run the journeys | `just e2e` |
| See what would be pushed | `just ozalid-dry` |
| Push the captures | `just ozalid-push` |
| Review them | the ozalid project, in a browser |

**Pushed from a developer's machine, before the pull request — never from CI.**
A capture that reaches CI is a capture nobody looked at while there was still
time to change it.

What changed is not computed here: every capture is hashed, ozalid is asked
which addresses it does not already hold, and what it does not hold is exactly
what changed. A capture ozalid holds is never sent twice, which is what makes a
full visual history affordable.

The case a journey maps to is committed in `tools/ozalid/cases.json`. ozalid
generates a case's id and the client stores it; matching on the title instead
would open a second case the day somebody rewords a test, silently, leaving the
history on the old one. A rename is fixed by editing one line in that file.

A journey that runs in one variant only — the narrow-screen one — leaves its
steps without siblings elsewhere. ozalid calls that a **hole**: it stores the
edition and surfaces the gap rather than refusing the evidence the run did
produce.

---

Expand Down
5 changes: 3 additions & 2 deletions docs/git-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ Not yet gated, and deliberately listed so nobody assumes otherwise:
|---|---|
| Commit message and PR title validation | — |

The journeys also produce the review report the user validates screens in — see
The journeys also produce the captures the user validates screens from — see
[`delivery-workflow.md`](delivery-workflow.md) § 6. `just e2e` runs them against
the development stack and builds the report; `just e2e-open` opens it.
the development stack; `just ozalid-push` sends the captures for review, from a
developer's machine and before the pull request.

All existing gates must be green before merge; there is no manual skip.

Expand Down
35 changes: 21 additions & 14 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -293,19 +293,18 @@ api-check:
echo "api types: current"

# =============================================================================
# END TO END — the journeys, and the report the user reviews them in
# END TO END — the journeys, and the captures ozalid reviews them from
# =============================================================================

# Run the journeys against a shop created from scratch, once per variant
e2e:
#!/usr/bin/env bash
set -euo pipefail
trap 'just dev-stop >/dev/null 2>&1 || true' EXIT
# Stale reports would be merged into this run's, so the previous ones go.
# Stale reports would be pushed alongside this run's, so the previous ones go.
rm -rf {{frontend_dir}}/tmp/e2e-report
# A failing variant is the most interesting thing to look at, so the run
# goes on and the report is built either way — the exit code carries the
# verdict, not a missing report.
# goes on to the end — the exit code carries the verdict.
failed=0
for variant in ${E2E_VARIANTS:-{{e2e_variants}}}; do
echo "── ${variant} ───────────────────────────────────────────────"
Expand All @@ -325,13 +324,12 @@ e2e:
E2E_BASE_URL="http://localhost:{{dev_web_port}}" E2E_VARIANT="${variant}" npx playwright test || failed=1
cd {{justfile_directory()}}
done
just e2e-report || failed=1
exit "${failed}"

# Run the journeys against the container image, the way CI does and the way an
# operator actually installs the shop — one origin, no dev server.
# Run the journeys against the container image, the way CI and an operator do
e2e-image:
#!/usr/bin/env bash
# One origin, no dev server — the shape a merchant actually installs.
set -euo pipefail
trap 'docker compose down -v >/dev/null 2>&1 || true' EXIT
rm -rf {{frontend_dir}}/tmp/e2e-report
Expand All @@ -348,16 +346,25 @@ e2e-image:
E2E_BASE_URL="http://localhost:{{dev_api_port}}" E2E_VARIANT="${variant}" npx playwright test || failed=1
cd {{justfile_directory()}}
done
just e2e-report || failed=1
exit "${failed}"

# Build the review site from the last run
e2e-report:
node tools/e2e-report/generate.mjs
# Push the last run's captures to ozalid, where they are reviewed
ozalid-push:
#!/usr/bin/env bash
# Local and before the pull request: the visual result is one of the two
# things only the user grants, and a capture reaching CI is a capture
# nobody looked at in time. What changed is not computed here — ozalid is
# asked which content it does not hold, and that is what changed.
set -euo pipefail
set -a; . ./.env; set +a
OZALID_REVISION="$(git rev-parse --short HEAD)" node tools/ozalid/push.mjs "$@"

# Open the review site
e2e-open:
xdg-open reports/e2e/index.html
# Show what a push would send, and write nothing
ozalid-dry:
#!/usr/bin/env bash
set -euo pipefail
set -a; . ./.env; set +a
node tools/ozalid/push.mjs --dry-run

# Everything a pull request must pass, in one command
check: backend-check backend-test frontend-check frontend-test frontend-build api-check
Expand Down
Loading