📚 Módulo 13: QA - Garantia de Qualidade com Testes E2E (Playwright) no Next.js e NestJS

Neste módulo final de Garantia de Qualidade (QA) da TecLoja 04, cobriremos testes ponta a ponta (End-to-End - E2E) utilizando o framework moderno Playwright.

Como a nossa TecLoja 04 adota uma arquitetura corporativa avançada baseada em Next.js (App Router) com renderização do lado do servidor (SSR), controle de rotas por Middleware, e autenticação com cookies protegidos HttpOnly (BFF), o Playwright é a ferramenta recomendada por sua alta velocidade de execução, suporte nativo a isolamento de contextos de navegadores e depuração profunda de Server Actions.


🗺️ 1. Arquitetura do Fluxo de Testes E2E com Playwright

O diagrama abaixo ilustra a esteira de validação controlando o fluxo de ponta a ponta desde a interface do usuário no Next.js até a persistência no banco corporativo:

flowchart TD
    %% Styling
    classDef pw fill:#2e8b57,stroke:#1e5e3a,stroke-width:2px,color:#fff;
    classDef browser fill:#2088ff,stroke:#005cc5,stroke-width:2px,color:#fff;
    classDef next fill:#000000,stroke:#333333,stroke-width:2px,color:#fff;
    classDef nest fill:#e0234e,stroke:#9f1239,stroke-width:2px,color:#fff;

    subgraph Playwright_Engine ["⚙️ Playwright Runner"]
        A[Playwright Spec Script]:::pw -->|Controlar via CDP / WebDriver| B[Navegador Chrome/Webkit Headless]:::browser
    end

    subgraph App_Server_Architecture ["💻 Infraestrutura Corporativa"]
        B -->|Acessar e Cliques| C[Next.js App Server - localhost:3000]:::next
        C -->|Autenticação BFF via HttpOnly Cookies| D[NestJS API Server - localhost:4000]:::nest
    end

⚙️ 2. Instalação e Setup do Playwright no Next.js

Acesse a pasta raiz do seu repositório frontend Next.js e execute a CLI interativa do Playwright para realizar a instalação de todas as dependências nativas e navegadores:

# Executar a instalação interativa recomendada
npm init playwright@latest

Durante o prompt de inicialização no console, responda da seguinte forma:

Após a finalização do setup, edite o arquivo de configuração playwright.config.ts criado na raiz do seu projeto Next.js para apontar para a porta local padrão da aplicação:

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: 'html',
  use: {
    baseURL: 'http://localhost:3000', // Porta padrão de desenvolvimento do Next.js
    trace: 'on-first-retry',
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
  ],
});

🧪 3. Escrevendo o Teste do Fluxo E2E (checkout_flow.spec.ts)

Nossos cenários validarão o comportamento do catálogo renderizado no servidor (SSR), o fluxo do carrinho com Zustand e o redirecionamento com base no cookie HttpOnly gerenciado pelo middleware do Next.js.

Crie o arquivo de testes em tests/checkout_flow.spec.ts:

import { test, expect } from '@playwright/test';

