Integration tests verify that multiple pieces, middleware, routing, controllers, and (usually) a real or in-memory database, work correctly together. This lesson builds a complete integration test for a CRUD route.
Testing the Full Request Pipeline
Unlike unit tests, an integration test sends an actual request through your Express app, exercising every middleware and handler in the real chain, exactly as a real client would trigger it.
This catches bugs unit tests miss, wrong route registration order, missing middleware, incorrect status codes, that only show up when the pieces run together.
A thorough integration test suite for a resource typically covers creation, successful reads, not-found reads, updates, and deletion, verifying both status codes and response shape.
For routes protected by authentication, generate a valid token (or session) in a test setup step, then attach it to requests exactly as a real client would.
Running integration tests against a shared database used by other developers or environments.
Not cleaning up test data between test cases, causing tests to interfere with each other.
Testing implementation details (internal function calls) instead of observable HTTP behavior.
Skipping negative test cases like invalid input or missing authentication.
Key Takeaways
Integration tests exercise the full request pipeline, middleware, routing, and handlers together.
Always use a dedicated or in-memory test database, never a shared or production one.
Clean up test data between tests to keep them independent and repeatable.
Cover both success and failure scenarios, including authentication and validation failures.
Pro Tip
Group integration tests by resource (describe('Users API', ...)) and by scenario within that (creation, validation, not-found, auth), this structure makes failures immediately clear when a test run fails.
You now know how to write integration tests. Next, dive deeper into the supertest library itself in the Supertest lesson.