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
91 changes: 91 additions & 0 deletions .github/workflows/client-e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# ===============================================================
# React Client E2E - Playwright (TypeScript) smoke suite
# ===============================================================
# - runs TypeScript Playwright tests for the React admin UI
# - Vite dev server is spawned by Playwright's webServer config
# - backend API is stubbed with page.route() (no gateway required)
# - triggered on PRs and pushes to main
# ---------------------------------------------------------------

name: Client E2E (Playwright)

on:
push:
branches: ["main"]
pull_request:
types: [opened, synchronize, ready_for_review]
branches: ["main"]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
playwright:
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
name: Playwright smoke + auth
runs-on: ubuntu-latest
timeout-minutes: 30

env:
CI: "true"
PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/.playwright-browsers

steps:
- name: ⬇️ Checkout source
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
persist-credentials: false
fetch-depth: 1

- name: 🟩 Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "22"

- name: 📥 Install dependencies
run: npm ci --no-audit --no-fund

- name: ⚙️ Generate types with orval
run: npm run generate

- name: 🎭 Cache Playwright browsers
id: playwright-cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}
key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-playwright-

- name: 🎭 Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: npx playwright install --with-deps chromium

- name: 🎭 Install Playwright system deps (cached browsers)
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: npx playwright install-deps chromium

- name: 🧪 Run Playwright tests
run: npm run e2e

- name: 📦 Upload Playwright HTML report
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: playwright-report
path: playwright-report
retention-days: 7
if-no-files-found: ignore

- name: 📦 Upload Playwright traces on failure
if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: playwright-traces
path: test-results
retention-days: 7
if-no-files-found: ignore
52 changes: 52 additions & 0 deletions .github/workflows/client-generate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# ===============================================================
# 🧬 Client Type Generation - verify generated types stay in sync
# ===============================================================
# - regenerates src/generated/ from the committed openapi.json
# - verifies types exist and compile
# ---------------------------------------------------------------

name: Client Type Generation

on:
pull_request:
branches: ["main"]
types: [opened, synchronize, reopened, ready_for_review]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
generate-types:
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
name: Generate and verify types
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
persist-credentials: false

- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "22"

- name: Install dependencies
run: npm ci --no-audit --no-fund

- name: Generate types with orval
run: npm run generate

- name: Verify generated types exist
run: |
test -d src/generated/types || (echo "ERROR: src/generated/types/ not created" && exit 1)
echo "Generated types count: $(find src/generated/types -name '*.ts' | wc -l)"

- name: Verify generated types compile
run: npx tsc -b --noEmit
57 changes: 57 additions & 0 deletions .github/workflows/client-lint-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# ===============================================================
# ⚛️ Client Lint & Test - React Frontend Quality Gate
# ===============================================================
# - runs ESLint, Prettier, and Vitest for the React client
# - ensures code quality and test coverage for frontend
# - runs on PRs and pushes to main
# ---------------------------------------------------------------

name: Client Lint & Test

on:
push:
branches: ["main"]
pull_request:
types: [opened, synchronize, ready_for_review]
branches: ["main"]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
lint-and-test:
if: github.event_name != 'pull_request' || !github.event.pull_request.draft
name: Lint & Test Client
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- name: ⬇️ Checkout source
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
persist-credentials: false
fetch-depth: 1

- name: 🟩 Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "22"

- name: 📥 Install dependencies
run: npm ci --no-audit --no-fund

- name: ⚙️ Generate types with orval
run: npm run generate

- name: 🎨 Check code formatting with Prettier
run: npm run format:check

- name: 🔍 Lint code with ESLint
run: npm run lint

- name: 🧪 Run tests with Vitest
run: npm run test:coverage
27 changes: 27 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Build outputs
dist
build

# Dependencies
node_modules

# Generated files
*.min.js
*.min.css

# Lock files
package-lock.json
pnpm-lock.yaml
yarn.lock

# Coverage
coverage
.nyc_output

# Logs
*.log

# Playwright
playwright-report
test-results
.playwright/
10 changes: 10 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"semi": true,
"trailingComma": "all",
"singleQuote": false,
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"arrowParens": "always",
"endOfLine": "lf"
}
2 changes: 1 addition & 1 deletion src/auth/AuthContext.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ describe("AuthContext", () => {
email_verified: true,
password_change_required: false,
};
vi.mocked(api.get).mockResolvedValueOnce(mockUser);
vi.mocked(api.get).mockResolvedValueOnce({ authenticated: true, user: mockUser });

// Hold the permissions fetch open so we can observe the loading window.
let resolvePerms!: (perms: string[]) => void;
Expand Down
Loading