4.9 KiB
QA procedure: transactional email templates
Automated (Go, test/)
This slice touches a use-case call site (a string literal) and two static template files; it has
no new HTTP surface of its own, so no new handler/router wiring is exercised here. Reuse the
existing fakes already in test/ (mockMailRepo from test/mail_test.go, the fake user.Repository
used by the registration and password-reset tests) rather than building new ones.
-
Registration sends "verification". In the existing registration test file (or its replacement after this slice), build
CreateUserUseCaseover an empty fakeuser.Repository, a real hasher, andmockMailRepo, callCreateUserwith usernamealice, passwordhunter2example12, emailalice@example.com, assert the call succeeds, then assertmockMailRepo.SentEmailshas exactly one entry whoseTemplatefield equals"verification"(not"mailValidation"). -
Password reset sends "password-reset". Build
RequestPasswordResetUseCaseover a fakeuser.Repositoryseeded with a user whose email isalice@example.com, a real hasher,mockMailRepoand a public URL, callRequestPasswordReset("alice@example.com"), assert it returnsnil, then assertmockMailRepo.SentEmailshas exactly one entry whoseTemplatefield equals"password-reset"(not"passwordReset"). -
render() produces the right subject, link and copy for each known template. Construct a real
mailer.NewMailRepository(config.SmtpSettings{})(SMTP fields are irrelevant sinceDialAndSendis never called here) and call its render step directly (test lives in packagetest, so this exercises the exported behavior surface of a real*mailer.MailRepositorywithout opening a network connection):render("verification", <data with Host "https://cms.example.com", VerificationCode "abc123">)→ subject"Verify your RenewCMS account", body containshttps://cms.example.com/register/validate?c=abc123,Verify my account,This link expires in 2 hours.render("password-reset", <data with Host "https://cms.example.com", VerificationCode "abc123", Email "alice@example.com">)→ subject"Reset your RenewCMS password", body containshttps://cms.example.com/register/reset/validate?c=abc123&email=alice%40example.com,Choose a new password,This link expires in 1 hour and works once.
(
html/templateauto-escapesEmailin the query string, turning@into%40; assert the escaped form, matching whatMailRepository.Sendwill actually produce.)
3b. render() fallback and failure paths.
render("does-not-exist", nil)returns an error (template file not found) and the returned subject is still the old default"RenewCMS | Action required", with an empty body.- A
render(<known templateName>, <data that fails Execute>)call returns an error; assertMailRepository.Sendwith the same inputs returns an error too and never gets toDialAndSend(no network dependency needed to prove this: a failingrenderreturn is sufficient to proveSendshort-circuits before dialing, sinceSend's existing structure calls render, then returns immediately on its error).
-
Old template files are gone.
os.Stat("internal/infrastructure/mailer/templates/mailValidation.html")and thepasswordReset.htmlequivalent each return an error satisfyingos.IsNotExist. -
Existing slice tests still pass with updated literals. Run the full suite (
task test) and confirm the tests backingregistration_gate_and_verification_email.featureandrequest_password_reset.featurestill pass now that their scenario text and any Go assertions inside their test files use"verification"and"password-reset"instead of the old strings. If those test files still contain the old literals as Go string constants (not just prose in the.featurefiles), they need the same rename; point this out tocoderrather than silently doing a code edit here.
Manual verification (not covered by the automated Go tests above)
- Rendered appearance in an actual mail client. The bulletproof button (table-cell background +
padded link), the hidden preheader text, and the
prefers-color-scheme: darkoverrides can only be judged by opening the rendered HTML in a real or preview mail client (or the board filedocs/design/source/RenewCMS Emails.dc.htmlnext to a manually triggered send through a real SMTP server) — this is not somethingos.ReadFile+html/template.Executecan verify. Confirm both light and dark rendering for both templates. - Real SMTP delivery end to end. Sending an actual email via
SMTP_HOST/SMTP_PORTand eyeballing the arrived message (subject line, sender name "RenewCMS <...>", clickable button, monospace fallback URL) is a manual item; nothing here exercisesgomail.Dialer.DialAndSend.