Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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
160 changes: 142 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,72 +7,121 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
NODE_VERSION: 22
STORE_PATH_KEY: pnpm-store-

jobs:
typecheck:
name: Type Check
setup:
name: Setup
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
- run: pnpm install --frozen-lockfile
- id: pnpm-store
run: echo "path=$(pnpm store path)" >> "$GITHUB_OUTPUT"
- uses: actions/cache/save@v4
with:
path: |
node_modules
${{ steps.pnpm-store.outputs.path }}
key: ${{ env.STORE_PATH_KEY }}${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}

typecheck:
name: Type Check
runs-on: ubuntu-latest
needs: [setup]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- uses: actions/cache/restore@v4
with:
path: |
node_modules
~/.local/share/pnpm/store
key: ${{ env.STORE_PATH_KEY }}${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- run: pnpm tsc --noEmit

lint:
name: Lint
runs-on: ubuntu-latest
needs: [setup]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
node-version: ${{ env.NODE_VERSION }}
- uses: actions/cache/restore@v4
with:
path: |
node_modules
~/.local/share/pnpm/store
key: ${{ env.STORE_PATH_KEY }}${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- run: pnpm lint

format:
name: Format Check
runs-on: ubuntu-latest
needs: [setup]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
node-version: ${{ env.NODE_VERSION }}
- uses: actions/cache/restore@v4
with:
path: |
node_modules
~/.local/share/pnpm/store
key: ${{ env.STORE_PATH_KEY }}${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- run: pnpm prettier --check .

react-compiler:
name: React Compiler Health
runs-on: ubuntu-latest
needs: [setup]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
node-version: ${{ env.NODE_VERSION }}
- uses: actions/cache/restore@v4
with:
path: |
node_modules
~/.local/share/pnpm/store
key: ${{ env.STORE_PATH_KEY }}${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- run: npx react-compiler-healthcheck --src "src/**/*.{ts,tsx}"

react-doctor:
name: React Doctor
runs-on: ubuntu-latest
needs: [setup]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
node-version: ${{ env.NODE_VERSION }}
- uses: actions/cache/restore@v4
with:
path: |
node_modules
~/.local/share/pnpm/store
key: ${{ env.STORE_PATH_KEY }}${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Run React Doctor (full scan on main, diff on PRs)
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
Expand All @@ -81,6 +130,42 @@ jobs:
npx -y react-doctor@latest . --verbose --fail-on error
fi

frontend-test:
name: Frontend Tests
runs-on: ubuntu-latest
needs: [typecheck]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- uses: actions/cache/restore@v4
with:
path: |
node_modules
~/.local/share/pnpm/store
key: ${{ env.STORE_PATH_KEY }}${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- run: pnpm test:frontend --reporter=verbose

backend-test:
name: Backend Tests
runs-on: ubuntu-latest
needs: [typecheck]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- uses: actions/cache/restore@v4
with:
path: |
node_modules
~/.local/share/pnpm/store
key: ${{ env.STORE_PATH_KEY }}${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- run: pnpm test:backend:run --reporter=verbose

build:
name: Build
runs-on: ubuntu-latest
Expand All @@ -90,7 +175,46 @@ jobs:
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
node-version: ${{ env.NODE_VERSION }}
- uses: actions/cache/restore@v4
with:
path: |
node_modules
~/.local/share/pnpm/store
key: ${{ env.STORE_PATH_KEY }}${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- run: pnpm vite build

e2e-test:
name: E2E Tests
runs-on: ubuntu-latest
environment: preview
needs: [build]
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- uses: actions/cache/restore@v4
with:
path: |
node_modules
~/.local/share/pnpm/store
key: ${{ env.STORE_PATH_KEY }}${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- run: npx playwright install --with-deps chromium
- run: pnpm test:e2e
env:
VITE_CONVEX_URL: ${{ secrets.VITE_CONVEX_URL }}
VITE_CONVEX_SITE_URL: ${{ secrets.VITE_CONVEX_SITE_URL }}
VITE_SITE_URL: ${{ secrets.VITE_SITE_URL }}
E2E_TEST_EMAIL: ${{ secrets.E2E_TEST_EMAIL }}
E2E_TEST_PASSWORD: ${{ secrets.E2E_TEST_PASSWORD }}
E2E_PLAYER_EMAIL: ${{ secrets.E2E_PLAYER_EMAIL }}
E2E_PLAYER_PASSWORD: ${{ secrets.E2E_PLAYER_PASSWORD }}
TEST_RUN_ID: ${{ github.run_id }}-${{ github.run_attempt }}
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 14
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ yarn.lock
# Sentry Config File
.env.sentry-build-plugin
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
.playwright-mcp/*

app.config.timestamp_*.js


e2e/.auth/
playwright-report/

.claude/

48 changes: 48 additions & 0 deletions convex/_test/assertions.helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { expect } from 'vitest'
import { ConvexError } from 'convex/values'
import { isClientError } from '../errors'
import type { ClientErrorCode } from '../errors'

export async function expectClientError(
promise: Promise<unknown>,
code: ClientErrorCode,
) {
try {
await promise
expect.fail(
`Expected ConvexError with code ${code}, but no error was thrown`,
)
} catch (error) {
if (error instanceof ConvexError && isClientError(error, code)) {
return error
}
if (
error instanceof Error &&
'data' in error &&
isClientError(error, code)
) {
return error
}
throw error
}
}

export function expectNotAuthenticated(promise: Promise<unknown>) {
return expectClientError(promise, 'NOT_AUTHENTICATED')
}

export function expectPermissionDenied(promise: Promise<unknown>) {
return expectClientError(promise, 'PERMISSION_DENIED')
}

export function expectNotFound(promise: Promise<unknown>) {
return expectClientError(promise, 'NOT_FOUND')
}

export function expectValidationFailed(promise: Promise<unknown>) {
return expectClientError(promise, 'VALIDATION_FAILED')
}

export function expectConflict(promise: Promise<unknown>) {
return expectClientError(promise, 'CONFLICT')
}
Loading
Loading