Guia de teste do Playwright: testes E2E para aplicativos Next.js

Escreva testes ponta a ponta confiáveis ​​para aplicativos Next.js com Playwright. Guia completo que abrange configuração, objetos de página, testes de autenticação, regressão visual e integração de CI/CD.

E

ECOSIRE Research and Development Team

Equipe ECOSIRE

5 de março de 20266 min de leitura1.2k Palavras

Guia de teste do Playwright: testes E2E para aplicativos Next.js

Os testes de ponta a ponta detectam os bugs que os testes de unidade não detectam: fluxos de autenticação quebrados, falhas no envio de formulários, erros de navegação e problemas de renderização entre navegadores. O Playwright, criado pela Microsoft, tornou-se a principal estrutura de testes E2E com seu suporte a vários navegadores, recursos de espera automática e poderosas ferramentas de depuração.

Principais conclusões

  • Os testes do Playwright são executados no Chromium, Firefox e WebKit a partir de um único conjunto de testes
  • A espera automática elimina testes instáveis, aguardando que os elementos sejam acionáveis antes de interagir
  • O estado de autenticação pode ser compartilhado entre testes para uma execução mais rápida
  • A integração de CI com GitHub Actions fornece testes automatizados em cada solicitação pull

Configuração do projeto

Instalação

npm init playwright@latest

Isso instala o Playwright, cria um arquivo de configuração e baixa os binários do navegador. Para projetos Next.js, configure o servidor web para iniciar automaticamente:

// playwright.config.ts
import { defineConfig } from "@playwright/test";

export default defineConfig({
  testDir: "./e2e",
  timeout: 30000,
  retries: process.env.CI ? 2 : 0,
  use: {
    baseURL: "http://localhost:3000",
    screenshot: "only-on-failure",
    trace: "on-first-retry",
  },
  webServer: {
    command: "npm run dev",
    port: 3000,
    reuseExistingServer: !process.env.CI,
  },
  projects: [
    { name: "chromium", use: { browserName: "chromium" } },
    { name: "firefox", use: { browserName: "firefox" } },
    { name: "webkit", use: { browserName: "webkit" } },
  ],
});

Escrevendo seu primeiro teste

Teste Básico de Navegação

// e2e/navigation.spec.ts
import { test, expect } from "@playwright/test";

test("home page loads and displays title", async ({ page }) => {
  await page.goto("/");
  await expect(page).toHaveTitle(/ECOSIRE/);
  await expect(page.getByRole("heading", { level: 1 })).toBeVisible();
});

test("navigation to services page", async ({ page }) => {
  await page.goto("/");
  await page.getByRole("link", { name: "Services" }).click();
  await expect(page).toHaveURL(/services/);
  await expect(page.getByRole("heading", { name: /Services/ })).toBeVisible();
});

Teste de envio de formulário

test("contact form submission", async ({ page }) => {
  await page.goto("/contact");

  await page.getByLabel("Name").fill("Test User");
  await page.getByLabel("Email").fill("[email protected]");
  await page.getByLabel("Message").fill("This is a test message");
  await page.getByRole("button", { name: "Send" }).click();

  await expect(page.getByText("Message sent")).toBeVisible();
});

Padrão de objeto de página

Encapsule interações de página em objetos de página para manutenção:

// e2e/pages/login.page.ts
import { Page, expect } from "@playwright/test";

export class LoginPage {
  constructor(private page: Page) {}

  async goto() {
    await this.page.goto("/login");
  }

  async login(email: string, password: string) {
    await this.page.getByLabel("Email").fill(email);
    await this.page.getByLabel("Password").fill(password);
    await this.page.getByRole("button", { name: "Sign In" }).click();
  }

  async expectLoggedIn() {
    await expect(this.page).toHaveURL(/dashboard/);
  }

  async expectError(message: string) {
    await expect(this.page.getByText(message)).toBeVisible();
  }
}

Use em testes:

test("successful login", async ({ page }) => {
  const loginPage = new LoginPage(page);
  await loginPage.goto();
  await loginPage.login("[email protected]", "password123");
  await loginPage.expectLoggedIn();
});

Teste de autenticação

Estado de autenticação compartilhada

Evite fazer login antes de cada teste salvando o estado de autenticação:

// e2e/auth.setup.ts
import { test as setup } from "@playwright/test";

setup("authenticate", async ({ page }) => {
  await page.goto("/login");
  await page.getByLabel("Email").fill("[email protected]");
  await page.getByLabel("Password").fill("admin-password");
  await page.getByRole("button", { name: "Sign In" }).click();
  await page.waitForURL("/dashboard");

  // Save authentication state
  await page.context().storageState({ path: ".auth/user.json" });
});

