Files
galaxy-game/.gitea/workflows/ui-test.yaml
T
Ilia Denisov eb549e6049
Tests · UI / test (push) Waiting to run
Tests · UI / test (pull_request) Successful in 3m24s
ci(ui-test): clean root-owned build artifacts so runner teardown succeeds
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.
2026-05-31 12:15:32 +02:00

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