The switch clears the registration but not the tax number, so the company step reopens with the old TIN and RHF re-seeds the field when the profile refetch lands. A TIN typed before that arrived was silently replaced by the stored one and the lookup ran against the wrong number. The spec now waits for the rehydrated VAT value, then asserts the field holds what it typed before waiting on eTrade.
EDR Passenger — Pricing/Config E2E Harness
Hermetic, bug-hunting test harness for the passenger platform. Targets pricing integrity and backoffice configuration. Never touches a real database.
Quick start
# 1. Bring up the isolated test Postgres (port 5544) and apply all migrations
bash e2e/prepare.sh
# (or: pnpm --filter @edr/passenger-api test:e2e:prepare)
# 2. Run the suites
pnpm --filter @edr/passenger-api test:e2e
# 3. Tear down
pnpm --filter @edr/passenger-api test:e2e:db:down
What's isolated
e2e/docker-compose.yml— Postgres 17 on host port 5544, containeredr-passenger-e2e-db,tmpfsdata (wiped ondown). Distinct from any dev/prod DB. Schemaspassenger,iam,edr_paymentcreated bye2e/init/01-schemas.sql.apps/edr-passenger-api/.env.test— points every connection at 5544; brokers/IAM/Fayda OFF. Loaded bytest/setup/load-env.tsbefore the app boots.
Architecture — why two tiers
The full AppModule cannot be booted in-process under jest:
@tria-plc/api-common(pulled via IAM)require("file-type"), which is ESM-only → jest's CommonJS resolver fails. (Worked around with amoduleNameMapperstub, but…)@golevelup/nestjs-rabbitmq+ microservice RMQ clients +onApplicationBootstrapseeders hang the boot waiting on a broker that isn't there.
So tests use one of two tiers:
Tier 1 — slim module harness (test/setup/slim-app.ts). Boots ONLY the pricing/config domain
modules that are free of the IAM/RabbitMQ chain: fare-engine, currency, currencies, promos, seat-classes, stations, schedules, segments, system-config. Two entry points:
createServiceHarness()— resolve services (e.g.FareEngineService) for direct method calls.createHttpHarness()— full HTTP app with the SAMEValidationPipeassrc/main.ts, for controller/DTO/pipe (client-trust, validation) tests over supertest.
Tier 2 — direct instantiation (test/setup/prisma.ts). For services behind the wall
(BookingsService, PaymentsService, WalletService, LoyaltyService, ExcessBaggageService):
new TheService(getTestPrisma(), ...mockedCollaborators) and assert the money logic. Avoids booting
the module graph entirely.
Fixtures
test/fixtures/seed-core.ts — deterministic graph (coach type → LOCAL/INTERNATIONAL seat classes →
3 stations → route with distance-bearing stops → FX rates) with fixed UUIDs in IDS. Call
resetAndSeedCore(prisma) in beforeEach. The repo's prisma/seed.ts is disabled (all steps
commented out) and is intentionally NOT used.
Suites (see docs/e2e-test-matrix.md for the full matrix)
Spec files are test/*.e2e-spec.ts. Each is tagged with the matrix IDs it covers. 🔴 in a test name
marks a confirmed defect the test documents/reproduces (the assertion encodes the BUGGY behavior;
a passing 🔴 test = the bug is present).
Current suites (all green):
pricing-fare-engine.e2e-spec.ts— baseline + D1/D2/D4 (promo → negative total), C1 (FX fallback)pricing-currency.e2e-spec.ts— C2/C2b (display↔charge FX divergence), C3 (future rate), C5 (unit divergence)money-integrity.e2e-spec.ts— F1/F2 (free wallet top-up), G4/G5 (refund never disbursed), E1/E2 (baggage)config-validation.e2e-spec.ts— H1/H2 (negative fares), H4/H5 (promo bounds/date)auth-gaps.e2e-spec.ts— J1 (unauthenticated FX writes)critical-repro.e2e-spec.ts— C-1 (client-controlled booking total), C-4 (payment amount never validated), C-6 (wallet double-spend via a deterministic race barrier)
test/app.e2e-spec.ts is a pre-existing repo test that boots the FULL AppModule; it is excluded via
testPathIgnorePatterns because that boot hangs in-process (RabbitMQ connect + ESM file-type) — a
harness limitation documented above, not a product bug.
Findings are catalogued in docs/ISSUES.md.