emailr_
Tous les articles
usecase·10 min

Tests d’e-mails en CI/CD : modèles d’automatisation

testingcicdautomation

Les tests d’e-mails automatisés détectent les problèmes avant qu’ils n’atteignent la production. Voici comment intégrer les tests d’e-mails dans votre pipeline CI/CD.

Que tester

  • Syntaxe et rendu des templates
  • Substitution des variables
  • Validation des liens
  • Vérification du score de spam
  • Conformité aux règles d’accessibilité
  • Rendu multi-clients

Validation des templates

Vérification de la syntaxe

// In your test suite
import { validateTemplate } from './email-utils';

describe('Email Templates', () => {
  const templates = glob.sync('templates/**/*.html');
  
  templates.forEach(templatePath => {
    it(`${templatePath} should have valid syntax`, () => {
      const content = fs.readFileSync(templatePath, 'utf-8');
      const result = validateTemplate(content);
      
      expect(result.valid).toBe(true);
      expect(result.errors).toEqual([]);
    });
  });
});

function validateTemplate(html: string): ValidationResult {
  const errors: string[] = [];
  
  // Check for unclosed tags
  const unclosedTags = findUnclosedTags(html);
  if (unclosedTags.length > 0) {
    errors.push(`Unclosed tags: ${unclosedTags.join(', ')}`);
  }
  
  // Check for invalid variables
  const invalidVars = findInvalidVariables(html);
  if (invalidVars.length > 0) {
    errors.push(`Invalid variables: ${invalidVars.join(', ')}`);
  }
  
  return { valid: errors.length === 0, errors };
}

Validation des variables

it('should have all required variables', () => {
  const template = loadTemplate('order-confirmation');
  const requiredVars = ['orderNumber', 'items', 'total', 'customerName'];
  
  const templateVars = extractVariables(template);
  
  for (const required of requiredVars) {
    expect(templateVars).toContain(required);
  }
});

Tests de rendu

Tests de snapshot

import { render } from './email-renderer';

describe('Email Rendering', () => {
  it('renders order confirmation correctly', async () => {
    const html = await render('order-confirmation', {
      orderNumber: 'ORD-123',
      customerName: 'Test User',
      items: [{ name: 'Widget', quantity: 2, price: 29.99 }],
      total: 59.98
    });
    
    expect(html).toMatchSnapshot();
  });
});

Tests de régression visuelle

import { takeScreenshot, compareImages } from './visual-testing';

it('should match visual baseline', async () => {
  const html = await render('welcome', testData);
  const screenshot = await takeScreenshot(html);
  
  const diff = await compareImages(screenshot, 'welcome-baseline.png');
  
  expect(diff.percentage).toBeLessThan(0.1); // 0.1% tolerance
});

Validation des liens

Vérifier tous les liens

import { extractLinks, validateUrl } from './link-utils';

describe('Email Links', () => {
  const templates = glob.sync('templates/**/*.html');
  
  templates.forEach(templatePath => {
    it(`${templatePath} should have valid links`, async () => {
      const html = fs.readFileSync(templatePath, 'utf-8');
      const links = extractLinks(html);
      
      for (const link of links) {
        // Skip template variables
        if (link.includes('{{')) continue;
        
        const isValid = await validateUrl(link);
        expect(isValid).toBe(true);
      }
    });
  });
});

Vérification du lien de désinscription

it('marketing emails should have unsubscribe link', () => {
  const marketingTemplates = glob.sync('templates/marketing/**/*.html');
  
  marketingTemplates.forEach(template => {
    const html = fs.readFileSync(template, 'utf-8');
    
    expect(html).toMatch(/unsubscribe/i);
    expect(html).toContain('List-Unsubscribe');
  });
});

Vérification du score de spam

Intégration avec SpamAssassin

import { checkSpamScore } from './spam-checker';

describe('Spam Score', () => {
  it('should have acceptable spam score', async () => {
    const html = await render('newsletter', testData);
    
    const result = await checkSpamScore({
      from: '[email protected]',
      subject: 'Your weekly update',
      html
    });
    
    expect(result.score).toBeLessThan(5.0);
    expect(result.flags).not.toContain('MISSING_HEADERS');
  });
});

Tests d’accessibilité

import { checkAccessibility } from './a11y-checker';

describe('Email Accessibility', () => {
  it('should pass accessibility checks', async () => {
    const html = await render('welcome', testData);
    
    const results = await checkAccessibility(html);
    
    expect(results.violations).toHaveLength(0);
  });
  
  it('should have alt text on images', () => {
    const html = fs.readFileSync('templates/welcome.html', 'utf-8');
    const images = html.match(/<img[^>]*>/g) || [];
    
    images.forEach(img => {
      expect(img).toMatch(/alt=["'][^"']+["']/);
    });
  });
});

Intégration au pipeline CI/CD

Exemple GitHub Actions

name: Email Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Validate templates
        run: npm run test:templates
      
      - name: Check spam scores
        run: npm run test:spam
      
      - name: Visual regression tests
        run: npm run test:visual
      
      - name: Upload visual diffs
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: visual-diffs
          path: test-results/visual-diffs/

Contrôles pré-déploiement

Tests en environnement de staging

// Send test emails to staging inbox
async function testInStaging() {
  const testEmails = [
    { template: 'welcome', data: welcomeTestData },
    { template: 'order-confirmation', data: orderTestData },
    { template: 'password-reset', data: resetTestData }
  ];
  
  for (const { template, data } of testEmails) {
    await sendEmail({
      to: '[email protected]',
      template,
      data,
      tags: ['staging-test', `template:${template}`]
    });
  }
  
  // Verify delivery
  await sleep(5000);
  const delivered = await checkStagingInbox();
  
  expect(delivered).toHaveLength(testEmails.length);
}

Bonnes pratiques

  1. Testez tôt - Validez les templates à chaque commit
  2. Gérez les snapshots avec précaution - Mettez à jour les snapshots intentionnellement
  3. Vérifiez les scores de spam - Détectez les problèmes avant qu’ils n’affectent la délivrabilité
  4. Validez les liens - Les liens cassés dégradent l’expérience utilisateur
  5. Testez l’accessibilité - Assurez-vous que les e-mails fonctionnent pour tout le monde
  6. Utilisez le staging - Des tests de livraison réels avant la production

Les tests d’e-mails automatisés détectent les problèmes avant que les utilisateurs ne les voient. Investissez dans votre suite de tests et déployez en toute confiance.

e_

Écrit par l'équipe emailr

Nous construisons l'infrastructure email pour les développeurs

Prêt à commencer à envoyer ?

Obtenez votre clé API et envoyez votre premier email en moins de 5 minutes. Aucune carte de crédit requise.