Skip to content

DEV-149 TESTING — Tests e2e del flujo crear/listar/ver personaje — test(e2e): add a black-box e2e for the character create/list/view flow#38

Open
LucianABC wants to merge 5 commits into
mainfrom
DEV-149/e2e-character-flow
Open

DEV-149 TESTING — Tests e2e del flujo crear/listar/ver personaje — test(e2e): add a black-box e2e for the character create/list/view flow#38
LucianABC wants to merge 5 commits into
mainfrom
DEV-149/e2e-character-flow

Conversation

@LucianABC

Copy link
Copy Markdown
Collaborator

Summary

  • Add an end-to-end suite for the MVP character flow (DEV-149): POST /charactersGET /characters (created one is in the list) → GET /characters/:id, plus error paths — 400 on values that don't match the Playbook template, 400 on a body that fails the request schema (empty name), and 404 on a missing id. Runs with npm run test:e2e.
  • The scaffolded e2e never started — jest-e2e.json didn't map @db, so the Prisma client never resolved. Reworked it into a self-contained black-box setup instead: test/e2e/global-setup.ts spins up an ephemeral Postgres via Testcontainers, runs prisma generate + migrate deploy, builds the app and boots node dist/src/main.js as a separate process; global-teardown stops both.
  • The app runs in real node, not Test.createTestingModule, on purpose: the Prisma 7 client (WASM engine) fails to initialize under ts-jest (deserializeParamGraph throws). So the spec drives the API over HTTP with supertest and seeds its own fixtures (System→Game→Playbook + User) with pg directly — no Prisma is loaded in the jest process.
  • Wire an E2E step into CI after the build (Docker is available on ubuntu-latest); document the setup and the Docker requirement in CLAUDE.md. Removed the boilerplate app.e2e-spec.ts (its in-process AppModule bootstrap would load Prisma under jest).

Test plan

  • npm run lint
  • npx tsc --noEmit
  • npm run test (unit — 50 tests, via pre-commit)
  • npm run test:e2e — 4 tests, ran twice, all green, no leaked containers (needs Docker running)
  • pre-commit hook end-to-end (real commit on the branch)

DEV-149. Cover the MVP flow end-to-end against the real API: POST
/characters -> GET list (character present) -> GET detail, plus the error
paths (400 on values that don't match the Playbook template, 400 on a
body that fails the request schema, 404 on a missing id).

The scaffolded jest-e2e couldn't even start (it didn't map @db, so the
Prisma client never resolved). Rework it into a self-contained black-box
setup: globalSetup spins up an ephemeral Postgres via Testcontainers,
runs prisma generate + migrate deploy, builds the app and boots
node dist/src/main.js as a separate process; globalTeardown stops both.
The app runs in real node rather than Test.createTestingModule because
the Prisma 7 client (WASM engine) fails to initialize under ts-jest. The
spec drives it over HTTP with supertest and seeds its own fixtures
(System->Game->Playbook + User) with pg directly, so no Prisma is loaded
in the jest process. Runs in CI after the build (Docker is available on
ubuntu-latest); needs Docker locally too.
The e2e globalSetup failed in CI with 'webidl.util.markAsUncloneable is
not a function': the undici bundled by Testcontainers 12 needs Node >=22,
but the workflow pinned Node 20. Dev already runs on 22 and the project
targets 20+, so bump the CI job to 22 (current LTS).
Address review findings on DEV-149:

- Clean up on globalSetup failure: wrap the container/build/server steps in
  try/catch and stop the container + kill the server before rethrowing, so
  a failure mid-setup (where jest skips globalTeardown) doesn't leak them.
- Formalize the Node requirement: Testcontainers' undici needs Node
  >=22.19. Add engines.node and .nvmrc, point CI at node-version-file, and
  update the CLAUDE.md/README claims (were 20+/18+).
- Assert the full wire contract: check the exact key set of the created /
  listed / detail Character (so a dropped ownerId, timestamp,
  playbookVersion or the list enrichment fails the test) plus ISO date
  strings and the pagination meta, typed against the contract package.
- Avoid fixed global resources: allocate a free port per run and name the
  bridge file per jest run (worker derives it from process.ppid), so two
  parallel runs or a busy port don't collide.
Second review pass on DEV-149:

- Fix start:prod: it pointed at 'node dist/main' but the build emits
  dist/src/main.js, so npm run start:prod failed with MODULE_NOT_FOUND.
  Point it at dist/src/main.js and boot the e2e server WITH that command
  (test/e2e/server.ts) so the deployable command is exercised — a future
  break of it now fails the e2e.
- Build once: move prisma generate + build out of globalSetup into the
  test:e2e script; globalSetup only does what depends on the container
  (migrate + start server). CI reuses its Build step via test:e2e:run
  instead of rebuilding.
- Exception-safe cleanup: on globalSetup failure and in globalTeardown,
  stop the server and the container via Promise.allSettled (a failing
  stop no longer masks the original error or skips the other cleanup),
  and wait for the server's exit event before resolving.
- Align publish-contracts.yml with .nvmrc (was still Node 20).
- expectIsoString: assert an exact ISO round-trip
  (new Date(v).toISOString() === v) instead of the laxer Date.parse.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant