Custom Cypress commands and examples for email testing with Mailoverse. Learn to create reusable commands for email verification, signup flows, and password reset testing.

Cypress

Custom Cypress commands for email retrieval and testing email verification flows.

Configuration

First, configure Cypress to use your Mailoverse credentials:

// cypress.config.ts
import { defineConfig } from 'cypress';

export default defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
    env: {
      MAILOVERSE_DOMAIN: process.env.MAILOVERSE_DOMAIN,
      MAILOVERSE_API_KEY: process.env.MAILOVERSE_API_KEY,
    },
  },
});

Custom Commands

Add these custom commands to your cypress/support/commands.ts:

// cypress/support/commands.ts
declare global {
  namespace Cypress {
    interface Chainable {
      waitForEmail(address: string, options?: { timeout?: number }): Chainable<any>;
      generateTestEmail(prefix?: string): Chainable<string>;
    }
  }
}

Cypress.Commands.add('generateTestEmail', (prefix = 'test') => {
  const domain = Cypress.env('MAILOVERSE_DOMAIN');
  const email = `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}@${domain}`;
  return cy.wrap(email);
});

Cypress.Commands.add('waitForEmail', (address, options = {}) => {
  const { timeout = 30000 } = options;
  const apiKey = Cypress.env('MAILOVERSE_API_KEY');

  const checkEmail = (startTime: number): Cypress.Chainable<any> => {
    if (Date.now() - startTime > timeout) {
      throw new Error(`Timeout waiting for email to ${address}`);
    }

    return cy.request({
      method: 'GET',
      url: `https://api.mailoverse.com/email?address=${encodeURIComponent(address)}`,
      headers: { 'Authorization': `Bearer ${apiKey}` },
    }).then((response) => {
      if (response.body.email) {
        return response.body.email;
      }
      return cy.wait(1000).then(() => checkEmail(startTime));
    });
  };

  return checkEmail(Date.now());
});

export {};

Signup Test

Using the commands in a signup flow test:

// cypress/e2e/signup.cy.ts
describe('Signup Flow', () => {
  it('should complete email verification', () => {
    cy.generateTestEmail('signup').then((testEmail) => {
      // Complete signup
      cy.visit('/signup');
      cy.get('[name="email"]').type(testEmail);
      cy.get('[name="password"]').type('SecurePass123!');
      cy.get('button[type="submit"]').click();

      // Wait for email and verify
      cy.waitForEmail(testEmail).then((email) => {
        expect(email.subject).to.include('Verify');

        const verifyLink = email.parsedHtml.links.find(
          (link: { href: string }) => link.href.includes('/verify')
        );
        cy.visit(verifyLink.href);
        cy.get('h1').should('contain', 'Email Verified');
      });
    });
  });
});

Password Reset Test

// cypress/e2e/password-reset.cy.ts
describe('Password Reset Flow', () => {
  it('should send and process password reset email', () => {
    cy.generateTestEmail('reset').then((testEmail) => {
      // First, create an account
      cy.visit('/signup');
      cy.get('[name="email"]').type(testEmail);
      cy.get('[name="password"]').type('OldPassword123!');
      cy.get('button[type="submit"]').click();

      // Verify the account
      cy.waitForEmail(testEmail).then((signupEmail) => {
        const verifyLink = signupEmail.parsedHtml.links[0];
        cy.visit(verifyLink.href);

        // Now trigger password reset
        cy.visit('/forgot-password');
        cy.get('[name="email"]').type(testEmail);
        cy.get('button[type="submit"]').click();

        // Wait for reset email
        cy.waitForEmail(testEmail).then((resetEmail) => {
          expect(resetEmail.subject).to.include('Reset');

          const resetLink = resetEmail.parsedHtml.links.find(
            (link: { href: string }) => link.href.includes('/reset-password')
          );

          // Complete the reset
          cy.visit(resetLink.href);
          cy.get('[name="password"]').type('NewPassword456!');
          cy.get('[name="confirmPassword"]').type('NewPassword456!');
          cy.get('button[type="submit"]').click();

          cy.get('h1').should('contain', 'Password Updated');
        });
      });
    });
  });
});

Using a Task (Alternative)

For better reliability, you can use a Cypress task for server-side email retrieval:

// cypress/plugins/index.ts (Cypress 9) or cypress.config.ts (Cypress 10+)
// Using a task for server-side email retrieval

// In cypress.config.ts:
import { defineConfig } from 'cypress';

export default defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      on('task', {
        async waitForEmail({ address, timeout = 30000 }) {
          const apiKey = process.env.MAILOVERSE_API_KEY;
          const startTime = Date.now();

          while (Date.now() - startTime < timeout) {
            const response = await fetch(
              `https://api.mailoverse.com/email?address=${encodeURIComponent(address)}`,
              { headers: { 'Authorization': `Bearer ${apiKey}` } }
            );
            const data = await response.json();

            if (data.email) {
              return data.email;
            }

            await new Promise(resolve => setTimeout(resolve, 1000));
          }

          throw new Error(`Timeout waiting for email to ${address}`);
        },
      });
      return config;
    },
  },
});

// Usage in tests:
cy.task('waitForEmail', { address: testEmail }).then((email) => {
  expect(email.subject).to.include('Verify');
});

See Also