Skip to content

build(deps): bump python from 2c941e8 to e5c9fa2 #196

build(deps): bump python from 2c941e8 to e5c9fa2

build(deps): bump python from 2c941e8 to e5c9fa2 #196

Workflow file for this run

name: UI tests
# Runs the Playwright UI suite (-m ui) so it cannot rot silently the way two
# settings tests did. The main CI job runs `-m "not ui"`, so without this the
# UI tests would never execute. Path-filtered to frontend changes to spare the
# single self-hosted host, plus a nightly run to catch drift, plus manual.
#
# Shares the host-global container lock with ci.yml's `test` job and
# e2e-staging: all three bind the fixed-name test container on port 18888 and
# must never run at once on the self-hosted host (#295).
on:
pull_request:
branches: [ main, develop ]
paths:
- 'templates/**'
- 'static/**'
- 'tests/test_ui.py'
- 'tests/conftest.py'
- 'Dockerfile'
- '.github/workflows/ui-tests.yml'
schedule:
- cron: '41 4 * * *' # nightly drift catch
workflow_dispatch:
permissions: read-all
concurrency:
group: ui-${{ github.ref }}
cancel-in-progress: true
jobs:
ui:
name: ui
runs-on: [self-hosted, Linux, X64]
# Same host-global lock ci.yml's `test` job uses: the UI suite binds the
# fixed-name test container on port 18888, so it must queue behind (never
# run beside) any other test job on the self-hosted host. Putting this
# shared group at workflow level instead made a co-triggered workflow cancel
# this run at 1s; keep it job-level, cancel-in-progress false so it queues.
concurrency:
group: certmate-selfhosted-test-container
cancel-in-progress: false
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Python 3.12
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.12'
- name: Cache pip dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install -r requirements-test.txt
- name: Install Playwright Chromium
# --with-deps installs the system libraries (libnss3, libasound2, ...)
# Chromium needs, but it shells out to sudo — which this self-hosted
# host does not grant passwordlessly. Use it when it is available and
# fall back to the plain install otherwise; either way the launch check
# below is what decides, so a host missing those libraries fails the
# job instead of skipping every test and reporting green (#414).
run: |
if sudo -n true 2>/dev/null; then
python -m playwright install --with-deps chromium
else
echo "passwordless sudo unavailable; installing browser only"
python -m playwright install chromium
fi
- name: Verify Chromium actually launches
# Fail here, loudly and in one line, rather than inside 17 fixtures.
run: |
python - <<'PY'
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
b = p.chromium.launch(headless=True)
print("chromium", b.version)
b.close()
PY
- name: UI tests
# CERTMATE_UI_REQUIRE_BROWSER=1 turns "browser unavailable" from a skip
# into a failure, so this job can no longer report success without
# having driven a browser.
env:
CERTMATE_UI_REQUIRE_BROWSER: '1'
run: python -m pytest -v -m ui --junitxml=ui-results.xml
- name: Refuse a green run that asserted nothing
if: always()
# The last line of defence: if every collected UI test skipped (or none
# were collected at all), the job fails. A suite that runs zero tests is
# not a passing suite.
run: |
python - <<'PY'
import sys, xml.etree.ElementTree as ET
try:
root = ET.parse("ui-results.xml").getroot()
except Exception as e:
sys.exit(f"no UI test results to check: {e}")
suites = root.iter("testsuite")
total = skipped = 0
for s in suites:
total += int(s.get("tests", 0))
skipped += int(s.get("skipped", 0))
print(f"collected={total} skipped={skipped}")
if total == 0:
sys.exit("UI suite collected 0 tests")
if skipped == total:
sys.exit("every UI test skipped - the suite proved nothing")
PY