@assertkit/playwright
v0.4.0
Published
Playwright fixture for AssertKit — test signup, OTP, magic-link, and verification-URL email flows without flake.
Downloads
1,187
Maintainers
Readme
@assertkit/playwright
Playwright fixture for AssertKit — test signup, OTP, magic-link, and verification-URL email flows without flake.
import { test, expect } from "@assertkit/playwright";
test("user can sign up with email OTP", async ({ page, inbox }) => {
await page.goto("/signup");
await page.getByLabel("Email").fill(inbox.address);
await page.getByLabel("Password").fill("correct-horse-battery-staple");
await page.getByRole("button", { name: "Sign up" }).click();
// Long-poll the inbox. Returns the moment the OTP arrives — no
// arbitrary timeouts, no regex parsing in your test code.
const otp = await inbox.waitForOtp({ from: "noreply" });
await page.getByLabel("Verification code").fill(otp);
await page.getByRole("button", { name: "Verify" }).click();
await expect(page).toHaveURL(/\/dashboard/);
});Why
Most E2E suites end up with a 60-line waitForEmail helper: REST polling, regex parsing, race conditions, occasional flakes. This package replaces it with a single fixture call.
- No polling glue. One HTTP call returns the moment a matching message arrives, up to 25s.
- No body parsing. OTPs, magic links, and verification URLs are extracted server-side. Your test gets the value.
- Parallel-safe by default. Each test gets a unique-per-run inbox so Playwright shards never collide.
- Free to try. No signup required — the fixture works out of the box against the free public surface of
assertkit.com.
Install
npm install --save-dev @assertkit/playwright
# or
pnpm add -D @assertkit/playwright
# or
yarn add -D @assertkit/playwrightUsage
The fixture (recommended)
Import test and expect from @assertkit/playwright instead of @playwright/test. Every test gets an inbox fixture for free.
import { test, expect } from "@assertkit/playwright";
test("magic-link login", async ({ page, inbox }) => {
await page.goto("/login");
await page.getByLabel("Email").fill(inbox.address);
await page.getByRole("button", { name: "Send link" }).click();
const magicLink = await inbox.waitForMagicLink();
await page.goto(magicLink);
await expect(page).toHaveURL(/\/dashboard/);
});Filters
// Only the email from a specific sender:
const otp = await inbox.waitForOtp({ from: "[email protected]" });
// Plus a subject filter — when your app sends multiple emails:
const otp = await inbox.waitForOtp({
from: "noreply",
subjectContains: "verify",
timeoutMs: 30_000,
});Read the whole message
const message = await inbox.waitForMessage({ from: "noreply" });
expect(message.subject).toContain("Verify your email");
expect(message.from_addr).toBe("[email protected]");Standalone (no fixture)
If you don't want to swap your test import, the building blocks are exported too:
import { AssertKitClient, Inbox, uniqueLocalPart } from "@assertkit/playwright";
const client = new AssertKitClient(); // or new AssertKitClient({ apiKey: "ak_..." })
const inbox = new Inbox(uniqueLocalPart(), client);
const otp = await inbox.waitForOtp();Configuration
The fixture reads three environment variables — no code changes needed in most CI setups:
| Variable | Purpose | Default |
|---|---|---|
| ASSERTKIT_API_KEY | Use the authenticated /api/v1 surface (higher limits, webhooks, BYO domain) instead of the free public surface | unset (uses free tier) |
| ASSERTKIT_BASE_URL | Override the AssertKit base URL (self-hosted deployments) | https://assertkit.com |
| ASSERTKIT_DOMAIN | Domain part of inbox addresses (set when using BYO custom domain) | assertkit.com |
Or override per-test:
test.use({ assertkit: { apiKey: process.env.MY_KEY, domain: "mail.acme.dev" } });TypeScript
Fully typed. The inbox fixture is typed as Inbox; all wait responses, filters, and extracted codes have full types you can import:
import type { Inbox, WaitMessage, ExtractedCode } from "@assertkit/playwright";License
MIT — see LICENSE.
Using Cypress instead?
Same author, same API shape: @assertkit/cypress ships cy.waitForOtp, cy.waitForMagicLink, cy.waitForVerificationUrl, and cy.uniqueInbox with one-line registration. See the Cypress guide.
