Local test targets read the running stack, not the deployment's domain
Docs / docs (push) Successful in 21s
Playwright Tests / test-playwright (1, 2) (push) Successful in 1m57s
Playwright Tests / test-playwright (2, 2) (push) Successful in 1m43s
pre-commit / pre-commit (push) Failing after 3m32s
Test Backend / test-backend (push) Successful in 2m18s
Compose Smoke Test / test-compose (push) Successful in 31s
Playwright Tests / merge-reports (push) Successful in 1m27s
Docs / docs (push) Successful in 21s
Playwright Tests / test-playwright (1, 2) (push) Successful in 1m57s
Playwright Tests / test-playwright (2, 2) (push) Successful in 1m43s
pre-commit / pre-commit (push) Failing after 3m32s
Test Backend / test-backend (push) Successful in 2m18s
Compose Smoke Test / test-compose (push) Successful in 31s
Playwright Tests / merge-reports (push) Successful in 1m27s
`make test-frontend` built PLAYWRIGHT_BASE_URL from DOMAIN in .env, which in a checkout configured for a deployment is that deployment's domain — so the suite that creates and deletes flows, dashboards and users was pointed at app.fluksio.com, held local only by --add-host and tests/guard.ts. The hostname now comes off the running stack (the frontend container's own Traefik rule), so a name no local container answers to cannot be reached at all, and the local targets default to *.localhost instead of reading .env. Target-specific on purpose: an exported DOMAIN outranks --env-file in compose interpolation and would put the production targets on localhost. `rebuild-frontend` replaces the raw compose line CLAUDE.md spelled out, taking the same domain so the baked VITE_API_URL cannot disagree with what Traefik serves. Also: a coverage HTML report that cannot be written no longer fails test-backend after a green suite, and both artifact actions in playwright.yml drop to @v3, which is the only version without the github.com-only guard that failed every run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -87,13 +87,16 @@ jobs:
|
||||
- name: Tear down
|
||||
if: always()
|
||||
run: docker compose down -v --remove-orphans
|
||||
# v3 deliberately: @v4 of both artifact actions refuses to run against
|
||||
# anything that is not github.com (GHESNotSupportedError), which failed
|
||||
# every run here after the tests had already passed. `include-hidden-files`
|
||||
# is v4-only and comes off with it — a blob report holds no dotfiles.
|
||||
- name: Upload blob report
|
||||
if: ${{ !cancelled() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: blob-report-${{ matrix.shardIndex }}
|
||||
path: frontend/blob-report
|
||||
include-hidden-files: true
|
||||
retention-days: 1
|
||||
|
||||
merge-reports:
|
||||
@@ -108,19 +111,23 @@ jobs:
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- name: Install dependencies
|
||||
run: bun install --frozen-lockfile
|
||||
# v3 has no `pattern:`/`merge-multiple:`, so it lands one directory per
|
||||
# artifact and merge-reports needs them flattened first.
|
||||
- name: Download blob reports
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: frontend/all-blob-reports
|
||||
pattern: blob-report-*
|
||||
merge-multiple: true
|
||||
- name: Flatten the per-shard directories
|
||||
run: |
|
||||
find frontend/all-blob-reports -mindepth 2 -type f \
|
||||
-exec mv -t frontend/all-blob-reports {} +
|
||||
find frontend/all-blob-reports -mindepth 1 -type d -empty -delete
|
||||
- name: Merge into an HTML report
|
||||
run: bunx playwright merge-reports --reporter html ./all-blob-reports
|
||||
working-directory: frontend
|
||||
- name: Upload HTML report
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: html-report--attempt-${{ github.run_attempt }}
|
||||
path: frontend/playwright-report
|
||||
include-hidden-files: true
|
||||
retention-days: 7
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Convenience targets for development, testing, linting, and deployment.
|
||||
# The workspace root delegates to these (see ../Makefile).
|
||||
|
||||
.PHONY: dev-utils dev dev-local dev-lan up down update install dev-backend dev-frontend \
|
||||
.PHONY: 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-frontend soak bench-startup lint lint-backend \
|
||||
lint-frontend format-frontend umami build docs docs-serve clean help
|
||||
|
||||
@@ -31,6 +31,14 @@ help: ## Show available targets
|
||||
|
||||
# ── Development (Docker) ──────────────────────────────────────────
|
||||
|
||||
# Hostname the local stack is served under. Never .env's DOMAIN: a checkout
|
||||
# configured for a deployment carries that deployment's domain, and a local
|
||||
# stack started under it answers to the same names the live installation does.
|
||||
# Target-specific on purpose — an exported DOMAIN outranks --env-file in
|
||||
# compose interpolation, which would put the *production* targets on localhost.
|
||||
# `make dev DOMAIN=fluksio.com` still wins.
|
||||
dev dev-utils dev-local dev-lan rebuild-frontend: export DOMAIN ?= localhost
|
||||
|
||||
dev-utils: ## Start only the utility containers (proxy, mailcatcher)
|
||||
$(COMPOSE_DEV) up --build proxy mailcatcher
|
||||
|
||||
@@ -45,6 +53,15 @@ dev-lan: ## Same, plus the app on http://<host-ip>:$(APP_PORT) (no DNS needed)
|
||||
DOMAIN=$${DOMAIN:-localhost} ENVIRONMENT=$${ENVIRONMENT:-local} APP_PORT=$(APP_PORT) \
|
||||
$(COMPOSE_LAN) up --build -d proxy backend frontend mailcatcher
|
||||
|
||||
# The frontend is an nginx image, so a UI change needs a rebuild. DOMAIN comes
|
||||
# off the running stack: VITE_API_URL is baked in at build time, and a rebuild
|
||||
# under a different domain leaves the SPA calling an API that answers elsewhere.
|
||||
rebuild-frontend: ## Rebuild and restart the local frontend (after a UI change)
|
||||
@domain=$$(docker inspect fluksio-app 2>/dev/null \
|
||||
| grep -o 'Host(`app\.[^`]*`)' | head -1 | sed 's/Host(`app\.//;s/`)//'); \
|
||||
DOMAIN=$${domain:-$$DOMAIN} ENVIRONMENT=$${ENVIRONMENT:-local} \
|
||||
$(COMPOSE_LOCAL) up --build -d frontend
|
||||
|
||||
up: ## Start the production stack
|
||||
$(COMPOSE_PROD_RUN) up --build -d
|
||||
|
||||
@@ -115,25 +132,27 @@ test-backend: ## Run backend tests (pytest + coverage)
|
||||
# nothing running and touches no development data.
|
||||
cd backend && uv run bash scripts/test.sh
|
||||
|
||||
# The hostname the stack is served under. A checkout configured for a
|
||||
# deployment carries the deployment's domain, and *.fluksio.com resolves to the
|
||||
# live instance from here — which is why the run below maps both names onto the
|
||||
# local Traefik by address and never lets DNS decide.
|
||||
export DOMAIN ?= $(shell sed -n 's/^DOMAIN=//p' $(COMPOSE_ROOT)/.env | head -1)
|
||||
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.
|
||||
test-frontend: ## Run frontend tests (Playwright e2e) against the local 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; }; \
|
||||
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 \
|
||||
--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 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)" \
|
||||
|
||||
@@ -5,4 +5,7 @@ set -x
|
||||
|
||||
coverage run -m pytest tests/
|
||||
coverage report
|
||||
coverage html --title "${@-coverage}"
|
||||
# The HTML report is a convenience: a container run can leave htmlcov/ owned by
|
||||
# root, and failing here after a green suite reads like a test failure.
|
||||
coverage html --title "${@-coverage}" \
|
||||
|| echo " ! coverage html failed (htmlcov/ not writable? try 'make clean') — tests passed" >&2
|
||||
|
||||
Reference in New Issue
Block a user