test.describe('Fluxo Comercial E2E - TecLoja 04', () => {

  test.beforeEach(async ({ page }) => {
    // Acessar a Home Page e garantir limpeza de cookies de autenticação
    await page.context().clearCookies();
    await page.goto('/');
  });

  test('Deve carregar produtos SSR, adicionar ao carrinho e redirecionar no checkout', async ({ page }) => {
    // 1. Confirmar se a página foi renderizada pelo servidor com sucesso
    await expect(page.locator('h1')).toContainText('TecLoja 04');
    
    // 2. Localizar o primeiro card de produto
    const primeiroProduto = page.locator('.produto-card').first();
    await expect(primeiroProduto).toBeVisible();

    // Guardar o nome do produto adicionado
    const nomeProduto = await primeiroProduto.locator('.produto-nome').innerText();

    // 3. Adicionar o produto ao carrinho (Zustand state trigger)
    await primeiroProduto.locator('button:has-text("Adicionar ao Carrinho")').click();

    // 4. Confirmar que a Navbar (Client Component) foi notificada do incremento do estado
    await expect(page.locator('.navbar-carrinho-count')).toContainText('1');

    // 5. Ir para o carrinho e confirmar presença do item correto
    await page.goto('/carrinho');
    await expect(page.locator('.carrinho-list')).toContainText(nomeProduto);

    // 6. Tentar finalizar compra (Middleware deve barrar se não houver cookie HttpOnly)
    await page.click('button:has-text("Finalizar Compra")');

    // 7. Esperado: O middleware intercepta a requisição e redireciona para a tela de autenticação
    await expect(page).toHaveURL(/\/login/);
  });

  test('Deve realizar o login seguro via BFF e finalizar a transação', async ({ page }) => {
    // 1. Ir para a tela de login
    await page.goto('/login');

    // 2. Preencher formulário de credenciais
    await page.fill('input[name="email"]', 'maria@gmail.com');
    await page.fill('input[name="password"]', '123456');
    await page.click('button[type="submit"]');

    // 3. Confirmar que o login foi bem sucedido (Cookie HttpOnly configurado em background)
    await expect(page).toHaveURL('/');
    await expect(page.locator('.navbar-user-section')).toContainText('Maria');

    // 4. Adicionar item e fazer o checkout completo
    await page.locator('.produto-card').first().locator('button:has-text("Adicionar ao Carrinho")').click();
    await page.goto('/carrinho');
    
    // 5. Finalizar pedido (Agora com permissão)
    await page.click('button:has-text("Finalizar Compra")');

    // 6. Validar a mensagem de sucesso pós-processamento da transação pelo NestJS
    const containerSucesso = page.locator('.checkout-sucesso-aviso');
    await expect(containerSucesso).toBeVisible();
    await expect(containerSucesso).toContainText('Compra faturada com sucesso');
  });
});

🚀 4. Executando e Depurando os Testes

Você pode executar o Playwright em diferentes modos usando o terminal:

Modo Headless (Execução Rápida / CI)

Roda os testes em segundo plano e exibe o relatório no final:

npx playwright test

Modo UI (Interface Gráfica de Depuração)

O Playwright abre uma interface gráfica espetacular com time-travel debugging, onde você pode rever o DOM, as requisições de rede feitas pela API Next.js e logs em cada linha de código do teste:

npx playwright test --ui

Verificando Relatório HTML

Caso ocorram erros de asserção, abra o relatório rico em HTML gerado localmente:

npx playwright show-report

✅ Pré-Requisitos deste Módulo

Antes de iniciar os testes E2E, confirme se:


🤔 Por que fizemos assim?


🔍 Checkpoint

  1. Relatório Verde: Execute npx playwright test e verifique se as execuções nos navegadores Chromium e Firefox passam sem falhas.
  2. Depuração com Trace Viewer: Rode npx playwright test --ui e clique em cada etapa do teste. Valide a requisição de checkout batendo no BFF do Next.js e confirmando o retorno HTTP 201.

⚠️ Erros Comuns

Erro Causa Solução
Target closed ou timeout na inicialização do teste O servidor Next.js ou API NestJS não estão de pé ou a URL base informada no arquivo config está incorreta. Certifique-se de iniciar as duas aplicações antes de rodar os testes e confirme se a porta de escuta do Next.js coincide com o baseURL do Playwright.
Erro de hidratação (Hydration error) ao carregar a página nos testes O HTML renderizado pelo Next.js no servidor difere do primeiro estado que o React monta no navegador (comum com manipulações locais de Zustand ou datas). Verifique se as telas com carregamento local dinâmico usam hooks com tratamento para suspender a renderização até o cliente hidratar (com tratamento useEffect ou component dynamic import desativando SSR).
TargetPage.fill: Timeout 30000ms exceeded O Playwright não encontrou o seletor correspondente ao formulário de e-mail ou senha na tela de login. Certifique-se de que os atributos name ou classes CSS dos campos input no seu formulário Next.js condizem com as chaves declaradas no script do teste.

Voltar para o Sumário