From 4e7d89751681bafa569b4f55e8bea5e53fa34d4c Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Sat, 31 Oct 2026 08:24:18 +0100 Subject: [PATCH] =?UTF-8?q?Answer=20prose=20round=201:=200=20=F0=9F=94=B4,?= =?UTF-8?q?=204=20=F0=9F=9F=A1=20(0=20misread);=20document=20the=20e2e=20t?= =?UTF-8?q?ypecheck,=20tighten=20comments=20and=20changelog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 3 ++- CHANGELOG.md | 5 +++-- README.md | 3 ++- ci.sh | 4 ++-- e2e-tests/visual.spec.ts | 2 +- src/ci-gate.test.ts | 2 +- src/compose.test.ts | 2 +- 7 files changed, 12 insertions(+), 9 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f4f7e00..d11ff9d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -358,6 +358,7 @@ Docker Compose. **Never run `node`, `npm`, or `tsc` on the host.** ```bash docker compose up # dev server, live reload docker compose run --rm --no-deps web npm run typecheck # strict type check (--no-deps: skip Ory) +docker compose -f compose.yml -f e2e-tests/compose.visual.yml run --user "$(id -u):$(id -g)" --rm --no-deps --build e2e npm run typecheck # the E2E specs docker compose run --rm --no-deps web npm test # tests docker compose -f compose.yml up --build -d # production ``` @@ -391,7 +392,7 @@ one-time setup. A file-map or table row gets a clause, not a paragraph. If a file genuinely must be plain JavaScript, use `.js`; `"type": "module"` is set in both `package.json`s, so `.js` is ESM. - **No build step** and no compiled artifacts — do not add a bundler or `tsc` emit. -- Before finishing a change, run the typecheck and tests above; both must pass. +- Before finishing a change, run the typechecks and tests above; all must pass. - Tests use the built-in `node --test` runner — no test framework dependency. - English everywhere. - Pin all dependencies and Docker images to exact, human-readable **semantic versions** — never diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ca4006..8dcc752 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,9 @@ at boot. Entries start at 0.3.0. ### Every page carries a smaller icon sprite -The inlined sprite no longer holds `i-chart`, `i-copy` and `i-download`, which nothing in the host or -the example plugins referenced. A plugin that referenced one renders a blank icon until the host registers it again. +`i-chart`, `i-copy` and `i-download` are gone from the inlined icon sprite, so a plugin that +referenced one now renders a blank icon. Nothing in the host or the example plugins used them. Pick +another id from `views/partials/icons.ejs`, or inline your own SVG. ### The README defines its terms and states its intended scale diff --git a/README.md b/README.md index 4bd4ed7..ce4d862 100644 --- a/README.md +++ b/README.md @@ -1493,6 +1493,7 @@ Type check and unit tests run off the Ory stack — `--no-deps` keeps `web` from ```bash docker compose run --rm --no-deps web npm run typecheck # strict tsc --noEmit docker compose run --rm --no-deps web npm test # node --test (units) +docker compose -f compose.yml -f e2e-tests/compose.visual.yml run --user "$(id -u):$(id -g)" --rm --no-deps --build e2e npm run typecheck # the E2E specs ``` ### End-to-end (Playwright) @@ -1502,7 +1503,7 @@ no Node/browsers on the host. Five suites, each on its own stack: | Suite | Compose overlay | Covers | | --- | --- | --- | -| `visual.spec.ts` + `language.spec.ts` | `e2e-tests/compose.visual.yml` | Ory-free: the rendered design system (app shell at five widths from 1920px to 320px, theme switch, mobile off-canvas, icon sprite, CSRF-guarded sign-out, landing, 404), plugin permission-gating, and [language switching](#languages-i18n) | +| `visual.spec.ts` + `language.spec.ts` | `e2e-tests/compose.visual.yml` | Ory-free: the rendered design system (app shell, theme switch, mobile off-canvas, icon sprite, CSRF-guarded sign-out, landing, 404), plugin permission-gating, and [language switching](#languages-i18n) | | `auth-refresh.spec.ts` | `e2e-tests/compose.auth.yml` | The real Ory stack with the session→JWT TTL cut to 8s: a lapsed JWT is silently re-minted from the live Kratos session, and once revoked the stale cookie is cleared | | `oauth-login.spec.ts` | `e2e-tests/compose.oauth.yml` | Another app logging in through us — register a client, start an authorization flow, `/oauth2/login` accept, `/oauth2/consent` Allow → authorization code | | `full-flow.spec.ts` | `e2e-tests/compose.full.yml` | The browser UI: password + mocked-SSO login, menu filtering by permission, admin users/groups/permissions CRUD, OAuth2-clients register → one-time secret → delete, a gated plugin page, logout | diff --git a/ci.sh b/ci.sh index fd4187f..0a3bef7 100755 --- a/ci.sh +++ b/ci.sh @@ -53,8 +53,8 @@ docker compose build web step "Typecheck" docker compose run --rm --no-deps web npm run typecheck -# The specs import @playwright/test, which only the runner image carries, so the host's tsc can't -# resolve them: typecheck them in that image. --no-deps skips web and Ory; any suite's file builds it. +# The specs import @playwright/test, which only the runner image installs, so they typecheck there +# rather than in the web image. --no-deps skips web; the visual file just names the e2e service. step "Typecheck e2e-tests" docker compose -f compose.yml -f e2e-tests/compose.visual.yml run --user "$(id -u):$(id -g)" --rm --no-deps --build e2e npm run typecheck diff --git a/e2e-tests/visual.spec.ts b/e2e-tests/visual.spec.ts index 922aa9f..5a85eb3 100644 --- a/e2e-tests/visual.spec.ts +++ b/e2e-tests/visual.spec.ts @@ -10,7 +10,7 @@ const SESSION_COOKIE = "plainpages_jwt"; // src/auth/login.ts — web verifies i const shot = (page: Page, name: string): Promise => page.screenshot({ fullPage: true, path: `artifacts/screenshots/${test.info().project.name}/${name}.png` }); -// Large desktop down to a small phone, either side of the stylesheet's 860px and 560px breakpoints. +// Either side of the stylesheet's 860px and 560px breakpoints. const VIEWPORTS = [ { name: "desktop-xl", width: 1920, height: 1080 }, { name: "laptop", width: 1280, height: 800 }, diff --git a/src/ci-gate.test.ts b/src/ci-gate.test.ts index ec44525..3e19a37 100644 --- a/src/ci-gate.test.ts +++ b/src/ci-gate.test.ts @@ -29,7 +29,7 @@ test("the commit-hash image is pushed even when the gate no-ops", () => { assert.doesNotMatch(step("docker push"), /^\s*if:/m); }); -test("every E2E suite the gate runs writes its artifacts as the invoking user", () => { +test("every E2E runner container the gate starts runs as the invoking user", () => { // The documented hand-run commands carry the same flag (src/compose.test.ts). const runs = gate.split("\n").filter((l) => /docker compose .*\brun\b.*\be2e\b/.test(l)); assert.equal(runs.length, 3, "the e2e-tests typecheck, the suite helper and the devstack run"); diff --git a/src/compose.test.ts b/src/compose.test.ts index fc930ed..5f9c92c 100644 --- a/src/compose.test.ts +++ b/src/compose.test.ts @@ -129,7 +129,7 @@ test("the E2E runner writes its artifacts as the invoking user, never as root", // filter would otherwise leave that command silently unguarded. const documented = [read("README.md"), ...composeFiles("e2e-tests/").map(read)] .join("\n").split("\n").filter((l) => /docker compose .*\brun\b.*\be2e\b/.test(l)); - assert.equal(documented.length, 6, "5 compose headers + 1 README block"); + assert.equal(documented.length, 7, "5 compose headers + 2 README lines"); for (const l of documented) assert.match(l, /--user "\$\(id -u\):\$\(id -g\)"/, `passes the uid: ${l.trim()}`); // An absent mount source is daemon-created as root, and then that uid can't write it at all.