Files
computer-playbook/scripts/tests/e2e/rerun-spec.sh
kevinveenbirkenbach 87f762bd75 fix(e2e): derive the shared Playwright helpers instead of listing them
A helper that no stager copies fails at import, and it fails for every
role that imports it at once, because the whole spec file stops loading.
That is what mcp-endpoint.js did to all ten MCP specs: they ran zero
tests rather than one failing one.

The set lived in three places and no two agreed - the deploy task named
four helpers, rerun-spec.sh named three, and the specs required five.
addon-gating.js was already missing from the rerun path before any of
this. Both stagers now glob the runner's own files/*.js, minus the
config, so the directory listing is the set.

The lint derives what must be staged from the requires the specs
actually make, and holds both stagers to globbing, since a set that can
be typed twice will differ twice.
2026-08-29 10:45:20 +02:00

138 lines
4.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Rerun a role-local Playwright spec against the live running stack.
#
# Preconditions:
# - The role has been deployed at least once, so the Playwright project is
# staged under $TEST_E2E_PLAYWRIGHT_STAGE_BASE_DIR/<role> with a rendered
# .env file.
# - The application under test is still running.
#
# The stage base comes from INFINITO_PLAYWRIGHT_STAGE_BASE_DIR (env handler);
# DiD nodes run this without a generated .env, so the script falls back to
# the same role-vars SPOT the handler reads.
#
# This script intentionally does NOT re-render .env. It restages the
# role-local Playwright files (spec + companions) from the repo and reruns
# Playwright via the same container image the deploy-time runner uses.
#
# Usage:
# scripts/tests/e2e/rerun-spec.sh <role> [playwright args...] # nocheck: self-path-reference
# scripts/tests/e2e/rerun-spec.sh web-app-nextcloud --grep "talk admin" # nocheck: self-path-reference
set -euo pipefail
if [[ $# -lt 1 ]]; then
echo "usage: $0 <role> [playwright args...]" >&2
exit 2
fi
role="$1"
shift
repo_root="$(cd "$(dirname "$0")/../../.." && pwd)"
role_playwright_dir="$repo_root/roles/$role/files/playwright"
spec_src="$role_playwright_dir/playwright.spec.js"
services_yml="$repo_root/roles/test-e2e-playwright/meta/services.yml"
stage_base="${INFINITO_PLAYWRIGHT_STAGE_BASE_DIR:-}"
if [[ -z "$stage_base" ]]; then
stage_base="$(awk '$1 == "TEST_E2E_PLAYWRIGHT_STAGE_BASE_DIR:" {gsub(/"/, "", $2); print $2}' \
"$repo_root/roles/test-e2e-playwright/vars/main.yml")"
fi
[[ -n "$stage_base" ]] || {
echo "TEST_E2E_PLAYWRIGHT_STAGE_BASE_DIR missing in roles/test-e2e-playwright/vars/main.yml (SPOT)" >&2
exit 2
}
# shellcheck source=/dev/null
source <(grep -E '^INFINITO_PLAYWRIGHT_REPORTS_BASE_DIR=' "$repo_root/.env")
reports_base="${INFINITO_PLAYWRIGHT_REPORTS_BASE_DIR:?INFINITO_PLAYWRIGHT_REPORTS_BASE_DIR missing in .env (SPOT)}"
stage_dir="$stage_base/$role"
reports_dir="$reports_base/$role"
env_file="$stage_dir/.env"
[[ -f "$spec_src" ]] || {
echo "missing spec: $spec_src" >&2
exit 1
}
[[ -d "$stage_dir" ]] || {
echo "missing staging dir (run deploy first): $stage_dir" >&2
exit 1
}
[[ -f "$env_file" ]] || {
echo "missing rendered env (run deploy first): $env_file" >&2
exit 1
}
image="${TEST_E2E_PLAYWRIGHT_IMAGE:-}"
if [[ -z "$image" ]]; then
base_image="$(awk '/^[[:space:]]*image:[[:space:]]/{print $2; exit}' "$services_yml")"
tag="$(awk -F'"' '/^[[:space:]]*version:[[:space:]]/{print $2; exit}' "$services_yml")"
image="${base_image}:${tag}"
fi
command -v docker >/dev/null || {
echo "docker not found in PATH" >&2
exit 1
}
mkdir -p "$stage_dir/tests" "$stage_dir/volume" "$reports_dir"
for role_js in "$role_playwright_dir"/*.js; do
[[ -f "$role_js" ]] || continue
cp "$role_js" "$stage_dir/tests/$(basename "$role_js")"
done
for helper_src in "$repo_root/roles/test-e2e-playwright/files"/*.js; do
[[ -f "$helper_src" ]] || continue
[[ "$(basename "$helper_src")" == "playwright.config.js" ]] && continue
cp "$helper_src" "$stage_dir/tests/$(basename "$helper_src")"
done
personas_dir="$repo_root/roles/test-e2e-playwright/files/personas"
if [[ -d "$personas_dir" ]]; then
mkdir -p "$stage_dir/tests/personas/utils"
for persona_file in "$personas_dir"/*.js; do
[[ -f "$persona_file" ]] || continue
cp "$persona_file" "$stage_dir/tests/personas/$(basename "$persona_file")"
done
for util_file in "$personas_dir"/utils/*.js; do
[[ -f "$util_file" ]] || continue
cp "$util_file" "$stage_dir/tests/personas/utils/$(basename "$util_file")"
done
fi
for sub in addons fixtures; do
sub_dir="$role_playwright_dir/$sub"
[[ -d "$sub_dir" ]] || continue
mkdir -p "$stage_dir/tests/$sub"
for sub_file in "$sub_dir"/*.js; do
[[ -f "$sub_file" ]] || continue
cp "$sub_file" "$stage_dir/tests/$sub/$(basename "$sub_file")"
done
done
cmd="${TEST_E2E_PLAYWRIGHT_COMMAND:-npm install --no-fund --no-audit && npx playwright test${*:+ $*}}"
if [[ "${TEST_E2E_PLAYWRIGHT_NETWORK_HOST:-}" == "true" ]]; then
net_args=(--network host)
proxy_host="127.0.0.1"
else
net_args=(--add-host=host.docker.internal:host-gateway)
proxy_host="host.docker.internal"
fi
proxy_env=()
if grep -qiE '\.onion' "$env_file"; then
default_proxy="socks5://${proxy_host}:${INFINITO_TOR_SOCKS_PORT:?INFINITO_TOR_SOCKS_PORT unset (built by the env handler from svc-net-tor services.tor.ports.local.socks)}"
proxy_env=(-e "PLAYWRIGHT_PROXY=${PLAYWRIGHT_PROXY:-$default_proxy}")
fi
exec docker run --rm \
--ipc=host --shm-size=1g \
"${net_args[@]}" \
--env-file "$env_file" \
"${proxy_env[@]}" \
-v "$stage_dir:/e2e" \
-v "$stage_dir/volume:/volume" \
-v "$reports_dir:/reports" \
-w /e2e \
"$image" \
/bin/bash -lc "$cmd"