| .. | ||
| evals | ||
| mock-github-server | ||
| scripts | ||
| tests | ||
| .gitignore | ||
| docker-compose.test.yml | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.ts | ||
| pw-measure.mjs | ||
| QUICK_START.md | ||
| README.md | ||
| tsconfig.json | ||
Integration Tests (Playwright)
End-to-end Playwright tests that validate critical user flows against a running Pulse instance.
Architecture
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────────┐
│ Playwright │────▶│ Pulse Server │────▶│ Mock GitHub API │
│ (Browser UI) │ │ (Test Instance) │ │ (Controlled │
│ │ │ │ │ Responses) │
└─────────────────┘ └──────────────────┘ └─────────────────────┘
Test Scenarios
tests/00-diagnostic.spec.ts— smoke test that the stack boots and the UI renders.tests/01-core-e2e.spec.ts— critical UI flows:- Bootstrap setup wizard (fresh instance)
- Login + authenticated state
- Alerts thresholds create/delete
- Settings persistence across refresh
- Add/delete a Proxmox node (test-only)
tests/02-navigation-perf.spec.ts— route transition performance budgets for:- Infrastructure → Workloads
- Workloads → Infrastructure
tests/06-theme-visual.spec.ts— visual regression baselines for light/dark auth surfaces:- Logged-out login page (full page + form card)
- Authenticated Settings → Authentication page
tests/07-trial-signup-return.spec.ts— trial workflow contract:- Start hosted Pro trial initiation via API
- Verify response points to hosted
/start-pro-trial - Verify local entitlements remain unchanged until activation
- Verify duplicate initiation is rate limited
tests/08-cloud-hosting.spec.ts— hosted cloud signup contract:- Public
/cloud/signupform creates a real Stripe sandbox checkout session - Checkout completes and returns to hosted signup completion page
- Magic-link request path succeeds via real public endpoint
- Public
tests/09-cloud-billing-lifecycle.spec.ts— hosted cloud post-checkout lifecycle:- Replays verified Stripe webhook events into control plane
- Asserts tenant activation after checkout event processing
- Asserts tenant cancellation after subscription deletion event processing
tests/16-dev-runtime-recovery.spec.ts— managed browser runtime proof:- Attaches Playwright to the canonical
5173browser entrypoint - Restarts the managed backend and proves the browser shell recovers through the proxy
- Attaches Playwright to the canonical
tests/17-recovery-layout.spec.ts— desktop Recovery layout regression guard:- Mocks a realistic Recovery dataset with human-readable subject labels
- Proves the focused history table fits the desktop wrapper without horizontal overflow
- Proves the
Outcomecolumn stays visible at the right edge
tests/18-patrol-runtime-state.spec.ts— Patrol runtime-state browser guard:- Mocks a blocked Patrol runtime with stale healthy summary payloads
- Proves the real
/airoute shows Patrol as paused and suppresses stale healthy summary copy
Running Tests
Local Development (Docker compose stack)
cd tests/integration
./scripts/setup.sh # one-time (installs deps + builds docker images)
npm test
Eval Packs (No Manual Steps)
Run the curated scenario pack (multi-tenant, trial-signup, cloud-hosting, cloud-billing-lifecycle) and emit a report:
cd tests/integration
npm run evals
Filter to one scenario:
npm run evals -- --scenario trial-signup
Reports are written to:
tests/integration/eval-results/<timestamp>/report.jsontests/integration/eval-results/<timestamp>/report.md
Cloud lifecycle evals require these environment variables (test-mode only):
PULSE_CP_ADMIN_KEYPULSE_E2E_STRIPE_API_KEYPULSE_E2E_STRIPE_WEBHOOK_SECRET
Agentic Mode (External Browser Agent)
The eval runner supports external browser-capable agents through a command template:
cd tests/integration
PULSE_EVAL_MODE=agentic \
PULSE_EVAL_AGENT_COMMAND_TEMPLATE='<your-agent-command-using {{task_file}} and {{result_json}}>' \
npm run evals
Supported placeholders in PULSE_EVAL_AGENT_COMMAND_TEMPLATE:
{{task_file}}{{result_json}}{{scenario_id}}{{base_url}}
The docker-compose stack seeds a deterministic bootstrap token for first-run setup:
- Override via
PULSE_E2E_BOOTSTRAP_TOKEN - Default token value is defined in
tests/integration/docker-compose.test.yml - When
PULSE_MULTI_TENANT_ENABLED=true, the integration harness also seeds a deterministic Enterprise-eval billing state so the multi-tenant suite runs against a licensed surface instead of skipping.
Credentials used by the E2E suite can be overridden:
PULSE_E2E_USERNAME(defaultadmin)PULSE_E2E_PASSWORD(defaultadminadminadmin)PULSE_E2E_ALLOW_NODE_MUTATION=1to enable the optional "Add Proxmox node" test (disabled by default for safety)PULSE_E2E_PERF=1to enable navigation performance budget checksPULSE_E2E_PERF_ITERATIONS(default3)PULSE_E2E_PERF_INFRA_TO_WORKLOADS_BUDGET_MS(default2200)PULSE_E2E_PERF_WORKLOADS_TO_INFRA_BUDGET_MS(default2200)
Run Against An Existing Pulse Instance
cd tests/integration
PULSE_E2E_SKIP_DOCKER=1 \
PULSE_BASE_URL='http://your-pulse-host:7655' \
PULSE_E2E_USERNAME='admin' \
PULSE_E2E_PASSWORD='adminadminadmin' \
npm test
Run Against A Managed Local Backend (No Docker, Deterministic)
cd tests/integration
PULSE_E2E_USE_LOCAL_BACKEND=1 \
PULSE_MULTI_TENANT_ENABLED=true \
npm test -- tests/03-multi-tenant.spec.ts --project=chromium
This mode starts an isolated Pulse backend from the local repo binary in a temporary data directory under tmp/integration-local-backend, seeds the requested entitlement profile, writes runtime connection state for Playwright, and cleans everything up in posttest.
Each npm test invocation gets its own runtime-state file and managed-backend root automatically, so separate managed-local-backend runs can execute in parallel without sharing PID or cleanup state. Shared embedded-frontend and backend-binary refreshes are serialized by the harness.
Run Against The Managed Hot-Dev Browser Runtime
Canonical one-command verification from the repo root:
npm run dev:verify
Equivalent direct proof command from the integration harness:
cd tests/integration
PULSE_E2E_USE_HOT_DEV=1 \
PULSE_E2E_SKIP_PLAYWRIGHT_INSTALL=1 \
npm test -- tests/16-dev-runtime-recovery.spec.ts tests/17-recovery-layout.spec.ts tests/18-patrol-runtime-state.spec.ts --project=chromium
This mode attaches Playwright to the canonical dev browser entrypoint on http://127.0.0.1:5173, uses the repo-root managed runtime wrappers as the control surface, and writes browser runtime connection state for Playwright instead of targeting the backend port directly. Those wrappers are backed by scripts/hot-dev-bg.sh, but the wrapper surface is the canonical operator contract.
When you run the wrapper as npm run dev:verify, the managed launcher hands a verification-lock path into the integration runner, and the runner holds that lock for the actual pretest, Playwright, and posttest lifetime so unrelated backend source churn does not invalidate the recovery proofs mid-run.
When no explicit PULSE_BASE_URL, PLAYWRIGHT_BASE_URL, or runtime-state file is present, the shared integration browser-default helper now prefers the managed hot-dev browser shell on http://127.0.0.1:5173 whenever hot-dev-bg is already running, and only falls back to the embedded frontend on :7655 when there is no managed dev session to attach to.
If the managed runtime is not already running, the harness starts it. If you need the harness to reclaim existing unmanaged 5173/7655 listeners first, add PULSE_E2E_HOT_DEV_TAKEOVER=1.
The managed proof pack bounces the real backend through npm run dev:backend-restart, kills the supervised hot-dev.sh owner process to prove full runtime recovery, verifies that the browser shell reports those outages and then recovers through the proxy, and keeps a desktop Recovery layout guard on the same canonical browser entrypoint. When the harness attaches to an already-running managed dev session, posttest leaves that runtime running.
For deterministic paid-feature runs against an existing instance, provide one of:
PULSE_E2E_BILLING_STATE_PATH=/absolute/path/to/billing.jsonto let the harness write the billing state file directly.PULSE_E2E_ENTITLEMENT_WRITE_COMMAND='ssh host "cat > /etc/pulse/billing.json"'to pipe the billing JSON to a remote/local writer command.
The harness understands these profiles:
PULSE_E2E_ENTITLEMENT_PROFILE=multi-tenantfor Enterprise/MSP multi-tenant coverage.PULSE_E2E_ENTITLEMENT_PROFILE=infrafor Pro/relay/reporting-style journeys.
Snapshot-Clean Proxmox LXC Trial SAT
For hosted trial initiation validation against a fresh LXC each run:
- Runbook:
docs/operations/TRIAL_E2E_LXC_SNAPSHOT_RUNBOOK.md - Probe script:
tests/integration/scripts/trial-signup-contract.sh - Full sandbox orchestration (multi-tenant + trial + cloud, with per-scenario snapshot reset):
tests/integration/scripts/run-lxc-sandbox-evals.sh- Includes hosted trial initiation validation and cloud subscription cancellation lifecycle verification
Example:
cd tests/integration
./scripts/run-lxc-sandbox-evals.sh
If the snapshot has stale binaries, inject the latest Linux control-plane build on each rollback:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /tmp/pulse-control-plane-e2e-linux-amd64 ./cmd/pulse-control-plane
cd tests/integration
PULSE_E2E_CP_BINARY=/tmp/pulse-control-plane-e2e-linux-amd64 ./scripts/run-lxc-sandbox-evals.sh
Run Theme Visual Regression Suite
cd tests/integration
PULSE_E2E_SKIP_DOCKER=1 \
PULSE_BASE_URL='http://your-pulse-host:7655' \
PULSE_E2E_USERNAME='admin' \
PULSE_E2E_PASSWORD='your-password' \
npm run test:visual
To refresh baselines intentionally:
npm run test:visual:update
When running against an existing instance (PULSE_E2E_SKIP_DOCKER=1), authenticated
visual snapshots require explicit credentials:
PULSE_E2E_USERNAMEPULSE_E2E_PASSWORD
If the instance is behind self-signed TLS:
PULSE_E2E_INSECURE_TLS=1 PULSE_E2E_SKIP_DOCKER=1 PULSE_BASE_URL='https://...' npm test
CI Pipeline
- Core E2E flows run via
.github/workflows/test-e2e.yml - Update flow coverage remains in
.github/workflows/test-updates.yml
Test Data (Update Flow Only)
The mock GitHub server (mock-github-server/) provides controllable responses:
/api/releases- List all releases/api/releases/latest- Latest stable release/download/{version}/pulse-{version}-linux-amd64.tar.gz- Release tarballs/download/{version}/checksums.txt- Checksum files
Response behavior can be controlled via environment variables:
MOCK_CHECKSUM_ERROR=true- Return invalid checksumsMOCK_NETWORK_ERROR=true- Simulate network failuresMOCK_RATE_LIMIT=true- Enable aggressive rate limitingMOCK_STALE_RELEASE=true- Mark releases as stale
Success Criteria
- ✅ Core E2E flows pass reliably in CI
- ✅ Update flow remains covered via API integration test + smoke UI check