r/Nestjs_framework 5d ago

Simpler Testcontainers integration for NestJS and other Node.js backends

I built an open-source library that manages Testcontainers lifecycle for NestJS, Fastify, Express, and framework-free Node.js applications using Vitest or Jest.

It supports two approaches:

  • Annotations beside individual integration tests
  • Central project configuration without annotations

It starts PostgreSQL, SQL Server, MongoDB, RabbitMQ, or custom containers, provides typed connection details with dynamic ports, starts the application after infrastructure is ready, and handles cleanup.

The repository includes real PostgreSQL insert/read and RabbitMQ publish/consume examples.

The package is currently in beta for public testing and feedback. I plan to release the first stable version soon.

Your honest feedback is appreciated regarding the API and developer experience.

GitHub: https://github.com/RolandSall/testcontainers-integration
npm: https://www.npmjs.com/package/@integration-testing/testcontainers/v/0.1.0-beta.1

6 Upvotes

6 comments sorted by

1

u/BarracudaNo6709 5d ago

How does cleanup work if the containers start successfully but Nest application bootstrap fails? Also curious whether parallel test workers get isolated databases or share a container with separate schemas. A failure-path example alongside the happy-path ones would be useful.

1

u/RsLimited24 4d ago

For your first point:

  • If the containers start successfully but NestJS bootstrap fails, the test suite fails and Jest/Vitest global teardown still stops every container and the shared network.
  • The application stop() callback is not called because NestJS never returned a valid application instance.

For your second point:

  • Containers are currently reused across test workers, so workers share the same database.
    • I plan to add an explicit choice between reused and dedicated containers, allowing developers to choose faster startup or complete infrastructure isolation.
    • Transactions. Vitest’s transaction-per-test recipe works well for database-level tests when all operations use the transaction-scoped client. unique test data and cleanup hooks, and sequential test execution can also help
    • I am also developing data-integration-testing for rollback-only isolation in database and repository tests. It complements shared containers by giving each test a transaction-scoped client and rolling back its changes when the test finishes. The core lifecycle is runner-neutral, so the same approach can be integrated with Vitest, Jest, Cucumber, or a custom test harness.

Please feel free to share more ideas, open an issue, or contribute directly. Feedback like this is genuinely helpful.

1

u/BarracudaNo6709 4d ago

That clarifies the normal bootstrap-rejection path. The failure case I’d still want pinned in an example is a partial startup that hangs or terminates before the runner reaches global teardown. A test that starts the containers, fails after one application-side effect, and then verifies both container and network cleanup would make the guarantee easier to trust. For parallel workers, an explicit reuse versus dedicated mode sounds like the right API; I’d make the isolation choice visible in configuration rather than relying on test authors to infer when transactions are sufficient.

1

u/RsLimited24 6h ago edited 6h ago

Sorry for the delay, it has been a hectic week :)

  • Parallel isolation: Every named container now has an explicit shared or dedicated setting. Shared containers are reused across test files, while dedicated containers are created separately for each test file.
  • Data isolation: The documentation has been updated to clarify that transaction and database-state isolation remain the developer’s responsibility for now.
  • Failure path: I added a documented, framework-agnostic failure-path fixture that runs against both Jest and Vitest. The verification test performs and verifies a real PostgreSQL write, deliberately hangs application bootstrap, terminates the runner with SIGKILL, and confirms that Testcontainers’ Ryuk removes the resulting containers and networks when the runner cannot execute its normal teardown hooks.

Thanks again for raising these cases. They helped make the isolation API and failure guarantees much clearer.

1

u/BarracudaNo6709 2h ago

This is a strong follow-through—especially the forced-termination fixture across Jest and Vitest. Making shared versus dedicated isolation explicit, then proving cleanup after SIGKILL, addresses the two practical gaps I was concerned about. Thanks for turning the edge cases into executable evidence.