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
4 changes: 2 additions & 2 deletions .cursor/rules/frontend/e2e-playwright.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ alwaysApply: false
- Confirm dialogs use `getByRole('alertdialog')` (shadcn AlertDialog), not `dialog`

## Projects (dependency graph)
`public` → `auth`; `public` → `setup` → `{chromium, security}`; `security` → `passkey-login`; `chromium` → `chat`
`public` → `auth` → `setup` → `{chromium, security, passkey-login}`; `chromium` → `chat`

- **public**: no storageState
- **auth**: empty storageState; numbered `01-`…`06-` specs (file-name order is the convention — `testMatch` only selects files, it does not impose execution order)
- **setup**: `auth.setup.ts` writes `test-results/.auth/user.json` (depends on public only)
- **setup**: `auth.setup.ts` writes `test-results/.auth/user.json` (depends on auth)
- **chromium** / **security** / **chat**: `storageState` from setup file
- **passkey-login**: empty storageState; dedicated `e2e-passkey@test.ai`

Expand Down
16 changes: 16 additions & 0 deletions .github/actions/setup-playwright/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Setup Playwright
description: Cache and install Chromium with system deps for API and web E2E
runs:
using: composite
steps:
- uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install Playwright Chromium
shell: bash
run: |
pnpm --filter @repo/api exec playwright install chromium --with-deps
pnpm --filter @repo/web exec playwright install chromium --with-deps
4 changes: 4 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}

jobs:
lint:
name: Lint Code
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/packages-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:
- 'packages/**'
- 'tools/**'
- 'apps/api/openapi/**'
- '.github/workflows/packages-test.yml'
- '.github/actions/setup-pnpm/**'
- 'pnpm-lock.yaml'
- 'package.json'
- 'turbo.json'
Expand All @@ -20,6 +22,8 @@ env:
PGLITE: true
DATABASE_URL: postgresql://localhost/test
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY || 'sk-ant-dummy-for-packages-test' }}
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}

jobs:
test:
Expand All @@ -28,6 +32,6 @@ jobs:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-pnpm
- name: Build packages
run: pnpm turbo run build --filter='!@repo/web' --filter='!@repo/api' --filter='!@repo/docu'
run: pnpm turbo run build --filter=@repo/error... --filter=@repo/core --filter=@repo/react
- name: Unit tests (packages only)
run: pnpm turbo run test --filter='!@repo/web' --filter='!@repo/api' --filter='!@repo/docu'
run: pnpm turbo run test --filter=@repo/core --filter=@repo/react --filter=@repo/error
22 changes: 12 additions & 10 deletions .github/workflows/web-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,23 @@ on:
pull_request:
paths:
- 'apps/web/**'
- 'apps/api/src/routes/auth/**'
- 'apps/api/src/routes/account/**'
- 'apps/api/src/routes/ai/**'
- 'apps/api/src/routes/health/**'
- 'apps/api/src/routes/test/**'
- 'scripts/**'
- 'packages/core/**'
- 'packages/react/**'
- 'packages/ui/**'
- 'packages/utils/**'
- 'packages/error/**'
- 'tools/eslint-config/**'
- 'tools/typescript-config/**'
- 'tools/eslint/**'
- 'tools/typescript/**'
- 'apps/api/openapi/**'
- '.github/workflows/web-e2e.yml'
- '.github/actions/setup-pnpm/**'
- '.github/actions/setup-playwright/**'
- 'pnpm-lock.yaml'
- 'package.json'
- 'turbo.json'
Expand All @@ -34,6 +41,8 @@ env:
NEXT_PUBLIC_API_URL: http://localhost:3001
AI_PROVIDER: anthropic
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}

jobs:
build-and-test:
Expand All @@ -49,14 +58,7 @@ jobs:
${{ runner.os }}-next-web-
- name: Build
run: pnpm turbo run build --filter=@repo/web...
- uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install Playwright
run: pnpm --filter @repo/web exec playwright install chromium --with-deps
- uses: ./.github/actions/setup-playwright
- name: Verify ANTHROPIC_API_KEY for E2E (AI_PROVIDER=anthropic)
shell: bash
env:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Run with `pnpm <script>`.
**Setup**
- `setup` — Full setup (install, hooks, gitleaks, osv, env templates, database, deepsec, Playwright Chromium)
- `setup:gitleaks`, `setup:osv` — Install Gitleaks, OSV scanner
- `setup:playwright` — Install Playwright Chromium for E2E tests
- `setup:playwright` — Install Playwright Chromium for API and web E2E
- `setup:env` — Copy `.env.<qualifier>.example` templates to dest files when missing
- `setup:database` — Database tools (Docker, Supabase CLI)
- `setup:deepsec` — Install DeepSec workspace (`.deepsec/`)
Expand All @@ -62,7 +62,7 @@ Run with `pnpm <script>`.
**Primary**
- `build` — Build packages and apps
- `dev` — Start dev (core, react, error, utils, api, web)
- `qa` — Full check: install → checktypes → lint → build → test (unit) → test:e2e (Fastify + Next, local spawn)
- `qa` — Full check: install (if needed) → checktypes → lint → OpenAPI drift → build → test (unit) → test:e2e (Fastify + Next, `SKIP_BUILD=1`)
**Format / Lint**
- `checktypes` — Type-check all packages
- `format` — Format code (Biome)
Expand Down
3 changes: 1 addition & 2 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"scripts": {
"test": "pnpm test:unit",
"test:unit": "NODE_OPTIONS='--import tsx' vitest run",
"test:unit": "node scripts/check-test-imports.mjs && NODE_OPTIONS='--import tsx' vitest run",
"test:watch": "NODE_OPTIONS='--import tsx' vitest",
"test:cov": "NODE_OPTIONS='--import tsx' vitest run --coverage",
"test:e2e": "node scripts/run-e2e.mjs",
Expand Down Expand Up @@ -93,7 +93,6 @@
"@types/react-dom": "^19.2.5",
"@typescript/native": "npm:typescript@^7.0.2",
"@vitest/coverage-v8": "^4.1.11",
"c8": "^12.0.0",
"chokidar-cli": "^3.0.0",
"concurrently": "^10.0.5",
"drizzle-kit": "^0.31.10",
Expand Down
2 changes: 1 addition & 1 deletion apps/api/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default defineConfig({
testMatch: /.*\.e2e\.spec\.ts$/,
fullyParallel: false, // PGLite does not support concurrent writers; run tests in series
forbidOnly: isCi,
retries: isCi ? 2 : 0,
retries: 0,
workers: 1,
reporter: isCi ? 'github' : 'list',
globalSetup: './test/playwright-global-setup.ts',
Expand Down
58 changes: 58 additions & 0 deletions apps/api/scripts/check-test-imports.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env node
import { readdir, readFile } from 'node:fs/promises'
import { dirname, join, relative } from 'node:path'
import { fileURLToPath } from 'node:url'

const scriptDir = dirname(fileURLToPath(import.meta.url))
const apiRoot = dirname(scriptDir)
const srcRoot = join(apiRoot, 'src')

const walk = async dir => {
const entries = await readdir(dir, { withFileTypes: true })
const files = await Promise.all(
entries.map(async entry => {
const path = join(dir, entry.name)
if (entry.isDirectory()) return walk(path)
return path.endsWith('.test.ts') ? [path] : []
}),
)
return files.flat()
}

const specFiles = await walk(srcRoot).then(files =>
Promise.all(
files.map(async file => ({
file,
content: await readFile(file, 'utf8'),
})),
),
)

const specPaths = new Set(
(await readdir(srcRoot, { recursive: true })).flatMap(entry =>
typeof entry === 'string' && entry.endsWith('.spec.ts') ? [join(srcRoot, entry)] : [],
),
)

const imported = new Set()
const importPattern = /import\s+['"](\.\.?\/[^'"]+\.test(?:\.(?:js|ts))?)['"]/g

for (const specPath of specPaths) {
const content = await readFile(specPath, 'utf8')
const dir = dirname(specPath)
let match = importPattern.exec(content)
while (match) {
const raw = match[1].replace(/\.js$/, '')
const testPath = raw.endsWith('.ts') ? join(dir, raw) : join(dir, `${raw}.ts`)
imported.add(testPath)
match = importPattern.exec(content)
}
}

const orphans = specFiles.map(({ file }) => file).filter(file => !imported.has(file))

if (orphans.length > 0) {
process.stderr.write('Orphan route test modules (not imported by any *.spec.ts):\n')
for (const file of orphans) process.stderr.write(` - ${relative(apiRoot, file)}\n`)
process.exit(1)
}
48 changes: 0 additions & 48 deletions apps/api/src/lib/ai/download.test.ts

This file was deleted.

Loading
Loading