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
22 changes: 22 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,38 @@ on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
skip_tests:
description: "Skip full E2E (emergency hotfix only)"
type: boolean
default: false

permissions:
contents: write
issues: write

jobs:
full-test:
if: ${{ github.event.inputs.skip_tests != 'true' }}
uses: ./.github/workflows/test-full.yml
permissions:
contents: read
issues: write

create-release:
needs: [full-test]
if: ${{ always() && (needs.full-test.result == 'success' || needs.full-test.result == 'skipped') }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Warn if tests were skipped
if: ${{ needs.full-test.result == 'skipped' }}
run: |
echo "::warning::Release created with skip_tests=true — full E2E tests were bypassed"
echo "⚠️ **Tests bypassed**: This release was created with \`skip_tests=true\`. Full E2E tests were not run." >> $GITHUB_STEP_SUMMARY

- name: Extract version number
id: version
run: |
Expand Down
78 changes: 78 additions & 0 deletions .github/workflows/test-full.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Full E2E Tests

on:
schedule:
- cron: "0 6 * * 1" # Monday 6am UTC
workflow_call:
workflow_dispatch:

concurrency:
group: test-full-${{ github.ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read
issues: write

jobs:
full-test:
name: full-test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6

- name: Check compose parity
run: bash scripts/check-compose-persist-parity.sh

- name: Setup Node.js
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6
with:
node-version: "22"
cache: "npm"

- name: Install npm 11
run: npm install -g npm@11

- name: Install dependencies
run: npm ci

- name: Run linter
run: npm run lint

- name: Run unit tests
run: npm run test:run

- name: Install Playwright browsers
run: npx playwright install --with-deps chromium webkit

- name: Run full E2E tests
run: npm run test:e2e

- name: Upload Playwright report
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 7

- name: Notify on failure
if: failure()
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
EXISTING=$(gh issue list --label ci-failure --state open --limit 1 --json number --jq '.[0].number // empty')
if [ -n "$EXISTING" ]; then
gh issue comment "$EXISTING" --body "Full E2E failed again: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} (${{ github.event_name }}, $(date -u +%Y-%m-%dT%H:%M:%SZ))"
else
gh issue create \
--title "Full E2E test suite failing" \
--label "automated,ci-failure" \
--body "The weekly full E2E test suite failed.

**Run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
**Trigger:** ${{ github.event_name }}
**Ref:** ${{ github.ref }}

Check the Playwright report artifact for details."
fi
8 changes: 3 additions & 5 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ name: Test
on:
pull_request:
branches: [main]
push:
branches: [main]
workflow_dispatch:
workflow_call:

Expand Down Expand Up @@ -43,10 +41,10 @@ jobs:
run: npm run test:run

- name: Install Playwright browsers
run: npx playwright install --with-deps chromium webkit
run: npx playwright install --with-deps chromium

- name: Run E2E tests (production build)
run: npm run test:e2e
- name: Run smoke E2E tests
run: npm run test:e2e:smoke

- name: Upload Playwright report
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
Expand Down
33 changes: 19 additions & 14 deletions playwright.smoke.config.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,33 @@
import { defineConfig, devices } from "@playwright/test";

const smokeTestUrl = process.env.SMOKE_TEST_URL;

/**
* Playwright configuration for post-deploy smoke tests.
*
* Runs against live URLs (d.racku.la or count.racku.la) to verify
* deployment succeeded and the app is working.
* Playwright configuration for smoke tests.
*
* Environment variables:
* - SMOKE_TEST_URL: Target URL to test (default: https://d.racku.la)
* Two modes:
* - Local mode (no SMOKE_TEST_URL): builds locally and serves on port 4173
* - Deploy mode (SMOKE_TEST_URL set): tests against a live URL
*
* @example
* # Test dev environment
* # Local/CI smoke tests (local build)
* npm run test:e2e:smoke
*
* # Test production
* SMOKE_TEST_URL=https://count.racku.la npm run test:e2e:smoke
*/
export default defineConfig({
// No webServer - we're testing a deployed URL
testDir: "e2e",
// Only run smoke tests - not the full E2E suite
testMatch: "smoke.spec.ts",
testMatch: ["smoke.spec.ts", "basic-workflow.spec.ts"],
fullyParallel: true,
// More retries for live environment
retries: 2,
// Longer timeouts for network latency
timeout: 60000,
expect: {
timeout: 15000,
},
reporter: [["html", { open: "never" }]],
use: {
baseURL: process.env.SMOKE_TEST_URL || "https://d.racku.la",
baseURL: smokeTestUrl || "http://localhost:4173",
trace: "on-first-retry",
screenshot: "only-on-failure",
},
Expand All @@ -40,6 +36,15 @@ export default defineConfig({
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
// Only chromium for smoke tests - speed over coverage
],
...(smokeTestUrl
? {}
: {
webServer: {
command: "npm run build && npm run preview",
port: 4173,
timeout: 120_000,
reuseExistingServer: !process.env.CI,
},
}),
});