- Add TransferFulfillModal for fulfilling wagon transfer requests. - Create TransferRequestFormModal for filing new wagon transfer requests. - Introduce TransferCloseShortModal for closing requests that cannot be fully fulfilled. - Develop WagonTransfersPage to manage and display wagon transfer requests. - Implement utility functions for handling wagon transfer request data and UI components. - Enhance UI with Mantine components for better user experience.
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.