Configure em playwright.config.ts:

projects: [
  { name: "setup", testMatch: /auth\.setup\.ts/ },
  {
    name: "authenticated",
    dependencies: ["setup"],
    use: { storageState: ".auth/user.json" },
  },
],

Teste de regressão visual

Capture alterações visuais não intencionais com comparações de capturas de tela:

test("home page visual regression", async ({ page }) => {
  await page.goto("/");
  await expect(page).toHaveScreenshot("home-page.png", {
    maxDiffPixelRatio: 0.01,
  });
});

Na primeira execução, o Playwright salva capturas de tela básicas. As execuções subsequentes são comparadas com as linhas de base e falham se as diferenças excederem o limite. Atualize as linhas de base com --update-snapshots quando as alterações forem intencionais.


Simulação de API

Respostas simuladas da API para testes determinísticos:

test("displays products from API", async ({ page }) => {
  await page.route("/api/products", async (route) => {
    await route.fulfill({
      status: 200,
      contentType: "application/json",
      body: JSON.stringify([
        { id: 1, name: "Product A", price: 29.99 },
        { id: 2, name: "Product B", price: 49.99 },
      ]),
    });
  });

  await page.goto("/products");
  await expect(page.getByText("Product A")).toBeVisible();
  await expect(page.getByText("Product B")).toBeVisible();
});

Integração CI/CD

Ações do GitHub

name: E2E Tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test
      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: playwright-report
          path: playwright-report/

Os relatórios de teste com falha são carregados como artefatos para depuração, incluindo capturas de tela, rastreamentos e gravações de vídeo.


Ferramentas de depuração

  • Playwright Inspector: Execute testes com sinalizador --debug para execução passo a passo
  • Trace Viewer: abra rastreamentos para ver cada ação, solicitação de rede e instantâneo do DOM
  • Codegen: execute npx playwright codegen para registrar interações do navegador e gerar código de teste
  • Extensão do VS Code: execute e depure testes diretamente do VS Code com elementos clique para localizar

Melhores práticas

  1. Use seletores baseados em função: prefira getByRole, getByLabel, getByText em vez de seletores CSS
  2. Evite esperas codificadas: confie na espera automática em vez de page.waitForTimeout()
  3. Testes isolados: cada teste deve ser independente e não depender de outros testes
  4. Teste fluxos de usuários, não implementação: concentre-se no que os usuários fazem, não em como o código funciona
  5. Mantenha os testes rápidos: use atalhos de API para configuração (crie dados de teste via API, não UI)
  6. Executar em CI: cada solicitação pull deve passar nos testes E2E antes da mesclagem

Perguntas frequentes

P: Como o Playwright se compara ao Cypress?

O Playwright oferece suporte nativo a vários navegadores (Chromium, Firefox, WebKit), enquanto o Cypress visa principalmente o Chromium. O Playwright é mais rápido para execução paralela e lida com várias guias/janelas. Cypress tem uma curva de aprendizado um pouco mais fácil e uma depuração de viagem no tempo mais forte.

P: Como lidamos com testes instáveis?

A espera automática do dramaturgo elimina a maior parte da instabilidade. Para os problemas restantes: use asserções web-first (espera o localizador), evite testar o comportamento dependente de tempo e configure novas tentativas no CI. Os relatórios de rastreamento ajudam a identificar a causa raiz das falhas intermitentes.

P: Devemos testar todas as páginas?

Concentre-se em fluxos críticos de usuários: autenticação, fluxos de trabalho principais de negócios, envios de formulários e fluxos de pagamento. Nem todas as páginas precisam de testes E2E – use testes de unidade e integração para cobertura em nível de componente.

P: Quanto tempo devem durar os testes E2E?

Os testes individuais devem ser concluídos em menos de 30 segundos. Um conjunto completo para um aplicativo de médio porte (50 a 100 testes) deve ser executado em menos de 10 minutos com execução paralela.


O que vem a seguir

O teste E2E com Playwright oferece confiança de que seu aplicativo funciona corretamente do ponto de vista do usuário. Comece com fluxos críticos e expanda a cobertura à medida que sua aplicação cresce.

Entre em contato com a ECOSIRE para obter ajuda na automação de testes ou explore nossos serviços de implementação Odoo para implantação de ERP com qualidade garantida.


Publicado pela ECOSIRE – ajudando empresas a escalar com soluções de software empresarial.

E

Escrito por

ECOSIRE Research and Development Team

Construindo produtos digitais de nível empresarial na ECOSIRE. Compartilhando insights sobre integrações Odoo, automação de e-commerce e soluções de negócios com IA.

Converse no WhatsApp