Skip to content

Run the browser test stack

apps/elitea-web/scripts/e2e-stack.sh drives a second, self-contained Compose stack (deploy/docker-compose.e2e-standalone.yml) sized for Playwright: no LLM gateway or worker service, non-default ports so it can coexist with other stacks on your machine, and a seed step built around two named personas. This is the stack apps/elitea-web’s own test suite and its documentation screenshot tooling both run against — use it instead of the standalone stack when you’re working on apps/elitea-web itself.

apps/elitea-web/scripts/e2e-stack.sh only understands four:

Usage: e2e-stack.sh {up|down|seed|logs [outfile]}
  1. up

    Terminal window
    apps/elitea-web/scripts/e2e-stack.sh up

    Generates the DeepWiki and Inventory provider mTLS material, then brings the stack up and waits for every healthcheck (compose up -d --wait). elitea-main runs its migrations on startup.

  2. seed

    Terminal window
    apps/elitea-web/scripts/e2e-stack.sh seed

    Bootstraps the schema if needed, creates the e2e-member@autotest.local and e2e-admin@autotest.local oidc-mock users and their matching database rows and role grants, and writes the fixture rows most journeys depend on (an audit-trail day anchor among them).

  3. logs [outfile]

    Collects compose ps plus every service’s logs into a file (default playwright-results/stack-logs.txt) — the only place to see what a failed run’s server actually did, since a torn-down stack takes its logs with it.

  4. down

    Tears the stack down, including its volumes (--remove-orphans -v).

There is no separate build or status subcommand: up builds what it needs, and podman compose -p elitea-e2e -f deploy/docker-compose.e2e-standalone.yml ps covers status.

docker-compose.e2e-standalone.yml is a complete stack, not an overlay, and deliberately uses non-default ports so it can run alongside other local stacks:

PortServiceOverride
8082elitea-main, the browser edge (relays /app and /docs to elitea-web)E2E_PORT
9400oidc-provider-mockfixed — see the standalone stack’s note
15432PostgreSQLE2E_PG_PORT

E2E_PROJECT (default elitea-e2e) names the Compose project; set it together with the port variables above to run a second, disposable E2E stack beside the first.

The seed step creates exactly two accounts through oidc-mock: e2e-member@autotest.local (a normal project member) and e2e-admin@autotest.local (holds the admin role). Playwright’s own auth.setup.ts project signs each one in through a real OIDC round trip — filling the mock’s “Subject” field with the persona’s email — and saves the result as a storage-state file per persona (member, admin, and a third, chat, used by the streaming/chat specs, which owns its own personal project so it never contends with the other two).

Individual specs and the docs screenshot tooling then create their own throwaway fixtures inside that seeded state, all prefixed autotest_ (apps/elitea-web/e2e/fixtures/api.ts) — an agent, a toolkit, a pipeline, and so on — and a fixtures-sweep project removes every autotest_-named entity left over at the end of a run.

Terminal window
npm run e2e # all default projects (from apps/elitea-web)
npx playwright test --project=chromium
npx playwright test --project=webkit
npm run e2e:chat-stream # chat-stream project, via scripts/chat-stream-e2e.sh
npm run e2e:visual # visual project, in the pinned Playwright container

playwright.config.ts reads PLAYWRIGHT_BASE_URL (default http://localhost:8082, matching E2E_PORT’s default) for its baseURL. The main projects are chromium and webkit (the bulk of the journeys), chat-stream (streaming chat, mock model), chat-stream-real/chat-stream-real-nightly (against a real small model), and visual (screenshot-diff baselines) — plus setup/fixture/live-toolkit projects most local runs don’t need directly.

Never regenerate @visual baselines locally. Use the ci-web-e2e.yml workflow’s workflow_dispatch inputs instead: update_visual_baselines runs the suite inside the pinned Playwright container and uploads the results as the visual-baselines artifact for you to review and commit; full_visual_refresh (which requires update_visual_baselines) rewrites every baseline rather than only the ones that failed. A local run uses your machine’s fonts and GPU rasterization, which do not match the pinned container the visual job asserts against in CI.

Two scripts (both under apps/elitea-web/scripts/, run from that directory) drive the documentation site’s own screenshots against a running, seeded E2E stack:

Terminal window
npx tsx scripts/docs-seed.ts # creates one autotest_docs_*-named instance of every entity the shots need
npm run docs:shots # captures the manifest's routes to WebP under apps/elitea-docs/src/screenshots/

docs-seed.ts looks every entity up by name first and reuses it if found, so re-running it is safe. Without --vllm-api-base/--vllm-model (which need the standalone stack’s worker, not this one) it still creates a conversation and its participant for empty-state and composer shots, but does not produce a real assistant turn — routes gated on agent execution answer 405 on this stack, since it composes no worker at all. docs:shots signs in with the same persona storage-state files Playwright’s own specs use, applies a reduced-motion stylesheet and waits for DOM stability rather than a fixed sleep, and re-encodes each capture to WebP at 1440×900, light theme, capped at 250 KB.