Visual E2E at five viewports, typecheck e2e-tests in the gate, drop unused icons #187
@@ -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
|
||||
|
||||
+3
-2
@@ -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
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ const SESSION_COOKIE = "plainpages_jwt"; // src/auth/login.ts — web verifies i
|
||||
const shot = (page: Page, name: string): Promise<Buffer> =>
|
||||
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 },
|
||||
|
||||
+1
-1
@@ -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");
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user