Files
firehose/app/Makefile
T
Willem van den Ende abb712f8a2 app: coverage floor (86) + framework-glue exclusions
Measured before choosing: 86.17%, identical via `mix test --cover` and via the
exported sample + `mix test.coverage`, stable across seeds. Floor is the integer
below that, with the rule written next to it: a FLOOR, ratcheted up as
behavior-test yaks land, never lowered (a drop means the change or an exclusion
is wrong).

Exclusions are the modules the suite cannot or should not exercise, each
justified in the config comment: `use`-generated glue (Repo, Mailer, Telemetry,
ErrorHTML/ErrorJSON), the `use FirehoseWeb` macro, production release tasks
(Release), the lib_dev credo check (NoConnShadowing), and test scaffolding
(DataCase, ConnCase, AccountsFixtures, Test.FakeBlog). Everything else counts,
CoreComponents/controllers/LiveViews included.

Wiring matches blogex and the fast/push split: `test.coverage` runs the suite
once with `--cover --export-coverage default` (deleting stale exports first,
since `mix test.coverage` imports every .coverdata it finds and would pool
them), then the `coverage` sensor enforces the floor from that export. The
sensor guards on the export existing because `mix test.coverage` exits 0 when it
finds nothing — a floor check that did not run must not pass.
2026-10-26 18:40:09 +00:00

139 lines
5.6 KiB
Makefile

# Makefile for Firehose app
MISE_BIN ?= mise
MISE_EXEC = $(MISE_BIN) exec --
.PHONY: check precommit deps compile test test.coverage coverage format credo verify
# Run all static analysis checks (no database required)
check: credo format
# Precommit target for CI/pre-commit hooks
precommit: check compile
# Sync dependencies
deps:
$(MISE_EXEC) mix deps.get
# Compile the project
compile:
$(MISE_EXEC) mix compile --warnings-as-errors
# Run tests (requires PostgreSQL running on localhost:5432)
# Note: If you don't have PostgreSQL, you can skip tests with `make check`
test: deps compile
$(MISE_EXEC) mix test
# Run the suite once with coverage exported, so the coverage floor check (and,
# later, CRAP) reads the export instead of running the suite a second time.
# Stale exports are removed first: the floor must never report an older run.
test.coverage: deps compile
rm -f cover/*.coverdata
$(MISE_EXEC) mix test --cover --export-coverage default
# Enforce the coverage floor (mix.exs -> test_coverage) from that export. No
# test run. `mix test.coverage` exits 0 when it finds no export at all, so the
# guard below is load-bearing: a floor check that did not run must not pass.
coverage:
@test -f cover/default.coverdata || { echo "coverage: no exported coverage - run 'make test.coverage' first" >&2; exit 1; }
$(MISE_EXEC) mix test.coverage
# Format code
format:
$(MISE_EXEC) mix format
# =============================================================================
# Playwright e2e browser tests
# =============================================================================
#
# Requires the Phoenix dev server running on the default port (8056).
# Set PLAYWRIGHT_BASE_URL to point at a different server/port.
#
# Available browsers (local):
# PLAYWRIGHT_BROWSER=firefox (default — works on macOS 15)
# PLAYWRIGHT_BROWSER=chromium (crashes on macOS 15, use Docker Chrome)
# PLAYWRIGHT_BROWSER=webkit
#
# Docker Chrome (alternative):
# 1. docker compose -f docker-compose.chrome.yml up -d
# 2. PLAYWRIGHT_BROWSERS_PATH=assets/node_modules/playwright-core/.local-browsers \
# npx playwright test --config=playwright.docker.config.ts
#
# =============================================================================
# Run Playwright e2e tests (default: local Firefox)
# Usage: make playwright
# PLAYWRIGHT_BROWSER=chromium make playwright
playwright:
cd assets && PLAYWRIGHT_BROWSERS_PATH=node_modules/playwright-core/.local-browsers npx playwright test --config=../playwright.config.ts
# Run a specific Playwright test file
# Usage: make playwright-test test/e2e/smoke.spec.ts
playwright-test:
cd assets && PLAYWRIGHT_BROWSERS_PATH=node_modules/playwright-core/.local-browsers npx playwright test --config=../playwright.config.ts $(filter-out $@,$(MAKECMDGOALS))
# Run Playwright tests with UI mode (headed browser)
playwright-ui:
cd assets && PLAYWRIGHT_BROWSERS_PATH=node_modules/playwright-core/.local-browsers npx playwright test --config=../playwright.config.ts --ui
# Show last Playwright HTML report
playwright-report:
cd assets && npx playwright show-report
# Start Docker Chrome container for remote Playwright
playwright-docker-start:
docker compose -f docker-compose.chrome.yml up -d
# Stop Docker Chrome container
playwright-docker-stop:
docker compose -f docker-compose.chrome.yml down
# Run Playwright against Docker Chrome (container must be running)
playwright-docker:
cd assets && PLAYWRIGHT_BROWSERS_PATH=node_modules/playwright-core/.local-browsers npx playwright test --config=../playwright.docker.config.ts
# Run full end-to-end workflow: start Docker Chrome, run tests, stop container
playwright-full: playwright-docker-start
@echo "Waiting for Chrome to be ready..."
@sleep 3
cd assets && PLAYWRIGHT_BROWSERS_PATH=node_modules/playwright-core/.local-browsers npx playwright test --config=../playwright.docker.config.ts; \
EXIT_CODE=$$?; \
cd ..; \
docker compose -f docker-compose.chrome.yml down; \
exit $$EXIT_CODE
# =============================================================================
# Static analysis
# =============================================================================
# Run Credo static analysis
credo:
$(MISE_EXEC) mix credo --strict
# =============================================================================
# Lens pass (heavy checks; root `make verify` runs this before every push)
# =============================================================================
#
# Sensor slots, cheapest first. Credo is cheap enough that it lives in
# `check`, not here. Add a sensor as its yak lands, both as a target and to
# VERIFY_SENSORS — that variable is the single source of truth for what this
# target reports as wired.
# - sobelow (yak: sobelow in the Lens pass)
# - coverage (yak: coverage floors + framework-glue exclusions policy)
# WIRED below (test.coverage + coverage).
# - crap (yak: CRAP scores with ex_crap (both apps))
# - mutation (yak: mutation testing with muex — a sensor, not a gate)
#
# Runtime note: the coverage sensor exports from a single suite run
# (`test.coverage` -> `mix test --cover --export-coverage default`) that CRAP is
# meant to reuse, instead of running the suite twice.
#
# The suite runs FIRST, because it is what produces the coverage export the
# sensors read; sensors still run cheapest-first among themselves.
VERIFY_SENSORS := coverage
verify:
@echo "==> verify(app): suite (coverage exported), then sensors [$(VERIFY_SENSORS)]"
@$(MAKE) test.coverage
@for sensor in $(VERIFY_SENSORS); do echo "==> verify(app): sensor $$sensor"; $(MAKE) $$sensor || exit 1; done