Skip to content

chore(deps): bump @playwright/test from 1.59.1 to 1.60.0 #1447

chore(deps): bump @playwright/test from 1.59.1 to 1.60.0

chore(deps): bump @playwright/test from 1.59.1 to 1.60.0 #1447

Workflow file for this run

name: E2E Tests
on:
pull_request:
paths-ignore:
- '**/*.md'
- 'docs/**'
- 'research/**'
- 'context/**'
- 'architecture/**'
- 'meta/**'
- 'CLAUDE.md'
push:
branches: [main, dev]
paths-ignore:
- '**/*.md'
- 'docs/**'
- 'research/**'
- 'context/**'
- 'architecture/**'
- 'meta/**'
- 'CLAUDE.md'
permissions:
contents: read
concurrency:
group: e2e-${{ github.ref }}
cancel-in-progress: true
# ---------------------------------------------------------------------------
# Shared setup steps are factored into a reusable composite across jobs.
# Both jobs (smoke, maintained) need a running server + web client, so the
# build outputs are cached via actions/cache and the service container is
# declared per-job.
# ---------------------------------------------------------------------------
jobs:
# -------------------------------------------------------------------------
# Smoke — fast-fail gate on every push.
# Runs local_full.spec.ts (full feature surface).
# -------------------------------------------------------------------------
smoke:
name: Smoke
runs-on: ubuntu-latest
timeout-minutes: 30
services:
postgres:
image: postgres:17
env:
POSTGRES_DB: echo_test
POSTGRES_USER: echo
POSTGRES_PASSWORD: test_password
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U echo -d echo_test"
--health-interval 5s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# -- Rust server --
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2.9.1
with:
shared-key: e2e
- name: Build server
run: cargo build --release --package echo-server
# -- Flutter web --
- uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0
with:
flutter-version-file: .flutter-version
channel: stable
cache: true
- name: Build web client
working-directory: apps/client
run: |
flutter pub get
flutter build web --release --pwa-strategy=none --dart-define=APP_VERSION=0.0.0-e2e
# -- Start services --
- name: Start server
run: |
./target/release/echo-server &
sleep 5
curl --retry 10 --retry-delay 2 --retry-connrefused -s http://localhost:8080/api/health
env:
DATABASE_URL: postgres://echo:test_password@localhost:5432/echo_test
JWT_SECRET: ${{ format('ci-test-secret-{0}-attempt-{1}-padding', github.run_id, github.run_attempt) }}
RUST_LOG: echo_server=info
SERVER_HOST: 0.0.0.0
SERVER_PORT: 8080
CORS_ORIGINS: http://localhost:8081
- name: Install serve
# Pinned to a specific version so we don't pull a different `serve` per
# CI run (#533). The Playwright runner below uses the tracked lockfile.
run: npm install -g serve@14.2.5
- name: Serve web client
run: |
serve -s apps/client/build/web -l 8081 &
sleep 3
curl --retry 10 --retry-delay 2 --retry-connrefused -sf http://localhost:8081/ > /dev/null
# -- Playwright --
- name: Install Playwright dependencies
working-directory: tests/e2e
# `npm ci` against the tracked lockfile so the installed Playwright
# version is exactly what was committed (#533).
run: |
npm ci
npx playwright install --with-deps chromium
- name: Validate spec coverage
working-directory: tests/e2e
# Every *.spec.ts file must be listed in exactly one project inside
# playwright.config.ts. This step fails CI if a new spec is added
# without being assigned to the smoke, maintained, or manual lane.
run: |
missing=()
for spec in $(find . -maxdepth 1 -name '*.spec.ts' | sed 's|^\./||' | sort); do
if ! grep -qE "(['\"])${spec}\1" playwright.config.ts; then
missing+=("$spec")
fi
done
if [ ${#missing[@]} -ne 0 ]; then
echo "ERROR: the following spec files are not assigned to any lane in playwright.config.ts:"
printf ' %s\n' "${missing[@]}"
exit 1
fi
echo "All spec files are covered by a lane."
- name: Install websocat
run: |
sudo apt-get update -qq
sudo apt-get install -y websocat || cargo install websocat --locked
- name: Run smoke tests
# Smoke lane: local_full.spec.ts exercises the full feature surface
# in a single end-to-end flow.
# `--retries=1` absorbs single-flake noise without masking real failures.
working-directory: tests/e2e
run: npx playwright test --project=smoke --retries=1
env:
DATABASE_URL: postgres://echo:test_password@localhost:5432/echo_test
JWT_SECRET: ${{ format('ci-test-secret-{0}-attempt-{1}-padding', github.run_id, github.run_attempt) }}
- name: Upload smoke artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
with:
name: e2e-smoke-results
path: |
tests/e2e/test-results/
retention-days: 7
# -------------------------------------------------------------------------
# Maintained — full suite of targeted UI and protocol specs.
# 9 specs: semantics_e2e, group_create_ui, group_messaging_ui,
# hover_then_type, crypto_dm_test, comprehensive, echo_e2e,
# qa_comprehensive, ws_check.
# -------------------------------------------------------------------------
maintained:
name: Maintained Suite
runs-on: ubuntu-latest
timeout-minutes: 30
services:
postgres:
image: postgres:17
env:
POSTGRES_DB: echo_test
POSTGRES_USER: echo
POSTGRES_PASSWORD: test_password
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U echo -d echo_test"
--health-interval 5s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
# -- Rust server --
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2.9.1
with:
shared-key: e2e
- name: Build server
run: cargo build --release --package echo-server
# -- Flutter web --
- uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2.23.0
with:
flutter-version-file: .flutter-version
channel: stable
cache: true
- name: Build web client
working-directory: apps/client
run: |
flutter pub get
flutter build web --release --pwa-strategy=none --dart-define=APP_VERSION=0.0.0-e2e
# -- Start services --
- name: Start server
run: |
./target/release/echo-server &
sleep 5
curl --retry 10 --retry-delay 2 --retry-connrefused -s http://localhost:8080/api/health
env:
DATABASE_URL: postgres://echo:test_password@localhost:5432/echo_test
JWT_SECRET: ${{ format('ci-test-secret-{0}-attempt-{1}-padding', github.run_id, github.run_attempt) }}
RUST_LOG: echo_server=info
SERVER_HOST: 0.0.0.0
SERVER_PORT: 8080
CORS_ORIGINS: http://localhost:8081
- name: Install serve
run: npm install -g serve@14.2.5
- name: Serve web client
run: |
serve -s apps/client/build/web -l 8081 &
sleep 3
curl --retry 10 --retry-delay 2 --retry-connrefused -sf http://localhost:8081/ > /dev/null
# -- Playwright --
- name: Install Playwright dependencies
working-directory: tests/e2e
run: |
npm ci
npx playwright install --with-deps chromium
- name: Install websocat
run: |
sudo apt-get update -qq
sudo apt-get install -y websocat || cargo install websocat --locked
- name: Run maintained E2E suite
# 9 specs: semantics_e2e, group_create_ui, group_messaging_ui,
# hover_then_type, crypto_dm_test, comprehensive, echo_e2e,
# qa_comprehensive, ws_check.
# `--retries=2` absorbs single-flake noise.
working-directory: tests/e2e
run: npx playwright test --project=maintained --retries=2
env:
DATABASE_URL: postgres://echo:test_password@localhost:5432/echo_test
JWT_SECRET: ${{ format('ci-test-secret-{0}-attempt-{1}-padding', github.run_id, github.run_attempt) }}
- name: Upload maintained artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: always()
with:
name: e2e-maintained-results
path: |
tests/e2e/test-results/
retention-days: 7
# -------------------------------------------------------------------------
# Summary gate -- require "E2E Tests / Summary" in branch protection.
# Both lanes are strict. Smoke failure blocks the gate; maintained failure
# also fails the gate (retries=2 absorbs flakes).
# -------------------------------------------------------------------------
summary:
name: Summary
runs-on: ubuntu-latest
needs: [smoke, maintained]
if: always()
steps:
- name: E2E gate
run: |
smoke_result="${{ needs.smoke.result }}"
maintained_result="${{ needs.maintained.result }}"
echo "smoke=${smoke_result} maintained=${maintained_result}"
if [ "$smoke_result" != "success" ]; then
echo "::error::Smoke job was ${smoke_result} -- gate failed"
exit 1
fi
if [ "$maintained_result" != "success" ]; then
echo "::error::Maintained suite was ${maintained_result} -- gate failed"
exit 1
fi
echo "E2E gate passed."