Files
2026-05-27 23:29:53 +01:00

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 — never axllent/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 keys MAILPIT_SMTP_URL and MAILPIT_API_URL

Scenario: Partial env-bridge rejected

  • WHEN only MAILPIT_SMTP_URL is set on process.env at 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() resolves true

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" and assertMail({ 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.com and assertMail({ 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" AND context.candidates is an array