make test-frontend runs against a stack of its own

The suite creates and deletes flows, dashboards and users, and ran against
whatever stack was up, which is the dev instance's data. make test-stack starts
the compose project fluksio-test (compose.test.yml over the local stack's
files) with its own containers, volumes and image tags, served by the local
Traefik on app.test.localhost and api.test.localhost, and leaves it running.
The hostname is fixed, so it no longer comes off the running dev stack, and a
LAN stack makes no difference. The suite's default origin is the test stack.
This commit is contained in:
2026-10-15 16:15:32 +02:00
parent 70677dcc20
commit fbd886f7a7
7 changed files with 82 additions and 40 deletions
+39 -28
View File
@@ -3,8 +3,8 @@
# The workspace root delegates to these (see ../Makefile).
.PHONY: init env-check dev-utils dev dev-local dev-lan rebuild-frontend up down update install dev-backend dev-frontend \
generate-client sync-example test test-backend test-checks test-frontend soak bench-startup lint lint-backend \
lint-frontend format-frontend umami build docs docs-serve clean help
generate-client sync-example test test-backend test-checks test-stack test-frontend soak \
bench-startup lint lint-backend lint-frontend format-frontend umami build docs docs-serve clean help
COMPOSE_ROOT := $(CURDIR)
# Explicit project name keeps this stack isolated from the sibling website
@@ -25,6 +25,13 @@ COMPOSE_LOCAL := $(COMPOSE_DEV) -f docker/compose.local.yml
# Same stack, with the frontend also published on APP_PORT and proxying the API
# there, for clients that cannot resolve app.$(DOMAIN).
COMPOSE_LAN := $(COMPOSE_LOCAL) -f docker/compose.lan.yml
# The frontend suite's own stack, a project of its own behind the local Traefik
# (compose.test.yml). The hostname is fixed, never read from a file or the
# command line, so the suite can only ever reach this stack.
TEST_DOMAIN := test.localhost
COMPOSE_TEST := DOMAIN=$(TEST_DOMAIN) STACK_NAME=fluksio-test TAG=test \
docker compose -p fluksio-test --env-file $(COMPOSE_ROOT)/.env -f docker/compose.yml \
-f docker/compose.dev.yml -f docker/compose.local.yml -f docker/compose.test.yml
help: ## Show available targets
@awk 'BEGIN{FS=":.*?## "} /^[a-zA-Z_-]+:.*?##/ {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
@@ -141,6 +148,7 @@ update: ## Pull, rebuild using the layer cache, and recreate changed containers
down: ## Stop all running containers
-$(COMPOSE_LOCAL) down
-$(COMPOSE_TEST) down
-$(COMPOSE_PROD_RUN) down
# ── Development (local, no Docker) ───────────────────────────────
@@ -184,35 +192,38 @@ test-backend: ## Run backend tests (pytest + coverage)
PW_VERSION = $(shell sed -n 's/.*"@playwright\/test": "[^0-9]*\([0-9.]*\)".*/\1/p' frontend/package.json | head -1)
# This suite creates and deletes flows, dashboards and users, so the hostname it
# is pointed at is not taken from any file: it is read off the running stack
# (the frontend container's own Traefik rule) and mapped onto the local Traefik
# by address, so DNS never decides. tests/guard.ts is the second line. The
# suite calls api.<domain> even on a LAN stack, so an api container recreated
# under another DOMAIN would answer every call with Traefik's 404.
test-frontend: ## Run frontend tests (Playwright e2e) against the local stack
# The suite creates and deletes flows, dashboards and users, so it runs against
# a stack of its own, never the dev instance. `up` only recreates what changed,
# and the stack is left running for the next run (and for a look at a failure
# on http://app.test.localhost). `make down` stops it. Its volumes are
# expendable: `docker compose -p fluksio-test down -v` starts it over.
test-stack: ## Start or update the frontend suite's own stack at http://app.test.localhost
@docker ps -q -f name='^fluksio-app-proxy-1$$' | grep -q . \
|| { echo " ✗ the local Traefik is not running, 'make dev' first"; exit 1; }
$(COMPOSE_TEST) up --build -d --wait redis backend frontend
# The Playwright container, minus its network. tests/guard.ts refuses a public
# address on top of the fixed hostname.
PW_RUN = docker run --rm --ipc=host --user $$(id -u):$$(id -g) -e HOME=/tmp \
-v $(COMPOSE_ROOT):/app -w /app/frontend \
-e PLAYWRIGHT_BASE_URL=http://app.$(TEST_DOMAIN) \
-e PLAYWRIGHT_API_URL=http://api.$(TEST_DOMAIN) \
-e CI=$${CI:-1} \
-e FIRST_SUPERUSER="$$(sed -n 's/^FIRST_SUPERUSER=//p' $(COMPOSE_ROOT)/.env | head -1)" \
-e FIRST_SUPERUSER_PASSWORD="$$(sed -n 's/^FIRST_SUPERUSER_PASSWORD=//p' $(COMPOSE_ROOT)/.env | head -1)"
PW_IMAGE = mcr.microsoft.com/playwright:v$(PW_VERSION)-noble
# The names are mapped onto the local Traefik by address, so DNS never decides.
# Twice, because Chromium pins *.localhost to loopback whatever /etc/hosts says.
test-frontend: test-stack ## Run frontend tests (Playwright e2e) against the test stack
@ip=$$(docker network inspect proxy \
--format '{{range .Containers}}{{if eq .Name "fluksio-app-proxy-1"}}{{.IPv4Address}}{{end}}{{end}}' \
2>/dev/null | cut -d/ -f1); \
[ -n "$$ip" ] || { echo " ✗ proxy network or Traefik container not found — is the stack up?"; exit 1; }; \
domain=$$(docker inspect fluksio-app 2>/dev/null \
| grep -o 'Host(`app\.[^`]*`)' | head -1 | sed 's/Host(`app\.//;s/`)//'); \
[ -n "$$domain" ] || { echo " ✗ no running app stack to test — 'make dev' first"; exit 1; }; \
api=$$(docker inspect fluksio-api 2>/dev/null \
| grep -o 'Host(`api\.[^`]*`)' | head -1 | sed 's/Host(`api\.//;s/`)//'); \
[ "$$api" = "$$domain" ] || { echo " ✗ api container is on api.$${api:-?}, the app on app.$$domain — recreate the stack with 'make dev'"; exit 1; }; \
docker run --rm --network proxy --ipc=host \
--user $$(id -u):$$(id -g) -e HOME=/tmp \
--add-host app.$$domain:$$ip --add-host api.$$domain:$$ip \
-v $(COMPOSE_ROOT):/app -w /app/frontend \
-e PLAYWRIGHT_BASE_URL=http://app.$$domain \
-e PLAYWRIGHT_API_URL=http://api.$$domain \
-e HOST_RESOLVER_RULES="MAP app.$$domain $$ip, MAP api.$$domain $$ip" \
-e CI=$${CI:-1} \
-e FIRST_SUPERUSER="$$(sed -n 's/^FIRST_SUPERUSER=//p' $(COMPOSE_ROOT)/.env | head -1)" \
-e FIRST_SUPERUSER_PASSWORD="$$(sed -n 's/^FIRST_SUPERUSER_PASSWORD=//p' $(COMPOSE_ROOT)/.env | head -1)" \
mcr.microsoft.com/playwright:v$(PW_VERSION)-noble \
npx playwright test $(PLAYWRIGHT_ARGS)
[ -n "$$ip" ] || { echo " ✗ the local Traefik is not on the proxy network"; exit 1; }; \
$(PW_RUN) --network proxy \
--add-host app.$(TEST_DOMAIN):$$ip --add-host api.$(TEST_DOMAIN):$$ip \
-e HOST_RESOLVER_RULES="MAP app.$(TEST_DOMAIN) $$ip, MAP api.$(TEST_DOMAIN) $$ip" \
$(PW_IMAGE) npx playwright test $(PLAYWRIGHT_ARGS)
# Load and chaos against a *running* stack, never part of `make test`: it
# restarts this stack's containers. `SOAK_ARGS="--dry-run"` only looks.