O fixture request do Playwright faz chamadas HTTP sem abrir um navegador, completando em 50 a 200 milissegundos versus 3 a 5 segundos para um teste de UI. Ele está disponível ao lado de page em qualquer teste Playwright, o que permite um padrão híbrido. Criar dados de teste via API, verificar pela UI, e limpar via API, tudo em um único arquivo de teste sem nenhuma ferramenta extra.

Por que testes de API pertencem à sua suite Playwright

O argumento para testes de API não é sobre substituir testes de UI. É sobre testar as coisas certas no nível certo.

Um teste de UI que cria um item de viagem passa pelo navegador, renderiza o formulário, preenche os inputs, clica em enviar, aguarda a página atualizar, depois verifica o resultado. Leva 3 a 5 segundos e pode falhar por uma dúzia de razões não relacionadas à feature real: uma animação lenta, um localizador alterado, uma requisição de rede frágil.

Um teste de API que cria um item de viagem envia uma requisição HTTP e verifica a resposta. Leva 50 a 200 milissegundos e falha apenas quando a própria API está quebrada.

Use testes de API para: validação de dados, regras de autenticação, respostas de erro, lógica de negócio no backend. Use testes de UI para: fluxos do usuário, renderização visual, interações com o frontend. Ambos têm seu lugar. O erro é usar apenas testes de UI quando o bug está na API.

O fixture request

O Playwright expõe um APIRequestContext através do fixture request. Ele está disponível em qualquer teste da mesma forma que page:

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

test('GET /api/items retorna uma lista', async ({ request }) => {
  const response = await request.get('https://lab.becomeqa.com/api/items');

  expect(response.status()).toBe(200);

  const items = await response.json();
  expect(items.length).toBeGreaterThan(0);
});

Nenhum navegador abre. Nenhuma página carrega. Apenas uma requisição HTTP e uma resposta. O fixture request trata cookies, headers e configuração de base URL automaticamente.

Requisições GET e validação de resposta

O padrão de teste de API mais comum: chamar um endpoint, verificar o status, verificar a estrutura dos dados.

test('GET /api/items retorna estrutura correta', async ({ request }) => {
  const response = await request.get('https://lab.becomeqa.com/api/items');

  // Verificar status HTTP
  expect(response.status()).toBe(200);
  expect(response.ok()).toBeTruthy(); // true para status codes 2xx

  // Parsear o corpo da resposta
  const items = await response.json();

  // Verificar o array
  expect(Array.isArray(items)).toBe(true);
  expect(items.length).toBeGreaterThan(0);

  // Verificar a estrutura do primeiro item
  const firstItem = items[0];
  expect(firstItem).toHaveProperty('id');
  expect(firstItem).toHaveProperty('destination');
  expect(firstItem).toHaveProperty('status');
});

response.ok() é um atalho para status >= 200 && status < 300. Use quando você só quer saber se a requisição foi bem-sucedida.

Para verificar headers da resposta:

const contentType = response.headers()['content-type'];
expect(contentType).toContain('application/json');

Requisições POST

Requisições POST enviam dados para criar um recurso. Passe o corpo como JSON:

test('POST /api/items cria um novo item', async ({ request }) => {
  const response = await request.post('https://lab.becomeqa.com/api/items', {
    data: {
      destination: 'Tokyo',
      status: 'planned',
      notes: 'Temporada de cerejeiras'
    }
  });

  expect(response.status()).toBe(201);

  const created = await response.json();
  expect(created).toHaveProperty('id');
  expect(created.destination).toBe('Tokyo');
  expect(created.status).toBe('planned');
});

A opção data serializa automaticamente para JSON e define o header Content-Type: application/json.

Para requisições form-encoded use form em vez de data:

const response = await request.post('/api/login', {
  form: {
    username: 'admin@becomeqa.com',
    password: 'testpass123'
  }
});

Autenticação

A maioria das APIs reais exige autenticação. Dois padrões são comuns.

Bearer token no header:

test('GET autenticado retorna dados do usuário', async ({ request }) => {
  // Primeiro, obter um token
  const loginResponse = await request.post('https://lab.becomeqa.com/api/auth/login', {
    data: {
      username: 'admin@becomeqa.com',
      password: 'testpass123'
    }
  });

  const { token } = await loginResponse.json();

  // Usar o token nas requisições subsequentes
  const response = await request.get('https://lab.becomeqa.com/api/items', {
    headers: {
      'Authorization': `Bearer ${token}`
    }
  });

  expect(response.status()).toBe(200);
});

Auth baseada em cookie via login pela UI:

Se seu app usa cookies para auth, você pode fazer login pelo navegador e reutilizar a sessão para chamadas de API. O objeto page.request compartilha cookies com o contexto do navegador:

test('chamada de API com sessão do navegador', async ({ page, request }) => {
  // Login pela UI
  await page.goto('https://lab.becomeqa.com');
  await page.getByRole('button', { name: 'Login' }).click();
  await page.getByLabel('Username').fill('admin@becomeqa.com');
  await page.getByLabel('Password').fill('testpass123');
  await page.getByRole('button', { name: 'Submit' }).click();

  // Usar page.request: ele carrega o cookie de auth
  const response = await page.request.get('https://lab.becomeqa.com/api/items');
  expect(response.status()).toBe(200);
});

Observe a diferença: request (o fixture) é um contexto independente sem cookies do navegador. page.request compartilha cookies com a sessão atual do navegador.

Testando respostas de erro

