test(ci): add quality gates, e2e data prep, and i18n integration coverage
This commit is contained in:
70
.gitea/workflows/ci.yml
Normal file
70
.gitea/workflows/ci.yml
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
name: CMS CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
- staging
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
BUN_VERSION: "1.3.5"
|
||||||
|
NODE_ENV: "test"
|
||||||
|
DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/cms?schema=public"
|
||||||
|
BETTER_AUTH_SECRET: "ci-test-secret-change-me"
|
||||||
|
BETTER_AUTH_URL: "http://localhost:3001"
|
||||||
|
CMS_ADMIN_ORIGIN: "http://127.0.0.1:3001"
|
||||||
|
CMS_WEB_ORIGIN: "http://127.0.0.1:3000"
|
||||||
|
CMS_ADMIN_SELF_REGISTRATION_ENABLED: "false"
|
||||||
|
CMS_SUPPORT_USERNAME: "support"
|
||||||
|
CMS_SUPPORT_EMAIL: "support@cms.local"
|
||||||
|
CMS_SUPPORT_PASSWORD: "support-ci-password"
|
||||||
|
CMS_SUPPORT_NAME: "Technical Support"
|
||||||
|
CMS_SUPPORT_LOGIN_KEY: "support-access"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
quality:
|
||||||
|
name: Lint Typecheck Unit E2E
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
env:
|
||||||
|
POSTGRES_DB: cms
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
options: >-
|
||||||
|
--health-cmd "pg_isready -U postgres -d cms"
|
||||||
|
--health-interval 10s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 5
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Bun
|
||||||
|
uses: oven-sh/setup-bun@v2
|
||||||
|
with:
|
||||||
|
bun-version: ${{ env.BUN_VERSION }}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: bun install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Install Playwright browser deps
|
||||||
|
run: bunx playwright install --with-deps chromium
|
||||||
|
|
||||||
|
- name: Lint and format checks
|
||||||
|
run: bun run check
|
||||||
|
|
||||||
|
- name: Typecheck
|
||||||
|
run: bun run typecheck
|
||||||
|
|
||||||
|
- name: Unit and integration tests
|
||||||
|
run: bun run test
|
||||||
|
|
||||||
|
- name: E2E tests
|
||||||
|
run: bun run test:e2e
|
||||||
@@ -69,6 +69,7 @@ bun run dev
|
|||||||
- `bun run test`
|
- `bun run test`
|
||||||
- `bun run test:watch`
|
- `bun run test:watch`
|
||||||
- `bun run test:coverage`
|
- `bun run test:coverage`
|
||||||
|
- `bun run test:e2e:prepare`
|
||||||
- `bun run test:e2e`
|
- `bun run test:e2e`
|
||||||
- `bun run lint`
|
- `bun run lint`
|
||||||
- `bun run typecheck`
|
- `bun run typecheck`
|
||||||
@@ -85,6 +86,7 @@ bun run dev
|
|||||||
- Unit/integration/component: Vitest + Testing Library + MSW
|
- Unit/integration/component: Vitest + Testing Library + MSW
|
||||||
- E2E: Playwright (separate projects for `web` and `admin`)
|
- E2E: Playwright (separate projects for `web` and `admin`)
|
||||||
- Use `bun run test` and `bun run test:e2e` (not plain `bun test`, which uses Bun's runner)
|
- Use `bun run test` and `bun run test:e2e` (not plain `bun test`, which uses Bun's runner)
|
||||||
|
- E2E data prep (migrations + seed): `bun run test:e2e:prepare`
|
||||||
|
|
||||||
One-time Playwright browser install:
|
One-time Playwright browser install:
|
||||||
|
|
||||||
@@ -97,6 +99,7 @@ bunx playwright install
|
|||||||
The repo includes a theoretical CI/CD and deployment baseline:
|
The repo includes a theoretical CI/CD and deployment baseline:
|
||||||
|
|
||||||
- Gitea workflow: `.gitea/workflows/ci-cd-theoretical.yml`
|
- Gitea workflow: `.gitea/workflows/ci-cd-theoretical.yml`
|
||||||
|
- Real quality gate workflow: `.gitea/workflows/ci.yml`
|
||||||
- App images:
|
- App images:
|
||||||
- `apps/web/Dockerfile`
|
- `apps/web/Dockerfile`
|
||||||
- `apps/admin/Dockerfile`
|
- `apps/admin/Dockerfile`
|
||||||
|
|||||||
10
TODO.md
10
TODO.md
@@ -61,11 +61,11 @@ This file is the single source of truth for roadmap and delivery progress.
|
|||||||
|
|
||||||
- [x] [P1] Vitest + Testing Library + MSW baseline
|
- [x] [P1] Vitest + Testing Library + MSW baseline
|
||||||
- [x] [P1] Playwright baseline with web/admin projects
|
- [x] [P1] Playwright baseline with web/admin projects
|
||||||
- [ ] [P1] CI workflow for lint/typecheck/unit/e2e gates
|
- [x] [P1] CI workflow for lint/typecheck/unit/e2e gates
|
||||||
- [ ] [P1] Test data strategy (seed fixtures + isolated e2e data)
|
- [x] [P1] Test data strategy (seed fixtures + isolated e2e data)
|
||||||
- [~] [P1] RBAC policy unit tests and permission regression suite
|
- [~] [P1] RBAC policy unit tests and permission regression suite
|
||||||
- [ ] [P1] i18n unit tests (locale resolution, fallback, message key loading)
|
- [ ] [P1] i18n unit tests (locale resolution, fallback, message key loading)
|
||||||
- [ ] [P1] i18n integration tests (admin/public locale switch and persistence)
|
- [x] [P1] i18n integration tests (admin/public locale switch and persistence)
|
||||||
- [ ] [P1] i18n e2e smoke tests (localized headings/content per route)
|
- [ ] [P1] i18n e2e smoke tests (localized headings/content per route)
|
||||||
- [ ] [P1] CRUD contract tests for shared service patterns
|
- [ ] [P1] CRUD contract tests for shared service patterns
|
||||||
|
|
||||||
@@ -160,6 +160,8 @@ This file is the single source of truth for roadmap and delivery progress.
|
|||||||
- [ ] [P1] Forgot password/reset password pipeline and support tooling
|
- [ ] [P1] Forgot password/reset password pipeline and support tooling
|
||||||
- [ ] [P2] GUI page to edit role-permission mappings with safety guardrails
|
- [ ] [P2] GUI page to edit role-permission mappings with safety guardrails
|
||||||
- [ ] [P2] Translation management UI for admin (language toggles, key coverage, missing translation markers)
|
- [ ] [P2] Translation management UI for admin (language toggles, key coverage, missing translation markers)
|
||||||
|
- [ ] [P2] Time-boxed support access keys generated by privileged admins; while active, disable direct support-user password login on the regular auth form
|
||||||
|
- [ ] [P2] Keep permanent emergency support key fallback via env (`CMS_SUPPORT_LOGIN_KEY`)
|
||||||
- [ ] [P2] Error boundaries and UX fallback states
|
- [ ] [P2] Error boundaries and UX fallback states
|
||||||
|
|
||||||
### Public App
|
### Public App
|
||||||
@@ -199,6 +201,8 @@ This file is the single source of truth for roadmap and delivery progress.
|
|||||||
- [2026-02-10] Admin dashboard includes a temporary posts CRUD sandbox (create/update/delete) to validate the shared CRUD base through the real app UI.
|
- [2026-02-10] Admin dashboard includes a temporary posts CRUD sandbox (create/update/delete) to validate the shared CRUD base through the real app UI.
|
||||||
- [2026-02-10] Admin i18n baseline now resolves locale from cookie and loads runtime message dictionaries in root layout; admin locale switcher is active on auth and dashboard views.
|
- [2026-02-10] Admin i18n baseline now resolves locale from cookie and loads runtime message dictionaries in root layout; admin locale switcher is active on auth and dashboard views.
|
||||||
- [2026-02-10] Admin self-registration policy is now managed via `/settings` and persisted in `system_setting`; env var is fallback/default only.
|
- [2026-02-10] Admin self-registration policy is now managed via `/settings` and persisted in `system_setting`; env var is fallback/default only.
|
||||||
|
- [2026-02-10] E2E now runs with deterministic preparation (`test:e2e:prepare`: generate + migrate deploy + seed) before Playwright execution.
|
||||||
|
- [2026-02-10] CI quality workflow `.gitea/workflows/ci.yml` enforces `check`, `typecheck`, `test`, and `test:e2e` against a PostgreSQL service.
|
||||||
|
|
||||||
## How We Use This File
|
## How We Use This File
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ export default defineConfig({
|
|||||||
{ text: "CRUD Baseline", link: "/product-engineering/crud-baseline" },
|
{ text: "CRUD Baseline", link: "/product-engineering/crud-baseline" },
|
||||||
{ text: "i18n Baseline", link: "/product-engineering/i18n-baseline" },
|
{ text: "i18n Baseline", link: "/product-engineering/i18n-baseline" },
|
||||||
{ text: "RBAC And Permissions", link: "/product-engineering/rbac-permission-model" },
|
{ text: "RBAC And Permissions", link: "/product-engineering/rbac-permission-model" },
|
||||||
|
{ text: "Testing Strategy", link: "/product-engineering/testing-strategy" },
|
||||||
{ text: "Workflow", link: "/workflow" },
|
{ text: "Workflow", link: "/workflow" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ This section covers platform and implementation documentation for engineers and
|
|||||||
- [Architecture](/architecture)
|
- [Architecture](/architecture)
|
||||||
- [Better Auth Baseline](/product-engineering/auth-baseline)
|
- [Better Auth Baseline](/product-engineering/auth-baseline)
|
||||||
- [RBAC And Permissions](/product-engineering/rbac-permission-model)
|
- [RBAC And Permissions](/product-engineering/rbac-permission-model)
|
||||||
|
- [Testing Strategy Baseline](/product-engineering/testing-strategy)
|
||||||
- [Workflow](/workflow)
|
- [Workflow](/workflow)
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
|
|||||||
33
docs/product-engineering/testing-strategy.md
Normal file
33
docs/product-engineering/testing-strategy.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Testing Strategy Baseline
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
|
||||||
|
- Keep lint, typecheck, unit/integration, and e2e as mandatory quality gates.
|
||||||
|
- Make e2e runs deterministic by preparing schema and seeded data before test execution.
|
||||||
|
- Keep test data isolated per environment (`dev` local, CI database service in workflow).
|
||||||
|
|
||||||
|
## Current Gate Stack
|
||||||
|
|
||||||
|
- `bun run check`
|
||||||
|
- `bun run typecheck`
|
||||||
|
- `bun run test`
|
||||||
|
- `bun run test:e2e`
|
||||||
|
|
||||||
|
## Data Preparation
|
||||||
|
|
||||||
|
- `bun run test:e2e:prepare` runs:
|
||||||
|
- Prisma client generation
|
||||||
|
- migration deploy
|
||||||
|
- seed data (including support user bootstrap)
|
||||||
|
- `bun run test:e2e` and related scripts call `test:e2e:prepare` automatically.
|
||||||
|
|
||||||
|
## Locale Integration Coverage
|
||||||
|
|
||||||
|
- `e2e/i18n.pw.ts` covers:
|
||||||
|
- web locale switch + persistence
|
||||||
|
- admin locale switch + persistence
|
||||||
|
|
||||||
|
## CI
|
||||||
|
|
||||||
|
- Real quality workflow: `.gitea/workflows/ci.yml`
|
||||||
|
- Uses a PostgreSQL service container and runs the full gate stack, including e2e.
|
||||||
@@ -15,10 +15,10 @@ Follow `BRANCHING.md`:
|
|||||||
|
|
||||||
## Quality Gates
|
## Quality Gates
|
||||||
|
|
||||||
- `bun run lint`
|
- `bun run check`
|
||||||
- `bun run typecheck`
|
- `bun run typecheck`
|
||||||
- `bun run test`
|
- `bun run test`
|
||||||
- `bun run test:e2e --list`
|
- `bun run test:e2e`
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
|||||||
29
e2e/i18n.pw.ts
Normal file
29
e2e/i18n.pw.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { expect, test } from "@playwright/test"
|
||||||
|
|
||||||
|
test.describe("i18n integration", () => {
|
||||||
|
test("web language switcher updates and persists locale", async ({ page }, testInfo) => {
|
||||||
|
test.skip(testInfo.project.name !== "web-chromium")
|
||||||
|
|
||||||
|
await page.goto("/")
|
||||||
|
await expect(page.getByRole("heading", { name: /your next\.js cms frontend/i })).toBeVisible()
|
||||||
|
|
||||||
|
await page.locator("select").first().selectOption("de")
|
||||||
|
await expect(page.getByRole("heading", { name: /dein next\.js cms frontend/i })).toBeVisible()
|
||||||
|
|
||||||
|
await page.reload()
|
||||||
|
await expect(page.getByRole("heading", { name: /dein next\.js cms frontend/i })).toBeVisible()
|
||||||
|
})
|
||||||
|
|
||||||
|
test("admin language switcher updates and persists locale", async ({ page }, testInfo) => {
|
||||||
|
test.skip(testInfo.project.name !== "admin-chromium")
|
||||||
|
|
||||||
|
await page.goto("/login")
|
||||||
|
await expect(page.getByRole("heading", { name: /sign in to cms admin/i })).toBeVisible()
|
||||||
|
|
||||||
|
await page.locator("select").first().selectOption("de")
|
||||||
|
await expect(page.getByRole("heading", { name: /bei cms admin anmelden/i })).toBeVisible()
|
||||||
|
|
||||||
|
await page.reload()
|
||||||
|
await expect(page.getByRole("heading", { name: /bei cms admin anmelden/i })).toBeVisible()
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -18,9 +18,10 @@
|
|||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"test:watch": "vitest",
|
"test:watch": "vitest",
|
||||||
"test:coverage": "vitest run --coverage",
|
"test:coverage": "vitest run --coverage",
|
||||||
"test:e2e": "bun run db:generate && playwright test",
|
"test:e2e:prepare": "bun run db:generate && bun run db:migrate:deploy && bun run db:seed",
|
||||||
"test:e2e:headed": "bun run db:generate && playwright test --headed",
|
"test:e2e": "bun run test:e2e:prepare && playwright test",
|
||||||
"test:e2e:ui": "bun run db:generate && playwright test --ui",
|
"test:e2e:headed": "bun run test:e2e:prepare && playwright test --headed",
|
||||||
|
"test:e2e:ui": "bun run test:e2e:prepare && playwright test --ui",
|
||||||
"commitlint": "commitlint --last",
|
"commitlint": "commitlint --last",
|
||||||
"changelog:preview": "conventional-changelog -p conventionalcommits -r 0",
|
"changelog:preview": "conventional-changelog -p conventionalcommits -r 0",
|
||||||
"changelog:release": "conventional-changelog -p conventionalcommits -i CHANGELOG.md -s",
|
"changelog:release": "conventional-changelog -p conventionalcommits -i CHANGELOG.md -s",
|
||||||
|
|||||||
Reference in New Issue
Block a user