From 4d4b583cf4dcb0f3b99f74c666af15d3b1a0fc59 Mon Sep 17 00:00:00 2001 From: Citali Date: Tue, 10 Feb 2026 21:17:41 +0100 Subject: [PATCH] test(ci): add quality gates, e2e data prep, and i18n integration coverage --- .gitea/workflows/ci.yml | 70 ++++++++++++++++++++ README.md | 3 + TODO.md | 10 ++- docs/.vitepress/config.mts | 1 + docs/product-engineering/index.md | 1 + docs/product-engineering/testing-strategy.md | 33 +++++++++ docs/workflow.md | 4 +- e2e/i18n.pw.ts | 29 ++++++++ package.json | 7 +- 9 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 .gitea/workflows/ci.yml create mode 100644 docs/product-engineering/testing-strategy.md create mode 100644 e2e/i18n.pw.ts diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..fe71858 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -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 diff --git a/README.md b/README.md index 12eb566..ac3377f 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ bun run dev - `bun run test` - `bun run test:watch` - `bun run test:coverage` +- `bun run test:e2e:prepare` - `bun run test:e2e` - `bun run lint` - `bun run typecheck` @@ -85,6 +86,7 @@ bun run dev - Unit/integration/component: Vitest + Testing Library + MSW - 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) +- E2E data prep (migrations + seed): `bun run test:e2e:prepare` One-time Playwright browser install: @@ -97,6 +99,7 @@ bunx playwright install The repo includes a theoretical CI/CD and deployment baseline: - Gitea workflow: `.gitea/workflows/ci-cd-theoretical.yml` +- Real quality gate workflow: `.gitea/workflows/ci.yml` - App images: - `apps/web/Dockerfile` - `apps/admin/Dockerfile` diff --git a/TODO.md b/TODO.md index 0d71663..7eff558 100644 --- a/TODO.md +++ b/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] Playwright baseline with web/admin projects -- [ ] [P1] CI workflow for lint/typecheck/unit/e2e gates -- [ ] [P1] Test data strategy (seed fixtures + isolated e2e data) +- [x] [P1] CI workflow for lint/typecheck/unit/e2e gates +- [x] [P1] Test data strategy (seed fixtures + isolated e2e data) - [~] [P1] RBAC policy unit tests and permission regression suite - [ ] [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] 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 - [ ] [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] 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 ### 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 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] 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 diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 92a27bf..92e508e 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -23,6 +23,7 @@ export default defineConfig({ { text: "CRUD Baseline", link: "/product-engineering/crud-baseline" }, { text: "i18n Baseline", link: "/product-engineering/i18n-baseline" }, { text: "RBAC And Permissions", link: "/product-engineering/rbac-permission-model" }, + { text: "Testing Strategy", link: "/product-engineering/testing-strategy" }, { text: "Workflow", link: "/workflow" }, ], }, diff --git a/docs/product-engineering/index.md b/docs/product-engineering/index.md index 2d5fd11..5735cc1 100644 --- a/docs/product-engineering/index.md +++ b/docs/product-engineering/index.md @@ -8,6 +8,7 @@ This section covers platform and implementation documentation for engineers and - [Architecture](/architecture) - [Better Auth Baseline](/product-engineering/auth-baseline) - [RBAC And Permissions](/product-engineering/rbac-permission-model) +- [Testing Strategy Baseline](/product-engineering/testing-strategy) - [Workflow](/workflow) ## Scope diff --git a/docs/product-engineering/testing-strategy.md b/docs/product-engineering/testing-strategy.md new file mode 100644 index 0000000..0df677a --- /dev/null +++ b/docs/product-engineering/testing-strategy.md @@ -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. diff --git a/docs/workflow.md b/docs/workflow.md index c72cdf7..4946754 100644 --- a/docs/workflow.md +++ b/docs/workflow.md @@ -15,10 +15,10 @@ Follow `BRANCHING.md`: ## Quality Gates -- `bun run lint` +- `bun run check` - `bun run typecheck` - `bun run test` -- `bun run test:e2e --list` +- `bun run test:e2e` ## Changelog diff --git a/e2e/i18n.pw.ts b/e2e/i18n.pw.ts new file mode 100644 index 0000000..01d6ff9 --- /dev/null +++ b/e2e/i18n.pw.ts @@ -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() + }) +}) diff --git a/package.json b/package.json index d6b2c84..28f8647 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,10 @@ "test": "vitest run", "test:watch": "vitest", "test:coverage": "vitest run --coverage", - "test:e2e": "bun run db:generate && playwright test", - "test:e2e:headed": "bun run db:generate && playwright test --headed", - "test:e2e:ui": "bun run db:generate && playwright test --ui", + "test:e2e:prepare": "bun run db:generate && bun run db:migrate:deploy && bun run db:seed", + "test:e2e": "bun run test:e2e:prepare && playwright test", + "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", "changelog:preview": "conventional-changelog -p conventionalcommits -r 0", "changelog:release": "conventional-changelog -p conventionalcommits -i CHANGELOG.md -s",