@playwright-labs/fixture-gmail
v0.3.0
Published
Gmail fixture integration for Playwright/test — find, read and send emails via the Gmail API
Downloads
213
Maintainers
Readme
Playwright Gmail support
Gmail fixture for Playwright/test — find, read and send emails straight from your tests via the Gmail API.
test("someTest", async ({ gmail }) => {
const emails = await gmail.findEmail({ subject: /qwe/ });
expect(emails).not.toBeNull();
const body = await gmail.readEmail(emails![0].id);
expect(body).toContain("123456");
});Installation
npm i -D @playwright/test @playwright-labs/fixture-gmailpnpm add -D @playwright/test @playwright-labs/fixture-gmailyarn add -D @playwright/test @playwright-labs/fixture-gmailAuthentication
The client talks to the Gmail API with an OAuth2 access token. Two setups are supported:
- Refresh token (recommended) — the client exchanges it for a short-lived access token and caches it:
GMAIL_CLIENT_ID,GMAIL_CLIENT_SECRET,GMAIL_REFRESH_TOKEN
- Static access token — used as-is (expires in ~1 hour, fine for local runs):
GMAIL_ACCESS_TOKEN
To get a refresh token: create a Google Cloud project, enable the Gmail API, create OAuth2 credentials (web application), then authorize the https://mail.google.com/ scope (e.g. via the OAuth 2.0 Playground with your own client id/secret) and exchange the authorization code for tokens.
Values can also be passed directly via options:
const gmail = useGmail({ clientId, clientSecret, refreshToken });
// or
const gmail = useGmail({ accessToken });Fixture
gmail: Gmail— ready-to-use client configured from theGMAIL_*env variables.useGmail(options?: GmailOptions): Gmail— factory for a client with custom options.
import { test, expect } from "@playwright-labs/fixture-gmail";
test("custom client", async ({ useGmail }) => {
const gmail = useGmail({ accessToken: process.env.SECOND_ACCOUNT_TOKEN });
await gmail.sendEmail({ to: "[email protected]", subject: "hi", body: "<h1>hello</h1>" });
});API
findEmail(options?): Promise<Email[] | null>
Searches the mailbox and returns matching emails (newest first) or null when nothing matches.
| Option | Type | Description |
| --------- | ------------------- | --------------------------------------------------------------------------- |
| subject | string \| RegExp | String -> Gmail query subject:"...", RegExp -> client-side header filter |
| from | string \| RegExp | Sender filter (same rules as subject) |
| to | string \| RegExp | Recipient filter (same rules as subject) |
| query | string | Raw Gmail search query, e.g. "newer_than:1h has:attachment" |
| unread | boolean | Adds is:unread to the query |
| limit | number | Max messages to inspect (default 10) |
Email contains id, threadId, subject, from, to, date and snippet — plus bound body readers: email.readAsString(), email.readAsBytes() and email.readAsStream().
readEmail(emailId, options?): Promise<string>
Returns the decoded body of a message. HTML is preferred by default; pass { format: "text" } for plain text. Falls back to the other format when the preferred part is absent.
waitForEmail(options?): Promise<Email>
Polls findEmail until at least one email matches and returns the newest one. Accepts all findEmail options plus timeout (default 30000 ms) and interval (default 1000 ms). Throws when nothing matches within the timeout.
const email = await gmail.waitForEmail({ to: user.email, subject: /verify/i });getEmailLinks(emailId): Promise<string[]>
Reads the email's HTML body and returns all unique href values — handy for confirmation/reset links:
const [confirmUrl] = await gmail.getEmailLinks(email.id);
await page.goto(confirmUrl!);markAsRead(emailId): Promise<void>
Marks a message as read (removes the UNREAD label via users.messages.modify). Requires the gmail.modify scope.
sendEmail(options): Promise<{ id, threadId }>
await gmail.sendEmail({
to: ["[email protected]", "[email protected]"],
cc: "[email protected]",
bcc: "[email protected]",
subject: "Test report",
body, // HTML string
attachments: [{ filename: "report.html", path: "playwright-report/index.html" }],
});attachments follow the nodemailer Attachment shape — filename, content (string | Buffer | base64), path, href, contentType, and cid for inline images.
Body primitives
The package re-exports the same string HTML primitives as @playwright-labs/reporter-email — every helper returns a string, so they compose by plain nesting:
h, fragment, html, head, title, body, div, p, a, img, ul, li, table, thead, tbody, tr, td, th, h1–h6, br, hr.
import { div, fragment, h1, table, tbody, td, thead, tr, img } from "@playwright-labs/fixture-gmail";
const body = div(
fragment(
h1("Playwright Test Report"),
table(
fragment(
thead(tr(fragment(td("Test"), td("Status")))),
tbody(tr(fragment(td("login.spec.ts"), td("passed")))),
),
),
img({ src: "cid:logo" }), // inline image from attachments
),
);
await gmail.sendEmail({
to: "[email protected]",
subject: "Report",
body,
attachments: [{ path: "./logo.png", cid: "logo" }],
});License
MIT
