The Region select called setValue without shouldDirty. `region` is an eTrade-bundle key, and stepPayload sends those only when the customer changed them this session — so for the two routes that type their address by hand (a co-operative, a foreign investor) the region was dropped on every save while zone, woreda and kebele went through, because those are registered inputs and are dirty by construction. Found by the new onboarding e2e suite: both manual-route companies finished onboarding with zone/woreda/kebele on file and region empty.
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.