Skip to content

Cypress

Cypress specs run in the browser, where an API key must never go. The SDK call lives in a Cypress task in the Node process, and the spec calls the task.

Terminal window
npm install --save-dev @mailcatchr/sdk
cypress.config.ts
import { defineConfig } from "cypress";
import { createClient } from "@mailcatchr/sdk";
const mc = createClient({ apiKey: process.env.MAILCATCHR_API_KEY! });
const mailboxId = process.env.MAILCATCHR_MAILBOX_ID!;
export default defineConfig({
e2e: {
setupNodeEvents(on) {
on("task", {
async waitForMail({ to, subject }: { to: string; subject?: string }) {
const summary = await mc.messages.await(mailboxId, { to, subject, timeoutSeconds: 30 });
if (!summary) return null;
return mc.messages.get(mailboxId, summary.id);
},
async totpCode(totpId: string) {
return (await mc.totps.code(totpId)).code;
},
});
},
},
});

Cypress tasks have a default timeout of 60 seconds, which covers the 30-second wait.

describe("signup", () => {
it("sends a verification link that works", () => {
const email = `signup-${Date.now()}@acme-ci.mailcatchr.com`;
cy.visit("/signup");
cy.get('input[name="email"]').type(email);
cy.get('input[name="password"]').type("correct horse battery staple");
cy.get('button[type="submit"]').click();
cy.task("waitForMail", { to: email, subject: "Verify your email" }).then((message: any) => {
expect(message, "verification email").to.not.be.null;
const link = message.textBody.match(/https:\/\/\S+\/verify\?token=\S+/)[0];
cy.visit(link);
});
cy.contains("Email verified");
});
});
cy.task("totpCode", Cypress.env("MAILCATCHR_TOTP_ID")).then((code) => {
cy.get('input[name="otp"]').type(code as string);
});

Pass the authenticator id in with CYPRESS_MAILCATCHR_TOTP_ID in the environment; the key itself stays in MAILCATCHR_API_KEY on the Node side only.