Cypress Email Testing Guide

Updated February 14, 2024

Learn how to implement robust email testing in your Cypress end-to-end tests using Mail7. This guide covers everything from basic setup to advanced email testing scenarios in modern web applications.

Setting Up Cypress Email Testing

1. Installation

First, install the necessary dependencies:

npm install cypress @mail7/cypress-plugin --save-dev

2. Configuration

Configure Cypress by adding Mail7 plugin to your cypress.config.js:

const { defineConfig } = require('cypress')

module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on, config) {
      require('@mail7/cypress-plugin')(on, config)
    },
    env: {
      MAIL7_API_KEY: 'your-api-key',
      MAIL7_WAIT_TIMEOUT: 10000, // Optional: customize wait timeout
      MAIL7_RETRY_INTERVAL: 1000  // Optional: customize retry interval
    }
  }
})

3. Custom Commands Setup

Add custom commands in cypress/support/commands.js:

// Custom command to generate test email
Cypress.Commands.add('generateTestEmail', () => {
  const timestamp = Date.now();
  return `test-${timestamp}@mail7.io`;
});

// Custom command to wait for email with retry
Cypress.Commands.add('waitForEmailWithRetry', (email, options = {}) => {
  const {
    timeout = 10000,
    retries = 3,
    interval = 2000
  } = options;

  return cy.wrap(null).then(() => {
    function checkEmail(attempt) {
      return cy.waitForEmail(email, { timeout })
        .catch(error => {
          if (attempt < retries) {
            cy.wait(interval);
            return checkEmail(attempt + 1);
          }
          throw error;
        });
    }
    return checkEmail(0);
  });
});

Basic Email Testing

describe('Email Testing', () => {
  let testEmail;

  beforeEach(() => {
    // Generate a unique test email before each test
    cy.generateTestEmail().then(email => {
      testEmail = email;
    });
  });

  it('should verify registration email', () => {
    // Register user with test email
    cy.visit('/register');
    cy.get('#email').type(testEmail);
    cy.get('#password').type('TestPassword123');
    cy.get('#register-button').click();

    // Wait for and verify the email
    cy.waitForEmailWithRetry(testEmail).then(email => {
      expect(email.subject).to.contain('Welcome');
      expect(email.html).to.contain('verify your account');
      
      // Extract and visit verification link
      const verifyLink = email.html.match(/href="([^"]*verify[^"]*)"/)[1];
      cy.visit(verifyLink);
      
      // Verify successful verification
      cy.get('.verification-success').should('be.visible');
    });
  });
});

Advanced Testing Scenarios

1. Password Reset Flow

it('should complete password reset flow', () => {
  const newPassword = 'NewPassword123!';
  
  // Trigger password reset
  cy.visit('/forgot-password');
  cy.get('#email').type(testEmail);
  cy.get('#reset-button').click();

  // Verify and use reset email
  cy.waitForEmailWithRetry(testEmail).then(email => {
    expect(email.subject).to.contain('Password Reset');
    
    // Extract reset token and link
    const resetLink = email.html.match(/href="([^"]*reset[^"]*)"/)[1];
    cy.visit(resetLink);
    
    // Set new password
    cy.get('#new-password').type(newPassword);
    cy.get('#confirm-password').type(newPassword);
    cy.get('#submit-reset').click();
    
    // Verify successful reset
    cy.get('.reset-success').should('be.visible');
    
    // Verify login with new password
    cy.visit('/login');
    cy.get('#email').type(testEmail);
    cy.get('#password').type(newPassword);
    cy.get('#login-button').click();
    cy.get('.dashboard').should('be.visible');
  });
});

2. Multi-Step Email Verification

it('should handle multi-step verification', () => {
  // Setup test data
  const verificationCode = '123456';
  
  // Start verification process
  cy.visit('/verify-account');
  cy.get('#email').type(testEmail);
  cy.get('#send-code').click();

  // Wait for and verify first email
  cy.waitForEmailWithRetry(testEmail).then(email => {
    expect(email.subject).to.contain('Verification Code');
    
    // Extract and enter verification code
    const code = email.text.match(/(\d{6})/)[1];
    cy.get('#verification-code').type(code);
    cy.get('#verify-code').click();
    
    // Complete additional verification steps
    cy.get('#setup-2fa').click();
    
    // Wait for and verify second email
    cy.waitForEmailWithRetry(testEmail, { timeout: 15000 }).then(secondEmail => {
      expect(secondEmail.subject).to.contain('2FA Setup');
      // Complete 2FA setup
      const setupCode = secondEmail.text.match(/(\d{6})/)[1];
      cy.get('#2fa-code').type(setupCode);
      cy.get('#complete-2fa').click();
    });
  });
});

3. Email Template Testing

it('should verify email template rendering', () => {
  // Test data
  const templateData = {
    username: 'TestUser',
    items: ['Item 1', 'Item 2'],
    total: '$99.99'
  };
  
  // Trigger template email
  cy.request('POST', '/api/send-template', {
    email: testEmail,
    template: 'order-confirmation',
    data: templateData
  });

  // Verify template rendering
  cy.waitForEmailWithRetry(testEmail).then(email => {
    // Verify subject
    expect(email.subject).to.contain('Order Confirmation');
    
    // Verify content
    expect(email.html)
      .to.contain(templateData.username)
      .and.to.contain(templateData.items[0])
      .and.to.contain(templateData.items[1])
      .and.to.contain(templateData.total);
    
    // Verify styling
    expect(email.html).to.match(/]*>[\s\S]*<\/style>/);
    
    // Verify links
    const links = email.html.match(/href="([^"]*)"/g);
    expect(links).to.have.length.at.least(2);
  });
});

Best Practices

1. Test Organization

  • Use descriptive test names
  • Group related tests using describe blocks
  • Implement proper test isolation
  • Clean up test data after each test

2. Error Handling

  • Implement proper timeout handling
  • Use retry mechanisms for email checks
  • Add comprehensive error messages
  • Log relevant information for debugging

3. Performance

  • Use appropriate wait times
  • Implement efficient email polling
  • Cache test data when possible
  • Clean up resources after tests

Common Pitfalls

  • Race Conditions: Not waiting properly for emails
  • Test Isolation: Not cleaning up test data
  • Error Handling: Not implementing proper retries
  • Resource Management: Not releasing resources

Debugging Tips

  • Use Cypress's debug() command
  • Enable verbose logging
  • Implement proper error messages
  • Use Mail7's web interface for manual verification
  • Add screenshots for UI-related tests

Start Email Testing with Cypress

Implement robust email testing in your Cypress test suite with Mail7's testing infrastructure.