✨ feat(bdd): pkg/bdd/mailpit/ HTTP client + integration tests (ADR-0030 Phase A.2)
Adds the Mailpit HTTP API client used by BDD scenarios to assert on
emails sent during a test. Implements the per-recipient query/await/
purge pattern from ADR-0030.
Build-tag-gated integration tests run against the live Mailpit at
localhost:8025 (started via docker compose up -d mailpit).
Three operations on the client:
- MessagesTo(ctx, to) — list message IDs for a recipient
- Get(ctx, id) — fetch full message content (text, html,
headers, subject, etc.)
- AwaitMessageTo(ctx, to, — poll until a message arrives or timeout
timeout) (50ms polls, fail-fast on ctx cancel)
- PurgeMessagesTo(ctx, to) — delete all messages for a recipient
Tests in client_integration_test.go (build tag `integration`):
- RoundTrip: SMTP submit → list → get → assert subject/text — proves
the BDD-helper contract end-to-end via real SMTP
- AwaitTimeoutWhenNoMessage: bounded wait when no email arrives
- PurgeIsolation: per-recipient delete does NOT affect other recipients
Mailpit API quirk discovered + documented (Q-NNN candidate):
- /api/v1/messages?query=... is for PAGINATION, not filtering — the
`query` param there is silently ignored for filtering
- /api/v1/search?query=to:<addr> is the correct endpoint for filtering
AND the matching DELETE
- ADR-0030 + EMAIL.md updated with the correct endpoint
Run integration tests:
docker compose up -d mailpit
go test -tags integration -race ./pkg/bdd/mailpit/...
Out of scope for this PR (Phase A.3+):
- pkg/bdd/steps/email_steps.go BDD step definitions
- magic_link_tokens table + repository
- magic-link/request and magic-link/consume HTTP handlers
- BDD scenarios for the magic-link flow
This commit is contained in:
@@ -36,7 +36,7 @@ Each BDD scenario generates a unique email address for its test user, derived fr
|
||||
|
||||
The application code accepts any email format. The BDD scenario asserts on Mailpit's HTTP API filtering by the `to` address. Two parallel scenarios with different addresses can NEVER see each other's emails.
|
||||
|
||||
**Cleanup** : at the start of each scenario, the BDD framework calls `DELETE /api/v1/messages?query=to:<scenario-address>` on Mailpit to purge any leftover messages from prior runs.
|
||||
**Cleanup** : at the start of each scenario, the BDD framework calls `DELETE /api/v1/search?query=to:<scenario-address>` on Mailpit to purge any leftover messages from prior runs.
|
||||
|
||||
### Option 2: One Mailpit instance per Go test package
|
||||
|
||||
@@ -127,7 +127,7 @@ func (s *EmailSteps) theEmailContainsAMagicLinkToken() (string, error)
|
||||
|
||||
### Race-free deletion
|
||||
|
||||
Mailpit's `DELETE /api/v1/messages?query=to:<addr>` is atomic per recipient. Two concurrent scenarios with different addresses cannot interfere.
|
||||
Mailpit's `DELETE /api/v1/search?query=to:<addr>` is atomic per recipient. Two concurrent scenarios with different addresses cannot interfere.
|
||||
|
||||
### Sample scenario (auth-magic-link.feature)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user