Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -468,12 +468,11 @@ migrations.individual.test\#%:

.PHONY: playwright
playwright: deps-frontend
@# on GitHub Actions VMs, playwright's system deps are pre-installed
@pnpm exec playwright install $(if $(GITHUB_ACTIONS),,--with-deps) chromium firefox $(PLAYWRIGHT_FLAGS)
@./tools/test-e2e.sh install

.PHONY: test-e2e
test-e2e: playwright frontend backend
@EXECUTABLE=$(EXECUTABLE) ./tools/test-e2e.sh $(GITEA_TEST_E2E_FLAGS)
@EXECUTABLE=$(EXECUTABLE) ./tools/test-e2e.sh run $(GITEA_TEST_E2E_FLAGS)

.PHONY: build
build: frontend backend ## build everything
Expand Down
101 changes: 100 additions & 1 deletion tools/test-e2e.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,99 @@
#!/bin/bash
set -euo pipefail

CONTAINER_RUNTIME="${CONTAINER_RUNTIME:-docker}"
CONTAINER_NAME="gitea-e2e-runner-$$"

free_port() {
node -e "const s=require('net').createServer();s.listen(0,'127.0.0.1',()=>{process.stdout.write(String(s.address().port));s.close()})"
}

detect_playwright_mode() {
if [ "${PLAYWRIGHT_MODE:-auto}" = "local" ] || [ "${PLAYWRIGHT_MODE:-auto}" = "container" ]; then
return
fi

PLAYWRIGHT_MODE="local"

if [ "$(uname -s)" = "Linux" ]; then
# playwright only supports ubuntu/debian officially
if ! grep -qE '^ID(_LIKE)?=.*(ubuntu|debian)' /etc/os-release 2>/dev/null; then
PLAYWRIGHT_MODE="container"
fi
fi
}

wait_for_container() {
local max_wait=30
local elapsed=0
echo "Waiting for container to start..."
while ! (echo > "/dev/tcp/127.0.0.1/$PLAYWRIGHT_SERVER_PORT") 2>/dev/null; do
if [ "$("$CONTAINER_RUNTIME" inspect -f '{{.State.Running}}' "$CONTAINER_NAME" 2>/dev/null)" != "true" ]; then
echo "Error: container exited before becoming ready." >&2
"$CONTAINER_RUNTIME" logs "$CONTAINER_NAME" >&2 || true
return 1
fi
if [ "$elapsed" -ge "$max_wait" ]; then
echo "Error: container did not become ready after ${max_wait}s." >&2
"$CONTAINER_RUNTIME" logs "$CONTAINER_NAME" >&2 || true
return 1
fi
sleep 1
elapsed=$((elapsed + 1))
done
echo "Container is ready."
}

CMD="${1:-run}"
if [ "$CMD" = "install" ] || [ "$CMD" = "run" ]; then
[ $# -gt 0 ] && shift
else
CMD="run"
fi

detect_playwright_mode

if [ "$PLAYWRIGHT_MODE" = "container" ]; then
if ! command -v "$CONTAINER_RUNTIME" >/dev/null 2>&1; then
echo "error: PLAYWRIGHT_MODE=container but '$CONTAINER_RUNTIME' is not installed." >&2
echo "Install docker/podman or set CONTAINER_RUNTIME to an available runtime." >&2
exit 1
fi
PLAYWRIGHT_VERSION=$(sed -n 's/.*"@playwright\/test"[[:space:]]*:[[:space:]]*"[^[:digit:]]*\([^"]*\)".*/\1/p' package.json)
if ! [[ "$PLAYWRIGHT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]]; then
echo "error: invalid @playwright/test version in package.json: '${PLAYWRIGHT_VERSION}'" >&2
exit 1
fi
PLAYWRIGHT_IMAGE="mcr.microsoft.com/playwright:v${PLAYWRIGHT_VERSION}-noble"
fi

if [ "$CMD" = "install" ]; then
if [ "$PLAYWRIGHT_MODE" = "local" ]; then
# on GitHub Actions VMs, playwright's system deps are pre-installed
if [ -z "${GITHUB_ACTIONS:-}" ]; then
pnpm exec playwright install --with-deps chromium firefox ${PLAYWRIGHT_FLAGS:-}
else
pnpm exec playwright install chromium firefox ${PLAYWRIGHT_FLAGS:-}
fi
else
echo "Running playwright in container as host distro is not supported by playwright directly"
if ! "$CONTAINER_RUNTIME" image inspect "$PLAYWRIGHT_IMAGE" >/dev/null 2>&1; then
"$CONTAINER_RUNTIME" pull "$PLAYWRIGHT_IMAGE"
fi
fi
exit 0
fi

# Create isolated work directory
WORK_DIR=$(mktemp -d)

# Find a random free port
FREE_PORT=$(node -e "const s=require('net').createServer();s.listen(0,'127.0.0.1',()=>{process.stdout.write(String(s.address().port));s.close()})")
FREE_PORT=$(free_port)

cleanup() {
if [ "$PLAYWRIGHT_MODE" = "container" ]; then
"$CONTAINER_RUNTIME" stop "$CONTAINER_NAME" >/dev/null 2>&1 || true
fi
if [ -n "${SERVER_PID:-}" ]; then
kill "$SERVER_PID" 2>/dev/null || true
wait "$SERVER_PID" 2>/dev/null || true
Expand All @@ -16,6 +102,16 @@ cleanup() {
}
trap cleanup EXIT

if [ "$PLAYWRIGHT_MODE" = "container" ]; then
PLAYWRIGHT_SERVER_PORT=$(free_port)
# --network=host: container needs host loopback to reach gitea.
"$CONTAINER_RUNTIME" run --network=host --name "$CONTAINER_NAME" -d --rm --init --workdir /home/pwuser --user pwuser "$PLAYWRIGHT_IMAGE" /bin/sh -c "npx -y playwright@${PLAYWRIGHT_VERSION} run-server --port ${PLAYWRIGHT_SERVER_PORT} --host 0.0.0.0"

if ! wait_for_container; then
exit 1
fi
fi

# Write config file for isolated instance
mkdir -p "$WORK_DIR/custom/conf"
cat > "$WORK_DIR/custom/conf/app.ini" <<EOF
Expand Down Expand Up @@ -112,4 +208,7 @@ export GITEA_TEST_E2E_PASSWORD
export GITEA_TEST_E2E_EMAIL
export GITEA_TEST_E2E_TIMEOUT_FACTOR

if [ "$PLAYWRIGHT_MODE" = "container" ]; then
export PW_TEST_CONNECT_WS_ENDPOINT="ws://127.0.0.1:${PLAYWRIGHT_SERVER_PORT}/"
fi
pnpm exec playwright test "$@"