eb549e6049
In host-mode the ui-test job runs as root, so vite (test:pwa),
svelte-kit and Playwright write build/, .svelte-kit/, test-results/ and
playwright-report/ root-owned into the shared host workspace. The
act_runner (non-root) then cannot remove them at teardown
("unlinkat ui/frontend/build: permission denied"), which spuriously
marks this or a sibling job that inherits the dirty workspace as failed
— it hit go-unit on the #83 merge even though every test passed.
Add an `if: always()` step that removes those generated dirs while the
job still has root, after the artifact uploads. Keeps the shared
workspace clean for the runner's own teardown and for later jobs.
135 lines
4.6 KiB
YAML
135 lines
4.6 KiB
YAML
name: Tests · UI
|
|
|
|
# UI-side unit and end-to-end tests (Vitest + Playwright). The Go side
|
|
# of the workspace is tested in `go-unit.yaml`. Both workflows can run
|
|
# in parallel for a push that touches Go and UI together.
|
|
|
|
on:
|
|
push:
|
|
paths:
|
|
- 'ui/**'
|
|
- '.gitea/workflows/ui-test.yaml'
|
|
- '!**/*.md'
|
|
pull_request:
|
|
paths:
|
|
- 'ui/**'
|
|
- '.gitea/workflows/ui-test.yaml'
|
|
- '!**/*.md'
|
|
|
|
# Playwright launches its own `pnpm dev` on :5173, and in host-mode
|
|
# the runner shares the host's port namespace with every other job,
|
|
# so two parallel ui-test runs collide on EADDRINUSE. Serialise via a
|
|
# singleton concurrency group with queueing — new runs wait their
|
|
# turn instead of cancelling the in-progress one. cancel-in-progress
|
|
# is explicitly false because Gitea has shown spurious self-cancel
|
|
# behaviour under cancel-in-progress: true even when no other run
|
|
# shares the group.
|
|
concurrency:
|
|
group: ui-test-singleton
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
submodules: recursive
|
|
|
|
- name: Set up pnpm
|
|
uses: pnpm/action-setup@v4
|
|
with:
|
|
version: 11.0.7
|
|
# Install pnpm into a per-job directory so concurrent jobs on
|
|
# the shared host runner do not race on the default
|
|
# `~/setup-pnpm` (the self-installer otherwise fails with
|
|
# `ENOTEMPTY` while cleaning a sibling job's install).
|
|
dest: ${{ runner.temp }}/setup-pnpm
|
|
|
|
- name: Set up Node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
cache-dependency-path: ui/pnpm-lock.yaml
|
|
|
|
- name: Install npm dependencies
|
|
working-directory: ui
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v5
|
|
with:
|
|
go-version-file: go.work
|
|
cache: true
|
|
|
|
- name: Build core.wasm
|
|
uses: ./.gitea/actions/build-wasm
|
|
|
|
- name: Install Playwright browsers
|
|
# `--with-deps` would shell out to `sudo apt-get install` for
|
|
# the system .so libraries, which the host-mode runner cannot
|
|
# run non-interactively. The host has the deps installed once,
|
|
# globally; we only need to fetch the browser binaries here.
|
|
# If a future run fails with missing libraries, install them
|
|
# on the host via `pnpm exec playwright install-deps` (one
|
|
# shot, requires sudo).
|
|
working-directory: ui/frontend
|
|
run: pnpm exec playwright install
|
|
|
|
- name: Run Vitest
|
|
working-directory: ui/frontend
|
|
run: pnpm test
|
|
|
|
- name: Clear stale Vite from :5173
|
|
# Defence in depth in case a previous job's webServer survived
|
|
# the concurrency-cancel — `pkill` does not fail when there is
|
|
# nothing to kill, and `fuser -k` cleans up anything else
|
|
# holding the port.
|
|
run: |
|
|
pkill -f 'vite dev' || true
|
|
fuser -k 5173/tcp 2>/dev/null || true
|
|
|
|
- name: Run Playwright
|
|
working-directory: ui/frontend
|
|
run: pnpm exec playwright test
|
|
|
|
- name: Run PWA tests
|
|
# Builds + previews the production bundle (the service worker only
|
|
# precaches a real build) and checks manifest / SW / offline.
|
|
working-directory: ui/frontend
|
|
run: pnpm test:pwa
|
|
|
|
- name: Upload Playwright report on failure
|
|
if: failure()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: playwright-report
|
|
path: ui/frontend/playwright-report/
|
|
retention-days: 14
|
|
|
|
- name: Upload Playwright traces on failure
|
|
if: failure()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: playwright-traces
|
|
path: ui/frontend/test-results/
|
|
retention-days: 14
|
|
|
|
- name: Remove root-owned build artifacts
|
|
if: always()
|
|
# In host-mode the job runs as root, so vite (test:pwa),
|
|
# svelte-kit and Playwright write these outputs root-owned into
|
|
# the shared host workspace. The act_runner (non-root) then
|
|
# cannot remove them at teardown ("unlinkat ... permission
|
|
# denied"), which spuriously fails this or a sibling job that
|
|
# inherits the dirty workspace (observed on go-unit). Clean them
|
|
# here while the step still has root, after the uploads above.
|
|
run: |
|
|
rm -rf ui/frontend/build ui/frontend/.svelte-kit \
|
|
ui/frontend/test-results ui/frontend/playwright-report
|