Write tests that deliver the same message more than once. Then check that the effect happened only once.
The basic test: call the handler twice with the same payload and the same message id. Then check there is:
- one order row
- one charge on the stubbed payment gateway
- one email
The harder cases:
- The handler crashes after writing to the database but before it acks (confirms the message). The broker then delivers the message again.
- Two workers process the same message at the same time. Use
Promise.allagainst a real database, so the unique constraint or lock is really tested. - Messages arrive in the wrong order.
The code usually uses a "processed messages" table with a unique key, or a natural unique constraint. It writes this in the same transaction as the business change. The tests must prove this design holds. That is why they need the real database, not a mocked repository.
- Deliver the same message twice and check there is only one effect.
- Simulate a crash before the ack, then a second delivery.
- Test two workers processing the same message at once, against a real database.
- Use an idempotency key or unique constraint in the same transaction as the business change.
Read more
- Testcontainers (https://testcontainers.com/)testcontainers.com