Introdução aos Testes End-to-End
Testes end-to-end (E2E) verificam sua aplicação como um usuário real faria: abrindo o navegador, clicando em botões, preenchendo formulários e validando resultados. Diferente de testes unitários que isolam funções, E2E testa fluxos completos da aplicação. Playwright e Cypress são as ferramentas mais populares para isso em JavaScript, cada uma com suas vantagens estratégicas.
Playwright é mantido pelo Google, suporta múltiplos navegadores (Chrome, Firefox, Safari) e é extremamente rápido. Cypress oferece uma experiência visual superior com debugging interativo e é mais intuitivo para iniciantes. Escolher entre elas depende do seu projeto, mas ambas resolvem o mesmo problema com abordagens diferentes.
Primeiros Passos: Instalação e Configuração
Setup Playwright
Comece instalando Playwright e sua CLI:
npm install -D @playwright/test
npx playwright install
Crie seu primeiro teste em tests/exemplo.spec.ts:
import { test, expect } from '@playwright/test';
test('deve fazer login com sucesso', async ({ page }) => {
await page.goto('https://exemplo.com/login');
await page.fill('input[name="email"]', 'usuario@teste.com');
await page.fill('input[name="senha"]', '123456');
await page.click('button:has-text("Entrar")');
await expect(page).toHaveURL('https://exemplo.com/dashboard');
await expect(page.locator('h1')).toContainText('Bem-vindo');
});
Execute com npx playwright test.
Setup Cypress
Para Cypress, o processo é semelhante:
npm install -D cypress
npx cypress open
Crie seu teste em cypress/e2e/login.cy.js:
describe('Login', () => {
beforeEach(() => {
cy.visit('https://exemplo.com/login');
});
it('deve fazer login com sucesso', () => {
cy.get('input[name="email"]').type('usuario@teste.com');
cy.get('input[name="senha"]').type('123456');
cy.get('button').contains('Entrar').click();
cy.url().should('include', '/dashboard');
cy.get('h1').should('contain', 'Bem-vindo');
});
});
Estratégias de Escrita e Boas Práticas
Seletores Robustos
Use data-testid ao invés de classes CSS que podem mudar:
// ❌ Frágil
cy.get('.btn-primary.mt-3')
// ✅ Robusto
cy.get('[data-testid="login-button"]')
Atualize seu HTML: <button data-testid="login-button">Entrar</button>
Page Object Model
Organize testes complexos separando lógica de página em classes:
// pages/LoginPage.js
export class LoginPage {
constructor(page) {
this.page = page;
this.emailInput = page.locator('[data-testid="email"]');
this.senhaInput = page.locator('[data-testid="senha"]');
this.loginButton = page.locator('[data-testid="login-btn"]');
}
async login(email, senha) {
await this.emailInput.fill(email);
await this.senhaInput.fill(senha);
await this.loginButton.click();
}
}
// test.spec.js
import { LoginPage } from './pages/LoginPage';
test('login flow', async ({ page }) => {
const loginPage = new LoginPage(page);
await page.goto('https://exemplo.com/login');
await loginPage.login('user@teste.com', '123456');
await expect(page).toHaveURL(/.*dashboard/);
});
Esperas Inteligentes
Evite sleep(). Use esperas explícitas que observam elementos:
// Playwright - espera por elemento estar visível
await page.waitForSelector('[data-testid="success-message"]', { timeout: 5000 });
await expect(page.locator('[data-testid="success-message"]')).toBeVisible();
// Cypress - espera automática por padrão
cy.get('[data-testid="success-message"]').should('be.visible');
Testes Avançados e CI/CD
Testando APIs e Mocks
Intercepte requisições para acelerar testes:
// Playwright
test('lista produtos sem chamar API real', async ({ page }) => {
await page.route('**/api/produtos', route => {
route.abort('blockedbyclient');
});
await page.goto('https://exemplo.com/produtos');
await expect(page.locator('p')).toContainText('Erro ao carregar produtos');
});
// Cypress
it('usa dados mockados', () => {
cy.intercept('GET', '/api/usuarios', {
statusCode: 200,
body: [{ id: 1, nome: 'João' }]
}).as('getUsers');
cy.visit('/usuarios');
cy.wait('@getUsers');
cy.contains('João').should('be.visible');
});
Integração com CI/CD
Configure no seu playwright.config.ts:
export default defineConfig({
testDir: './tests',
webServer: {
command: 'npm run dev',
url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI,
},
use: {
baseURL: 'http://localhost:3000',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
});
Configure no GitHub Actions (.github/workflows/e2e.yml):
name: E2E Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm ci && npx playwright install
- run: npm run test:e2e
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
Conclusão
Três pilares para dominar E2E: (1) Escolha a ferramenta conforme seu contexto — Playwright para velocidade e múltiplos navegadores, Cypress para experiência visual; (2) Use Page Object Model e data-testid para testes mantíveis que sobrevivem a mudanças CSS; (3) Integre ao seu pipeline CI/CD desde o início, capturando screenshots/vídeos de falhas.
A diferença entre um projeto robusto e frágil está na disciplina de escrita desde o primeiro teste. Comece simples, automatize fluxos críticos, e expanda gradualmente sua cobertura.