Testes automatizados de email detectam problemas antes de chegarem à produção. Veja como integrar testes de email ao seu pipeline de CI/CD.
O que testar
- —Sintaxe e renderização de templates
- —Substituição de variáveis
- —Validação de links
- —Verificação de pontuação de spam
- —Conformidade de acessibilidade
- —Renderização em diferentes clientes de email
Validação de templates
Verificação de sintaxe
// 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 };
}
Validação de variáveis
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);
}
});
Testes de renderização
Testes 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();
});
});
Testes de regressão visual
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
});
Validação de links
Verificar todos os links
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);
}
});
});
});
Verificação do link de cancelar inscrição
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');
});
});
Verificação de pontuação de spam
Integração com 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');
});
});
Testes de acessibilidade
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=["'][^"']+["']/);
});
});
});
Integração ao pipeline de CI/CD
Exemplo de 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/
Verificações pré-implantação
Testes em ambiente 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);
}
Boas práticas
- —Teste cedo - Valide os templates a cada commit
- —Snapshots com cuidado - Atualize os snapshots intencionalmente
- —Verifique a pontuação de spam - Detecte problemas antes que afetem a entregabilidade
- —Valide links - Links quebrados prejudicam a experiência do usuário
- —Teste a acessibilidade - Garanta que os emails funcionem para todos
- —Use staging - Testes de entrega reais antes da produção
Testes automatizados de email detectam problemas antes que os usuários os vejam. Invista na sua suíte de testes e faça deploy com confiança.