DEV Community

Silviu Technology
Silviu Technology

Posted on

Playwright Checks for Facebook Signup Emails

When a team tests signup or recovery flows that look a lot like Facebook, the email step is often where confidence gets weird. The UI passes, the API returns 200, and then the inbox assertion grabs the wrong message because two workers touched the same alias a minute apart. I have seen this more than once, and it almost never gets fixed by adding a longer wait.

The better fix is to treat the email as part of the test contract. That means the inbox address, the trigger event, and the assertion all need one shared identifier. If you search for phrases like temp mail for facebook or even the clumsy temp mail mail, you will find a lot of advice about disposable inboxes, but the real QA problem is usually traceability, not just inbox creation.

Why Facebook-style signup emails are easy to misread in QA

These flows tend to fail in a pretty predictable way:

  • signup emails reuse the same subject line
  • retries send another valid message a few seconds later
  • parallel workers share lookup rules like "latest email wins"
  • manual testers leave notes like dummy e mail in fixtures and nobody cleans them up

That is enough to produce false passes. One run reads an older verification link, the assertion still sees "Confirm your account", and the suite goes green for the wrong reason. The Playwright team keeps stressing isolated state for parallel execution because workers are independent and collisions happen fast in real projects (https://playwright.dev/docs/test-parallel).

I use the same mindset from parallel worker inbox isolation: remove ambiguity before you tune retries. On the backend side, idempotent verification delivery is also worth studying, because duplicate sends and stale tokens often start there, not in the browser test.

The test contract that reduces wrong-message passes

My baseline contract is small:

  1. Generate a run id at the start of the test.
  2. Use a unique inbox for that run.
  3. Preserve the same run id in the app event or test metadata.
  4. Query the inbox by run id first, timestamp second.
  5. Assert both the business text and the run id before following links.

This sounds a bit fussy, but it makes failure analysis much simpler. Instead of asking "did any verification email show up?" you ask "did the verification email for run fb-pw-41a8c show up?" That is a much better question, and honestly a more usefull one when CI is noisy.

A small Playwright setup that stays debuggable

Here is the shape I like:

import { test, expect } from "@playwright/test";

test("signup sends the right verification email", async ({ page, request }) => {
  const runId = `fb-pw-${Date.now().toString(36)}`;
  const inbox = `signup-${runId}@example.test`;

  await request.post("/api/test/inboxes", {
    data: { inbox, runId, flow: "facebook-signup" }
  });

  await page.goto("/signup");
  await page.getByLabel("Email").fill(inbox);
  await page.getByLabel("Password").fill("ExamplePassword123!");
  await page.getByRole("button", { name: "Create account" }).click();

  const response = await request.get(`/api/test/inboxes/${inbox}?runId=${runId}`);
  const message = await response.json();

  expect(message.subject).toContain("Confirm your email");
  expect(message.runId).toBe(runId);
  expect(message.html).toContain("Verify account");
});
Enter fullscreen mode Exit fullscreen mode

Two details matter more than people think. First, the test helper is queryable by runId, not just by inbox address. Second, the email content gets checked before the link is followed. If you skip that order, you can still land on a valid page from an old message and miss the regression. It is a small detail, but it saves realy annoying triage later.

What I check when CI still flakes

If this test still fails, I walk the same path every time:

  • confirm the app generated the run id before the signup request
  • confirm the mail worker stored or forwarded the same id
  • confirm the test inbox API filters by run id before recency
  • confirm retries do not silently create a second run id
  • confirm the assertion uses the current worker's inbox, not a shared alias

I also like to log the run id in the Playwright trace name or attachment metadata. That makes the browser trace, server logs, and inbox record line up without much effort. When everything shares the same identifier, the bug usually becomes obvious prety fast.

Quick Q&A

Do I need a separate inbox per test?

Yes, if the suite runs in parallel or retries. Shared inboxes are cheap at first and expensive later.

What if I cannot change the provider payload?

Put the run id in the test harness and query API, then expose enough metadata in non-production to map the message back. You do not always need a custom header, but you do need a stable lookup path.

Is this only useful for social-login style flows?

No. Password reset, email change, invite acceptance, and digest notifications all benefit from the same contract. Signup is just where teams usualy notice the flake first.

Checklist before you merge

  • Every email-producing test gets a unique run id.
  • The inbox lookup filters by run id before it sorts by time.
  • The message assertion checks content before clicking links.
  • Parallel workers never point at the exact same inbox.
  • Retries keep evidence scoped to the current run.

Once these pieces are in place, Facebook-style signup email tests stop feeling mysterious. They still fail sometimes, sure, but they fail in ways a QA engineer can explain and fix without guesswork.

Top comments (0)