feat(#288): real-form signup E2E with a Mailpit mail-catcher#347
Merged
Conversation
#288 item 3 — take the REAL human path end-to-end, the thing #287 proved untested: sign up via the real form → the real confirmation email lands in Mailpit → click the emailed link → authenticated. Runs against the LOCAL Supabase stack (Mailpit), because the cloud project has no readable inbox (Resend is send-only). - tests/e2e/signup-mailer/signup-confirm.spec.ts + tests/e2e/utils/mailpit.ts: the spec + a Mailpit REST helper. Fails LOUDLY if no email arrives — that is the #287 signal. - playwright.signup-mailer.config.ts: dedicated config (no globalSetup — the cloud-user prereq doesn't apply). Excluded from the main config's gen/mobile/tablet projects so it never runs against cloud. - docker-compose.yml: parameterize GOTRUE_MAILER_AUTOCONFIRM (default 'true' unchanged; the E2E sets it false to emit a real confirmation email) + pin GOTRUE_MAILER_URLPATHS_* to /auth/v1/verify (GoTrue's bare /verify default 404s at Kong — a real local-stack bug this surfaced). - .github/workflows/signup-mailer.yml: new CI job (local Supabase + Mailpit, autoconfirm off, root-anchored build pointed at the local stack, serve, run). Per-ref concurrency — ephemeral stack, no shared-backend mutex. Verified locally: autoconfirm=false → 'Confirm Your Email' in Mailpit; the fixed link 303-redirects to /auth/callback#access_token=…&type=signup; helper extraction works. type-check + lint clean. Full browser flow + CI orchestration proven by the new job. Refs #288 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jul 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
#288, item 3 — the real human signup path, end-to-end, including the mailer. This is the thing #287 proved was untested: the deployed product was unusable (email confirmation broke) while every test stayed green, because tests minted users via
admin.createUser({email_confirm:true})— bypassing the form and the mailer.This test does what a human does:
Refs #288 (not Closes — item 2
@smoke+ wiring the auth-config drift gate into CI still remain).Why local Supabase + Mailpit
The cloud shared project has no readable inbox (Resend is send-only). The local Supabase stack already bundles Mailpit (
supabase-mail), so a test can actually read the confirmation email. Owner chose the mail-catcher (best practice) over minting the link via the admin API, because proving email delivery is the whole point of #288.Changes
tests/e2e/signup-mailer/signup-confirm.spec.ts+tests/e2e/utils/mailpit.ts— the spec + a Mailpit REST helper (waitForMessageTo/extractConfirmationLink/clearMailbox). It fails loudly if no email arrives — that is exactly the Production OAuth broken since the Supabase project migration: client IDs are placeholders (recurrence of #85, closed-but-never-fixed) #287 signal, never a silent skip.playwright.signup-mailer.config.ts— dedicated config with noglobalSetup(the main config's globalSetup requires cloud creds + shared PRIMARY/TERTIARY users, absent on the ephemeral local stack). The spec is excluded from the main config's gen/mobile/tablet projects so it never runs against cloud.docker-compose.yml— (1) parameterizeGOTRUE_MAILER_AUTOCONFIRM(default'true'unchanged — normal local dev still auto-confirms; the E2E sets itfalseto emit a real confirmation email); (2) fix a real local-stack bug: pinGOTRUE_MAILER_URLPATHS_*to/auth/v1/verify. GoTrue's default is a bare/verify, butAPI_EXTERNAL_URLpoints at Kong (which only routes/auth/v1/*), so the emailed link would 404. (Matches the official Supabase stack.).github/workflows/signup-mailer.yml— new CI job (modeled onconformance.yml+e2e.yml): local Supabase + Mailpit with autoconfirm off, a root-anchored build pointed at the local stack, serve, run. Per-ref concurrency — the stack is per-runner ephemeral, so it needs no sharede2e-supabasemutex.Verified
Locally (the novel/risky mechanics), against the running local stack:
autoconfirm=false→ GoTrue sends "Confirm Your Email" into Mailpit.http://localhost:54321/auth/v1/verify?token=…&type=signup&redirect_to=…/auth/callback/, and visiting it returns303 → http://localhost:3000/auth/callback/#access_token=…&type=signup— the token verifies, session tokens land in the callback hash (implicit flow) exactly as the spec expects.type-check+lintclean.The full browser flow + CI orchestration are proven by the new
signup-mailerjob in this PR.🤖 Generated with Claude Code