Manual UI checks
The user performs browser appearance and interaction review. Use synthetic data in the local fixture, and record browser/version, scenario, expected result, actual result, and unresolved failures.
Admin workflows
Section titled “Admin workflows”- Check sign-in, required password change, account preferences, API-key reveal/copy, and sign-out with unsaved work.
- Create, edit, import, preview, and delete resources. Inspect empty, loading, failed, stale, and permission-limited states.
- Exercise source and visual editors, attachments, keyboard focus, dialogs, and content preservation between modes.
- Save a campaign draft, reload it, review recipients, schedule or launch it, inspect delivery, and resolve a controlled uncertain outcome.
- Filter analysis, inspect recipient timelines, export both formats, and compare displayed definitions with downloaded rows.
- Switch English/German, formatting locale, and time zone independently. Check persistence after another login and reset-to-browser behavior.
- Inspect narrow layouts, wrapped labels/actions, keyboard navigation, visible focus, reduced motion, and long localized strings.
Form validation and recovery
Section titled “Form validation and recovery”- Start a campaign with empty fields. Continue must stay on the incomplete step, show localized field feedback and move keyboard focus to the first error. Correct each step and confirm the draft is saved before the next step appears.
- Save an incomplete draft, reload it, and attempt Review. Missing audience/content or scheduled time must lead to the relevant editing step without a broken review page. Choose immediate delivery explicitly, then compare with a scheduled launch requiring a valid date and time zone.
- Delete a selected resource from another session before review, then correct the selection. Repeat with a schedule that has passed and with a launch response interrupted after submission; the latter must retain the existing retry action.
- Submit invalid resource content, including a recipient row, template expression and attachment. Confirm errors point to editable controls or content anchors and that the saved resource remains intact. Correct and save; then test a stale edit from another session.
- Check password confirmation, short and oversized passwords, blank password on a user edit, and blank secret on an integration edit. Confirm diagnostics never echo credentials and that a rejected change preserves the existing credential.
- Check settings duration ranges, invalid domain origins and preference values. Correct an error while a request is delayed; an obsolete field error must not replace the new state. Distinguish operational failures from field errors.
- Repeat in English and German using keyboard navigation and narrow layouts. Inspect labels, associated error descriptions, focus and hidden editor panels; functional Rust tests do not establish these browser behaviors.
Participant-browser checks
Section titled “Participant-browser checks”Keep the admin campaign view open alongside DevTools Network on the public page. Use invented canaries such as LOCAL-USERNAME-CANARY and LOCAL-PASSWORD-CANARY; never use real login information. Create a fresh campaign with seed when a case requires a clean recipient/session.
- Open the browser campaign email in Mailpit. Allow its external image if prompted. Confirm one
Email Openedevent only when the tracking image is fetched; opening Mailpit’s message view alone is not evidence of a fetch. Follow the practice link and confirm the greeting is personalized andClicked Linkappears for the same recipient. - Inspect the public document’s CSP and DOM. Native form submissions must be blocked by
form-action 'none'; the authored script must be absent, anddocument.body.dataset.authoredScriptExecutedmust be undefined. Ordinary names, IDs and autocomplete attributes should remain usable. - Submit with the password empty, then submit again on the same page with a synthetic password. Each submission must create a separate event. Campaign/dashboard summary counts stay at one recipient per category; recipient details show both events. The sole submission request body must contain
event_idand booleanpassword_present, with no usernames, password values, field maps, lengths or hashes. The corresponding history must show only submission/presence metadata. - Test a password manager with a synthetic saved entry and the external password control below the form. Confirm filling only that external control still reports presence. Repeat with a prefilled/read-only control and a revealed password. Disabled or unnamed controls must not report presence. Verify disabled-fieldset controls and the first-legend exception. In the page editor, confirm disabled controls receive advisory warnings and can still be saved. Check the network body again; do not infer privacy from the UI text.
- Block the public submission request in DevTools, submit, then unblock and use Retry this submission. The page must show an unconfirmed/error state, recover, and reuse the original event ID. For a true timeout, use a request-stalling proxy; DevTools Offline usually produces immediate failure, which does not prove the 15-second deadline. Timeout/retry logic also has isolated functional tests.
- Disable JavaScript and reload the public page. Attempt submission: no form data may leave through native navigation. Re-enable JavaScript afterward. Check console CSP failures as well as Network; an error alone does not prove that no data was sent.
- Disable the domain in admin, then try another page load/submission. It must fail without new events. Re-enable and verify as needed; complete the campaign and confirm later submissions likewise fail. Use a fresh campaign for subsequent cases.
- Inspect campaign responses/history and
tests/acceptance/data/ruphish.logfor your synthetic canaries. The automated test additionally scans database/WAL bytes for its own rejected-payload canary. Record browser/version, case, expected/actual result and any failure; do not attach real credentials or unredacted admin tokens.
Record the boundary
Section titled “Record the boundary”A passing direct HTTP test cannot prove that a browser sent no entered values. Inspect actual request bodies, blocked native submissions, and all applicable output channels before claiming end-to-end participant privacy. Retain synthetic evidence without publishing credentials, tokens, or fixture secrets.