Skip to content

CICD - Unit | Integration | E2E #6

CICD - Unit | Integration | E2E

CICD - Unit | Integration | E2E #6

Workflow file for this run

# =============================================================================
# CI/CD Pipeline
# =============================================================================
#
# Two-stage pipeline that gates merges to main:
# Stage 1 (test): Unit + integration tests on GH Actions runner
# [TODO] Stage 2 (e2e): Playwright E2E against a real staging deployment
#
# Both stages must pass before a PR can be merged to main.
# Merging to main triggers production deploy via Coolify (existing setup).
#
# REQUIRED BRANCH PROTECTION RULES ON main:
# - Require status checks for unit-integration and e2e
# - Require branches to be up to date before merging
# =============================================================================
name: CI Pipeline
on:
pull_request:
branches: [main]
# =============================================================================
# WHY NO WORKFLOW-LEVEL CONCURRENCY:
#
# We need different concurrency strategies per job:
# - unit-integration: cancel-in-progress per PR (fast feedback on new pushes)
# - e2e: queue globally (staging is a shared single resource)
#
# Workflow-level concurrency would force one strategy for both.
# =============================================================================
jobs:
# ===========================================================================
# STAGE 1: Unit & Integration Tests
# ===========================================================================
#
# Runs Vitest against a local Supabase subset.
#
# Concurrency: cancel-in-progress PER PR. If you push again to the same PR
# while tests are running, the old run is killed immediately. No point
# finishing tests on stale code.
# ===========================================================================
unit-integration:
name: Unit & Integration Tests
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
concurrency:
group: test-pr-${{ github.event.pull_request.number }}
cancel-in-progress: true
# -------------------------------------------------------------------------
# maximum amount of time a job or step can run before GitHub automatically cancels it
# -------------------------------------------------------------------------
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
# use Node version enforced for the project
# see https://github.com/actions/setup-node
with:
node-version-file: '.nvmrc'
cache: "npm"
- name: Install dependencies
run: npm ci
# load the env variables for the sveltekit app
# (slightly) different from .env.ci
- name: Load app env
run: cat cicd/.env.app.ci >> "$GITHUB_ENV"
# -----------------------------------------------------------------------
- name: Run Unit Tests
run: npm run test:unit
- name: Run Integration Tests
if: always()
run: npm run test:integration
- name: Upload unit coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-unit
path: reports/coverage/unit
retention-days: 7
- name: Upload integration coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-integration
path: reports/coverage/integration
retention-days: 7
# https://github.com/davelosert/vitest-coverage-report-action
- name: Report Unit Coverage
# Set if: always() to also generate the report if tests are failing
# Only works if you set `reportOnFailure: true` in your vite config as specified above
if: always()
uses: davelosert/vitest-coverage-report-action@v2
with:
name: Unit
json-summary-path: reports/coverage/unit/coverage-summary.json
json-final-path: reports/coverage/unit/coverage-final.json
vite-config-path: vitest.config.unit.ts
- name: Report Integration Coverage
if: always()
uses: davelosert/vitest-coverage-report-action@v2
with:
name: Integration
json-summary-path: reports/coverage/integration/coverage-summary.json
json-final-path: reports/coverage/integration/coverage-final.json
vite-config-path: vitest.config.integration.ts