3.0 KiB
ADDED Requirements
Requirement: Mailpit image policy
The @suaveplan/testing-integration-mailpit plugin SHALL pin to axllent/mailpit at a fixed minor tag (e.g. axllent/mailpit:v1.20). The plugin MUST NOT use the latest tag. A follow-up operational change tracked at docs/superpowers/specs/2026-04-25-test-suite-audit.md §5 will pin to sha256:<digest>.
Scenario: Image tag pinned to minor
- WHEN the container factory is invoked without injection
- THEN the resulting container uses an
axllent/mailpit:v<major>.<minor>tag — neveraxllent/mailpit:latest
Requirement: Env-bridge contract
The plugin SHALL declare and forward both MAILPIT_SMTP_URL and MAILPIT_API_URL. When BOTH are set on the parent process at construction time, the fixture MUST enter env-bridge passthrough mode. A partial-set (only one of the two) MUST throw INTEGRATION.MAILPIT.PARTIAL_ENV at construction.
Scenario: env() returns the full set
- WHEN the fixture has started in container mode
- THEN
fixture.env()returns a record with exactly the keysMAILPIT_SMTP_URLandMAILPIT_API_URL
Scenario: Partial env-bridge rejected
- WHEN only
MAILPIT_SMTP_URLis set onprocess.envat construction - THEN the constructor throws with
code === "INTEGRATION.MAILPIT.PARTIAL_ENV"
Requirement: Healthcheck contract — API ping
isHealthy() SHALL issue an HTTP GET to the Mailpit API health endpoint and treat a 2xx response as healthy. The fixture constructor SHALL accept an optional fetch parameter for test injection.
Scenario: 2xx is healthy
- WHEN the API health endpoint returns 200
- THEN
isHealthy()resolvestrue
Requirement: assertMail() helper
The package SHALL export assertMail(opts: { to?: string | string[]; from?: string; subject?: string; subjectMatch?: "exact" | "partial" }) that queries the Mailpit API and asserts at least one matching message exists. Address matching MUST be exact. Subject matching defaults to "partial" (substring on subject); callers MAY opt into exact matching. On no match, the helper MUST throw with code === "INTEGRATION.MAILPIT.NO_MATCH" and context listing the candidates that were considered.
Scenario: Partial subject match by default
- WHEN Mailpit holds a message with subject
"Welcome to Suaveplan, please confirm your email"andassertMail({ subject: "Welcome to Suaveplan" })is invoked - THEN the helper resolves without throwing
Scenario: Exact address match required
- WHEN Mailpit holds a message addressed to
user@example.comandassertMail({ to: "USER@example.com" })is invoked without case-insensitivity opt-in - THEN the helper rejects with
INTEGRATION.MAILPIT.NO_MATCH
Requirement: Error-code prefix
Errors thrown from the plugin SHALL carry codes matching ^INTEGRATION\.MAILPIT\.[A-Z_]+$.
Scenario: Coded helper failure
- WHEN
assertMail()finds no match - THEN the rejection's
code === "INTEGRATION.MAILPIT.NO_MATCH"ANDcontext.candidatesis an array