APIs devem retornar erros significativos. Teste-os explicitamente.

test('GET /api/items/:id retorna 404 para id desconhecido', async ({ request }) => {
  const response = await request.get('https://lab.becomeqa.com/api/items/id-inexistente-99999');

  expect(response.status()).toBe(404);

  const body = await response.json();
  expect(body).toHaveProperty('error');
});

test('POST /api/items retorna 400 para campos obrigatórios faltando', async ({ request }) => {
  const response = await request.post('https://lab.becomeqa.com/api/items', {
    data: {
      // campo 'destination' obrigatório faltando
      status: 'planned'
    }
  });

  expect(response.status()).toBe(400);
});

test('endpoint protegido retorna 401 sem auth', async ({ request }) => {
  const response = await request.get('https://lab.becomeqa.com/api/items');
  // sem header Authorization
  expect(response.status()).toBe(401);
});

Esses testes verificam que a API lida corretamente com entradas ruins, não apenas o caminho principal.

Combinando testes de API e UI

Um dos padrões mais poderosos: usar a API para configurar dados de teste, depois verificar pela UI. Ou o inverso: interagir pela UI, verificar pela API.

Setup via API, verificação pela UI:

test('item criado aparece na tabela da UI', async ({ page, request }) => {
  // Criar item via API: rápido e confiável
  const createResponse = await request.post('https://lab.becomeqa.com/api/items', {
    data: { destination: 'Lisboa', status: 'planned' }
  });
  const { id } = await createResponse.json();

  // Verificar se aparece na UI
  await page.goto('https://lab.becomeqa.com');
  // ... passos de login ...
  await expect(page.getByText('Lisboa')).toBeVisible();

  // Limpeza via API após o teste
  await request.delete(`https://lab.becomeqa.com/api/items/${id}`);
});

Esse teste é mais rápido e mais confiável. O setup pela UI é a fonte mais comum de flakiness em testes que não estão realmente testando a UI.

Ação pela UI, verificação via API:

test('deletar item pela UI remove da API', async ({ page, request }) => {
  // Setup via API
  const createResponse = await request.post('https://lab.becomeqa.com/api/items', {
    data: { destination: 'Oslo', status: 'planned' }
  });
  const { id } = await createResponse.json();

  // Ação pela UI
  await page.goto('https://lab.becomeqa.com');
  // ... login, encontrar item, clicar em deletar ...

  // Verificar via API
  const checkResponse = await request.get(`https://lab.becomeqa.com/api/items/${id}`);
  expect(checkResponse.status()).toBe(404);
});

Configure uma base URL para testes de API

Repetir a URL completa em cada teste é ruído. Defina baseURL no playwright.config.ts:

export default defineConfig({
  use: {
    baseURL: 'https://lab.becomeqa.com',
  },
});

Agora você pode usar caminhos relativos:

const response = await request.get('/api/items');
const response = await request.post('/api/items', { data: { ... } });

Para projetos com base URLs separadas para UI e API, crie um fixture customizado que configura o contexto de API separadamente.

Adicione extraHTTPHeaders à configuração se sua API exige um header comum em cada requisição (como uma API key ou um header customizado X-App-Version). Defina uma vez na configuração em vez de em cada teste.

export default defineConfig({
  use: {
    baseURL: 'https://lab.becomeqa.com',
    extraHTTPHeaders: {
      'X-Api-Key': process.env.API_KEY || '',
    },
  },
});

Organize os testes de API separadamente

Mantenha os testes de API em sua própria pasta para poder executá-los independentemente dos testes de UI:

tests/
  ui/
    login.spec.ts
    items.spec.ts
  api/
    items-api.spec.ts
    auth-api.spec.ts

# Rodar apenas testes de API: rápido, sem navegador
npx playwright test tests/api/

# Rodar apenas testes de UI
npx playwright test tests/ui/

Os testes de API rodam significativamente mais rápido que os testes de UI. Executá-los separadamente no CI permite feedback rápido sobre bugs de backend antes que a suite de UI mais lenta termine.

FAQ

Ainda preciso do Postman se uso o Playwright para testes de API?

O Postman é útil para exploração manual de API: descobrir quais endpoints existem, quais parâmetros aceitam, como são as respostas. Quando você já sabe o que testar, escreva a versão automatizada no Playwright. Ambos têm seu lugar.

Todo endpoint de API precisa ter um teste?

Foque nos endpoints que importam: autenticação, operações de dados principais, e qualquer endpoint com lógica de validação complexa. Uma API CRUD para itens de viagem precisa de testes para criar, ler, atualizar, deletar, e pelo menos os casos de erro principais (404, 400, 401). Não toda combinação de inputs.

Como testo uploads de arquivo via API?

Use a opção multipart:

const response = await request.post('/api/upload', {
  multipart: {
    file: {
      name: 'test.pdf',
      mimeType: 'application/pdf',
      buffer: Buffer.from('conteúdo fake do pdf'),
    }
  }
});

Posso usar o fixture request sem uma page?

Sim. Testes que usam apenas request e não page rodam sem abrir um navegador. São testes HTTP puros e rodam tão rápido quanto qualquer outro cliente HTTP.

→ Veja também: Testes de API 101: Tudo que Todo Engenheiro QA Precisa Saber em 2026 | Testes de API com o APIRequestContext do Playwright (Sem Postman) | Autenticação em Testes de API: Chaves API, Tokens Bearer, OAuth2, JWT | Testes de API Avançados com Playwright: Padrões para Projetos Reais