mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-02 21:03:34 +03:00
# Description of Changes Nightlies keep failing because the Playwright tests only run on Chrome in PRs. This PR changes it so that we run all 3 browsers in all (frontend) PRs so we catch these things before they merge in. They run in parallel so it won't take any more time for the CI to finish.
276 lines
11 KiB
YAML
276 lines
11 KiB
YAML
version: '3'
|
|
|
|
tasks:
|
|
install:
|
|
desc: "Install Playwright browsers"
|
|
dir: frontend/editor
|
|
deps: [ ':frontend:install' ]
|
|
cmds:
|
|
- npx playwright install {{.CLI_ARGS}} --with-deps
|
|
|
|
stubbed:
|
|
desc: "Run stubbed E2E tests"
|
|
dir: frontend/editor
|
|
deps: [ ':frontend:prepare' ]
|
|
cmds:
|
|
- npx playwright test --project=stubbed {{.CLI_ARGS}}
|
|
|
|
stubbed-project:
|
|
desc: "Run the stubbed E2E suite for a single Playwright project"
|
|
dir: frontend/editor
|
|
deps: [ ':frontend:prepare' ]
|
|
vars:
|
|
PROJECT: '{{.PROJECT | default "stubbed"}}'
|
|
cmds:
|
|
- npx playwright test --project={{.PROJECT}} {{.CLI_ARGS}}
|
|
|
|
live:
|
|
desc: "Run live E2E tests"
|
|
summary: |
|
|
Auto-spawns a Spring Boot backend with isolated state under
|
|
.test-state/playwright/ (purged on every run) so the suite doesn't
|
|
touch your local DB, settings.yml, backups or customFiles. The
|
|
backend is stopped automatically when the runner exits.
|
|
|
|
Pass extra Playwright flags via -- :
|
|
task e2e:live -- --headed --grep merge
|
|
deps:
|
|
- live:backend
|
|
- live:runner
|
|
|
|
live:backend:
|
|
internal: true
|
|
ignore_error: true
|
|
vars:
|
|
BASE_DIR: '{{.ROOT_DIR}}/.test-state/playwright'
|
|
# COVERAGE=1 in the calling environment attaches the JaCoCo agent to
|
|
# the bootRun JVM and writes to BASE_DIR/jacoco.exec on shutdown.
|
|
# Off by default to keep local dev runs uninstrumented; CI flips it.
|
|
env:
|
|
STIRLING_BASE_PATH: '{{.BASE_DIR}}'
|
|
# Suppress the analytics opt-in modal that fires on first admin login.
|
|
# It renders a Mantine overlay that intercepts pointer events and blocks
|
|
# FirstLoginSlide from rendering, so the bootstrap spec times out waiting
|
|
# for the password-change prompt.
|
|
SYSTEM_ENABLEANALYTICS: "false"
|
|
# NOTE: SECURITY_INITIALLOGIN_USERNAME/PASSWORD are intentionally NOT set.
|
|
# The live-setup project's bootstrap spec performs the real first-login
|
|
# flow against the backend's default admin/stirling user, exercising the
|
|
# forced-password-change UI and leaving the DB at admin/adminadmin for
|
|
# the rest of the live suite. This is both real coverage of the first-
|
|
# login flow and a stronger seed than env-var-driven user creation.
|
|
cmds:
|
|
# Wrapped in `bash -c` because Task's embedded shell (mvdan/sh) doesn't
|
|
# support `&` + `$!` + `wait` reliably (gradle was never actually
|
|
# backgrounded, so `$!` recorded a stale PID and the runner saw an
|
|
# immediate "backend died"). Real bash backgrounds gradle properly and
|
|
# gives us a stable PID to clean up.
|
|
- |
|
|
bash -c '
|
|
set -e
|
|
rm -rf "{{.BASE_DIR}}"
|
|
mkdir -p "{{.BASE_DIR}}"
|
|
GRADLE_ARGS=":stirling-pdf:bootRun"
|
|
if [ -n "${COVERAGE:-}" ]; then
|
|
# copyJacocoAgent is wired as a dependency of bootRun when
|
|
# -PjacocoAgent=true, so we do not need to invoke it separately.
|
|
GRADLE_ARGS="$GRADLE_ARGS -PjacocoAgent=true -PjacocoExec={{.BASE_DIR}}/jacoco.exec"
|
|
echo "JaCoCo coverage enabled, writing to {{.BASE_DIR}}/jacoco.exec"
|
|
fi
|
|
# Background gradle and record its PID so the runner can clean up
|
|
# the exact process tree (wrapper + forked Spring Boot JVM) without
|
|
# resorting to fuzzy `pkill -f` patterns. `wait` keeps this script
|
|
# alive for the lifetime of gradle so Task'"'"'s parallel deps stay
|
|
# synchronised.
|
|
bash gradlew $GRADLE_ARGS > "{{.BASE_DIR}}/backend.log" 2>&1 &
|
|
GRADLE_PID=$!
|
|
echo $GRADLE_PID > "{{.BASE_DIR}}/backend.pid"
|
|
wait $GRADLE_PID
|
|
'
|
|
|
|
live:runner:
|
|
internal: true
|
|
deps: [ ':frontend:prepare' ]
|
|
dir: frontend/editor
|
|
vars:
|
|
BASE_DIR: '{{.ROOT_DIR}}/.test-state/playwright'
|
|
cmds:
|
|
# Wrapped in `bash -c` because Task's embedded shell (mvdan/sh) only
|
|
# supports `EXIT`/`ERR` in `trap`, not `INT`/`TERM`. CLI_ARGS are
|
|
# passed positionally so quoted args like --grep "foo bar" survive.
|
|
- |
|
|
bash -c '
|
|
set +e
|
|
# bootRun forks a separate Spring Boot JVM as a child of the gradle
|
|
# wrapper; killing only the wrapper leaves that JVM orphaned holding
|
|
# :8080. Walk the recorded PID'"'"'s process tree via pgrep so we kill
|
|
# every descendant, then lsof as a last-resort backstop.
|
|
kill_tree() {
|
|
local pid=$1
|
|
for child in $(pgrep -P "$pid" 2>/dev/null); do
|
|
kill_tree "$child"
|
|
done
|
|
kill "$pid" 2>/dev/null || true
|
|
}
|
|
cleanup() {
|
|
if [ -f "{{.BASE_DIR}}/backend.pid" ]; then
|
|
echo "Stopping backend..."
|
|
kill_tree "$(cat "{{.BASE_DIR}}/backend.pid")"
|
|
sleep 1
|
|
lsof -ti:8080 2>/dev/null | xargs kill 2>/dev/null || true
|
|
echo "Backend stopped"
|
|
fi
|
|
}
|
|
# Trap so cleanup runs on every exit path: tests pass, tests fail,
|
|
# backend never starts, user Ctrl-Cs. Without this the gradle JVM
|
|
# is left orphaned holding :8080 whenever the wait loop times out.
|
|
trap cleanup EXIT INT TERM
|
|
|
|
echo "Waiting for backend on :8080 (up to 10min; first compile can be slow)..."
|
|
WAITED=0
|
|
while [ $WAITED -lt 600 ]; do
|
|
if curl -sf http://localhost:8080/api/v1/info/status 2>/dev/null | grep -q UP; then
|
|
echo "Backend ready, starting Playwright"
|
|
break
|
|
fi
|
|
# Bail early if the backend already died: no point waiting 10min.
|
|
if [ -f "{{.BASE_DIR}}/backend.pid" ]; then
|
|
BACKEND_PID=$(cat "{{.BASE_DIR}}/backend.pid")
|
|
if ! kill -0 "$BACKEND_PID" 2>/dev/null; then
|
|
echo "Backend process exited before becoming ready; last 100 log lines:"
|
|
tail -100 "{{.BASE_DIR}}/backend.log" 2>/dev/null || true
|
|
exit 1
|
|
fi
|
|
fi
|
|
sleep 2
|
|
WAITED=$((WAITED + 2))
|
|
done
|
|
if [ $WAITED -ge 600 ]; then
|
|
echo "Backend did not become ready within 10min, aborting"
|
|
exit 1
|
|
fi
|
|
|
|
npx playwright test --project=live "$@"
|
|
' bash {{.CLI_ARGS}}
|
|
|
|
enterprise:
|
|
desc: "Run enterprise E2E tests"
|
|
summary: |
|
|
Requires an already-running keycloak compose stack on :8080. Bring one
|
|
up first with:
|
|
task e2e:oauth:up
|
|
task e2e:saml:up
|
|
dir: frontend/editor
|
|
deps: [ ':frontend:prepare' ]
|
|
cmds:
|
|
- npx playwright test --project=enterprise {{.CLI_ARGS}}
|
|
|
|
cross-browser:
|
|
desc: "Run stubbed E2E tests on Chromium, Firefox, and WebKit"
|
|
dir: frontend/editor
|
|
deps: [ ':frontend:prepare' ]
|
|
cmds:
|
|
- npx playwright test --project=stubbed --project=stubbed-firefox --project=stubbed-webkit {{.CLI_ARGS}}
|
|
|
|
check:
|
|
desc: "Run all E2E tests not requiring Docker"
|
|
cmds:
|
|
- task: stubbed
|
|
- task: live
|
|
|
|
check:all:
|
|
desc: "Run all E2E tests"
|
|
summary: |
|
|
Includes the enterprise project, which requires a keycloak compose
|
|
stack on :8080. Bring one up first with:
|
|
task e2e:oauth:up
|
|
task e2e:saml:up
|
|
cmds:
|
|
- task: stubbed
|
|
- task: live
|
|
- task: enterprise
|
|
|
|
oauth:up:
|
|
desc: "Start the OAuth keycloak test environment"
|
|
summary: |
|
|
Set LICENSE_KEY=<KEY> to skip the interactive license prompt:
|
|
task e2e:oauth:up LICENSE_KEY=abc123
|
|
Pass extra flags via -- :
|
|
task e2e:oauth:up -- --auto --nobuild
|
|
ignore_error: true
|
|
cmds:
|
|
- bash testing/compose/start-oauth-test.sh {{if .LICENSE_KEY}}--license-key "{{.LICENSE_KEY}}"{{end}} {{.CLI_ARGS}}
|
|
|
|
oauth:down:
|
|
desc: "Stop the OAuth keycloak test environment"
|
|
cmds:
|
|
- docker compose -f testing/compose/docker-compose-keycloak-oauth.yml down -v
|
|
|
|
saml:up:
|
|
desc: "Start the SAML keycloak test environment"
|
|
summary: |
|
|
Set LICENSE_KEY=<KEY> to skip the interactive license prompt:
|
|
task e2e:saml:up LICENSE_KEY=abc123
|
|
Pass extra flags via -- :
|
|
task e2e:saml:up -- --auto --with-storage --nobuild --language sv-SE
|
|
ignore_error: true
|
|
cmds:
|
|
- bash testing/compose/start-saml-test.sh {{if .LICENSE_KEY}}--license-key "{{.LICENSE_KEY}}"{{end}} {{.CLI_ARGS}}
|
|
|
|
saml:down:
|
|
desc: "Stop the SAML keycloak test environment"
|
|
cmds:
|
|
- docker compose -f testing/compose/docker-compose-keycloak-saml.yml down -v
|
|
|
|
mcp:up:
|
|
desc: "Start the MCP keycloak test environment (Stirling as OAuth resource server)"
|
|
summary: |
|
|
Brings up Keycloak (OAuth authorization server) + Stirling configured as an
|
|
MCP resource server, then you can exercise /mcp with real Keycloak tokens.
|
|
Set LICENSE_KEY=<KEY> to skip the interactive license prompt:
|
|
task e2e:mcp:up LICENSE_KEY=abc123
|
|
Pass extra flags via -- :
|
|
task e2e:mcp:up -- --validate --nobuild
|
|
ignore_error: true
|
|
cmds:
|
|
- bash testing/compose/start-mcp-test.sh {{if .LICENSE_KEY}}--license-key "{{.LICENSE_KEY}}"{{end}} {{.CLI_ARGS}}
|
|
|
|
mcp:manual:
|
|
desc: "Start the MCP keycloak test env in manual mode (prints URLs + a live token for your client)"
|
|
summary: |
|
|
Brings the stack up and prints copy-paste URLs/commands plus a freshly minted
|
|
access token so you can drive your own MCP client (Inspector, curl, ...).
|
|
task e2e:mcp:manual LICENSE_KEY=<your-license-key>
|
|
Add --nobuild if the images are already built:
|
|
task e2e:mcp:manual LICENSE_KEY=<your-license-key> -- --nobuild
|
|
ignore_error: true
|
|
cmds:
|
|
- bash testing/compose/start-mcp-test.sh --manual {{if .LICENSE_KEY}}--license-key "{{.LICENSE_KEY}}"{{end}} {{.CLI_ARGS}}
|
|
|
|
mcp:apikey:
|
|
desc: "Start the MCP test env in API-KEY manual mode (no OAuth/IdP): mints a key + prints client settings"
|
|
summary: |
|
|
Brings Stirling up in apikey auth mode and prints copy-paste client settings with a freshly
|
|
minted X-API-KEY - ideal for clients whose OAuth layer can't reach localhost.
|
|
task e2e:mcp:apikey LICENSE_KEY=<your-license-key>
|
|
Add --nobuild if images are already built:
|
|
task e2e:mcp:apikey LICENSE_KEY=<your-license-key> -- --nobuild
|
|
ignore_error: true
|
|
cmds:
|
|
- bash testing/compose/start-mcp-test.sh --apikey {{if .LICENSE_KEY}}--license-key "{{.LICENSE_KEY}}"{{end}} {{.CLI_ARGS}}
|
|
|
|
mcp:validate:
|
|
desc: "Validate the running MCP keycloak test environment end-to-end (oauth mode + real MCP SDK client)"
|
|
cmds:
|
|
- bash testing/compose/validate-mcp-test.sh
|
|
|
|
mcp:validate-apikey:
|
|
desc: "Validate the MCP server in API-KEY auth mode (mints a key + real MCP SDK client), then restore oauth"
|
|
cmds:
|
|
- bash testing/compose/validate-mcp-apikey.sh
|
|
|
|
mcp:down:
|
|
desc: "Stop the MCP keycloak test environment"
|
|
cmds:
|
|
- docker compose -f testing/compose/docker-compose-keycloak-mcp.yml down -v
|