MoeMail
Back to Blog

Testing Magic-Link / Passwordless Login

Passwordless (magic-link) login is lovely for users and awkward for tests: there's no password to type, just a one-time link delivered by email. The good news — it's the same inbox-read pattern as everything else in email testing for developers, and a near-twin of password-reset testing.

The flow

  1. Provision a fresh disposable inbox and request a magic link for it.
  2. Read the email and pull out the sign-in URL.
  3. Open the URL and assert you land in an authenticated session.

Example (Playwright)

const inbox = await createInbox()
await page.goto('/login')
await page.getByLabel('Email').fill(inbox.address)
await page.getByRole('button', { name: 'Send magic link' }).click()

const msg = await waitForMessage(inbox.id, 30000)
// first http(s) URL in the email body
const link = (msg.links && msg.links[0])
  || msg.text.split(/\s+/).find(w => w.indexOf('http') === 0)

await page.goto(link)
await expect(page.getByText('Signed in')).toBeVisible()

The createInbox / waitForMessage helpers come from the Playwright tutorial; the Cypress custom commands work the same way.

Edge cases

Expired links, single-use enforcement (a second click should fail), and requesting a link for an unknown address (respond identically to avoid user enumeration). Each is a small variant of the flow above. Compare with OTP and 2FA testing when a second factor is also involved.

Get started

Create a mailbox and read the OpenAPI docs to wire the inbox calls into your suite.