57 lines
3.0 KiB
Markdown
57 lines
3.0 KiB
Markdown
## 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
|