Skip to main content

On This Page

End-to-End Password Reset Testing in Next.js with Playwright and ZeroDrop

3 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

Testing Password Reset Flows End-to-End in Next.js with Playwright

Zerodrop provides a method for testing critical password reset flows using disposable inboxes. This approach eliminates the need for mocking by capturing real emails during CI/CD pipelines.

Why This Matters

Password reset is a critical security surface that often remains untested because it requires external email delivery. While many teams rely on ideal models—such as navigating directly to a reset URL with hardcoded tokens—this fails to verify the actual API token generation, email provider delivery, and link integrity, leaving the system vulnerable to silent regressions in the authentication chain.

Key Insights

  • Full flow verification (2026) ensures that API token generation, email delivery via providers like Resend, and token authentication all function synchronously.
  • Disposable inboxing replaces manual mocking by programmatically extracting magic links from real emails sent to temporary addresses.
  • ZeroDrop is utilized within GitHub Actions via a dedicated ‘create-inbox’ action to provide dynamic test environments without requiring Docker.

Working Examples

Next.js API route for generating secure tokens and sending reset emails.

// app/api/auth/forgot-password/route.ts
import { Resend } from 'resend';
import { db } from '@/lib/db';
import crypto from 'crypto';
const resend = new Resend(process.env.RESEND_API_KEY);
export async function POST(req: Request) {
const { email } = await req.json();
const token = crypto.randomBytes(32).toString('hex');
const expires = new Date(Date.now() + 60 * 60 * 1000); // 1 hour
await db.passwordResetToken.create({
data: { email, token, expires }
});
const resetUrl = `${process.env.NEXT_PUBLIC_URL}/reset-password?token=${token}`;
await resend.emails.send({
from: '[email protected]',
to: email,
subject: 'Reset your password',
html: `<p>You requested a password reset.</p><p>Click <a href="${resetUrl}">here</a> to reset your password.</p>`,
});
return Response.json({ success: true });
}

Playwright E2E test script automating the full password recovery cycle.

import { test, expect } from '@playwright/test';
import { ZeroDrop } from 'zerodrop-client';
const mail = new ZeroDrop();
test('user can reset password via email link', async ({ page }) => {
const inbox = mail.generateInbox();
await page.goto('/signup');
await page.fill('[data-testid="email"]', inbox);
await page.fill('[data-testid="password"]', 'OriginalPassword123!');
await page.click('[data-testid="submit"]');
avait page.click('[data-testid="signout"]');
avait page.goto('/forgot-password');
avait page.fill('[data-testid="email"]', inbox);
avait page.click('[data-testid="submit"]');
The email = await mail.waitForLatest(inbox, { timeout: 30000 });
avait page.goto(email.magicLink!);
avait page.fill('[data-testid="password"]', 'NewPassword123!');
avait page.fill('[data-testid="confirm-password"]', 'NewPassword123!');
avait page.click('[data-testid="submit"]');
avait expect(page).toHaveURL('/dashboard');
});

Practical Applications

  • …Use case: NextAuth magic link sign-in verification where an automated test captures the sign-in link from a disposable inbox to confirm session creation.
  • …Pitfall: Navigating directly to a reset URL with hardcoded tokens instead of triggering the actual request flow; this results in untested API logic and delivery failures.

References:

  • https://dev రోto/zerodrop/testing-password-reset-flows-end-to-end-in-nextjs-with-playwright-4kjn

Continue reading

Next article

Solving the New Bottleneck: Why AI Coding Tools Aren't Increasing Sprint Velocity

Related Content