DEV Community

Cover image for Cypress Testes de API: Como Testar APIs com cy.request()
Lucas
Lucas

Posted on • Originally published at apidog.com

Cypress Testes de API: Como Testar APIs com cy.request()

Você já usa Cypress para testes end-to-end. Para validar uma API diretamente, você não precisa abrir a UI: use cy.request() para enviar requisições HTTP reais, verificar status codes e fazer asserções no corpo JSON. O comando roda no processo Node do Cypress, fora do navegador, e funciona bem para testar endpoints isolados ou preparar estado antes de um teste de interface.

Experimente o Apidog hoje

Neste guia, você verá como testar APIs com Cypress na prática: uso básico de cy.request(), asserções em respostas, encadeamento de chamadas com token de autenticação e stubbing de tráfego do navegador com cy.intercept(). Também verá quando o Cypress é suficiente e quando uma ferramenta nativa de API faz mais sentido.

Por que testar APIs com Cypress

Grande parte do que você valida na UI depende de uma API:

  • /login retorna um token.
  • /users retorna uma lista no formato esperado.
  • POST /orders cria um registro.
  • Uma resposta 500 exibe uma mensagem de erro na tela.

Testar esses endpoints diretamente ajuda em dois cenários:

  1. Verificações mais rápidas: não há renderização, seleção de elementos ou espera por componentes da UI.
  2. Setup de dados para testes e2e: em vez de clicar em vários formulários para criar dados, você envia requisições HTTP e começa o teste já no estado desejado.

Se o Cypress já está na sua stack, você pode adicionar testes de API nos mesmos arquivos de spec, com as mesmas asserções expect e no mesmo pipeline de CI.

Fundamentos do cy.request()

cy.request() envia uma requisição HTTP e retorna a resposta. Como ele roda no processo Node do Cypress, não fica sujeito a CORS ou à política de same-origin do navegador.

Formas comuns de uso:

cy.request(url)
cy.request(url, body)
cy.request(method, url)
cy.request(method, url, body)
cy.request(options)
Enter fullscreen mode Exit fullscreen mode

A chamada mais simples usa GET por padrão:

cy.request('https://jsonplaceholder.typicode.com/users')
Enter fullscreen mode Exit fullscreen mode

Para controlar método, headers, query params e payload, prefira o objeto de opções:

cy.request({
  method: 'POST',
  url: 'https://jsonplaceholder.typicode.com/posts',
  headers: {
    'Content-Type': 'application/json'
  },
  body: {
    title: 'API test',
    body: 'created from Cypress',
    userId: 1
  }
})
Enter fullscreen mode Exit fullscreen mode

Opções úteis:

Opção Uso
method Verbo HTTP: GET, POST, PUT, PATCH, DELETE etc. O padrão é GET.
url Endpoint da API.
body Payload da requisição. Objetos são serializados como JSON.
headers Cabeçalhos da requisição.
auth Credenciais para autenticação HTTP Basic.
qs Query string como objeto.
failOnStatusCode Use false para testar respostas 4xx ou 5xx sem falhar automaticamente.

Exemplo com query string:

cy.request({
  method: 'GET',
  url: 'https://jsonplaceholder.typicode.com/posts',
  qs: {
    userId: 1
  }
}).then((response) => {
  expect(response.status).to.eq(200)
  expect(response.body).to.be.an('array')
})
Enter fullscreen mode Exit fullscreen mode

Para testes negativos, desative failOnStatusCode. Por padrão, o Cypress falha o teste quando a resposta não é 2xx ou 3xx.

cy.request({
  method: 'GET',
  url: 'https://jsonplaceholder.typicode.com/users/99999',
  failOnStatusCode: false
}).then((response) => {
  expect(response.status).to.eq(404)
})
Enter fullscreen mode Exit fullscreen mode

Fazendo asserções no status e no corpo

cy.request() retorna um objeto de resposta. Encadeie .then() para acessar os dados.

Propriedades mais usadas:

  • status: código HTTP.
  • body: corpo da resposta. Quando o Content-Type é JSON, o Cypress converte para objeto JavaScript.
  • headers: headers da resposta.
  • duration: tempo da requisição em milissegundos.

Exemplo completo:

describe('Users API', () => {
  it('returns a list of users', () => {
    cy.request('https://jsonplaceholder.typicode.com/users').then((response) => {
      expect(response.status).to.eq(200)
      expect(response.body).to.be.an('array')
      expect(response.body).to.have.length(10)
      expect(response.body[0]).to.have.property('email')
    })
  })
})
Enter fullscreen mode Exit fullscreen mode

Como response.body já é um objeto JavaScript, você pode usar Chai normalmente:

cy.request('https://jsonplaceholder.typicode.com/users/1').then((response) => {
  expect(response.status).to.eq(200)

  expect(response.body).to.include({
    id: 1,
    username: 'Bret'
  })

  expect(response.body).to.have.nested.property('address.city')
  expect(response.body.email).to.match(/@/)
})
Enter fullscreen mode Exit fullscreen mode

Também é comum validar headers:

cy.request('https://jsonplaceholder.typicode.com/users').then((response) => {
  expect(response.headers['content-type']).to.include('application/json')
})
Enter fullscreen mode Exit fullscreen mode

Para estruturar melhor esse tipo de validação, veja também o guia sobre asserções de API e as melhores práticas de teste de API.

Encadeando requisições e reutilizando um token de autenticação

APIs reais geralmente exigem autenticação. O fluxo típico é:

  1. Fazer login.
  2. Ler o token da resposta.
  3. Enviar o token nas próximas requisições.

Com cy.request(), esse encadeamento fica direto:

describe('Authenticated API flow', () => {
  it('logs in and fetches a protected resource', () => {
    cy.request({
      method: 'POST',
      url: 'https://api.example.com/login',
      body: {
        email: 'user@example.com',
        password: 'secret'
      }
    }).then((loginResponse) => {
      expect(loginResponse.status).to.eq(200)

      const token = loginResponse.body.token

      cy.request({
        method: 'GET',
        url: 'https://api.example.com/profile',
        headers: {
          Authorization: `Bearer ${token}`
        }
      }).then((profileResponse) => {
        expect(profileResponse.status).to.eq(200)
        expect(profileResponse.body).to.have.property('email', 'user@example.com')
      })
    })
  })
})
Enter fullscreen mode Exit fullscreen mode

Se vários testes precisam do mesmo token, mova o login para um beforeEach:

describe('Protected API', () => {
  beforeEach(() => {
    cy.request({
      method: 'POST',
      url: 'https://api.example.com/login',
      body: {
        email: 'user@example.com',
        password: 'secret'
      }
    }).then((response) => {
      Cypress.env('authToken', response.body.token)
    })
  })

  it('gets the current user', () => {
    cy.request({
      method: 'GET',
      url: 'https://api.example.com/profile',
      headers: {
        Authorization: `Bearer ${Cypress.env('authToken')}`
      }
    }).then((response) => {
      expect(response.status).to.eq(200)
    })
  })
})
Enter fullscreen mode Exit fullscreen mode

Esse padrão de login e reutilização de dados é comum em fluxos de teste de integração de API, onde uma chamada alimenta a próxima.

Usando cy.request() para preparar estado antes da UI

Um dos usos mais práticos de cy.request() é reduzir setup via interface.

Em vez de criar um usuário clicando por várias telas, crie via API e visite diretamente a página que você quer testar:

describe('User dashboard', () => {
  beforeEach(() => {
    cy.request({
      method: 'POST',
      url: 'https://api.example.com/test/users',
      body: {
        name: 'Ada Lovelace',
        email: 'ada@example.com'
      }
    }).then((response) => {
      expect(response.status).to.eq(201)
      Cypress.env('userId', response.body.id)
    })
  })

  it('shows the created user in the dashboard', () => {
    cy.visit(`/users/${Cypress.env('userId')}`)

    cy.contains('Ada Lovelace').should('be.visible')
    cy.contains('ada@example.com').should('be.visible')
  })
})
Enter fullscreen mode Exit fullscreen mode

Esse padrão deixa seus testes de UI mais focados: a API prepara o estado, e a UI valida o comportamento visual.

cy.intercept() para stubbing

cy.request() acessa a API real. Quando você quer controlar o que o front-end recebe, use cy.intercept().

A diferença é importante:

  • cy.request() envia uma requisição HTTP real a partir do Node.
  • cy.intercept() intercepta requisições feitas pelo app no navegador.
  • cy.intercept() não intercepta chamadas feitas com cy.request().

Use cy.intercept() para testar como a UI reage a respostas específicas da API.

Exemplo de stub:

cy.intercept('GET', '/api/users', {
  statusCode: 200,
  body: [{ id: 1, name: 'Ada' }]
})
Enter fullscreen mode Exit fullscreen mode

Agora, qualquer requisição do navegador para /api/users recebe esse payload fixo.

Isso é útil para simular cenários como:

  • lista vazia;
  • erro 500;
  • timeout;
  • payload incompleto;
  • usuário sem permissões.

Exemplo testando erro de API na UI:

it('shows an error banner when the API fails', () => {
  cy.intercept('GET', '/api/users', {
    statusCode: 500,
    body: { message: 'Server error' }
  }).as('getUsers')

  cy.visit('/dashboard')

  cy.wait('@getUsers')
    .its('response.statusCode')
    .should('eq', 500)

  cy.contains('Something went wrong').should('be.visible')
})
Enter fullscreen mode Exit fullscreen mode

Configure a interceptação antes da ação que dispara a requisição. Caso contrário, o Cypress pode não capturar nada.

Você também pode simular uma resposta lenta:

cy.intercept('GET', '/api/users', {
  delay: 2000,
  statusCode: 200,
  body: []
}).as('getUsers')

cy.visit('/dashboard')

cy.contains('Loading').should('be.visible')
cy.wait('@getUsers')
cy.contains('No users found').should('be.visible')
Enter fullscreen mode Exit fullscreen mode

Se você está decidindo entre falsificar uma resposta ou simular um serviço inteiro, veja os posts sobre API mocking e API stubbing vs API mocking.

Quando Cypress para API faz sentido

Use Cypress para testes de API quando eles estão próximos da sua suite de UI.

Bons casos de uso:

  • preparar dados antes de um teste e2e;
  • validar rapidamente endpoints dos quais a UI depende;
  • fazer smoke tests de API no mesmo pipeline do Cypress;
  • autenticar via API antes de visitar uma página;
  • simular respostas do backend com cy.intercept() para testar estados da UI.

Exemplo de smoke test simples:

describe('API smoke checks', () => {
  it('health endpoint is available', () => {
    cy.request('https://api.example.com/health').then((response) => {
      expect(response.status).to.eq(200)
      expect(response.body.status).to.eq('ok')
    })
  })
})
Enter fullscreen mode Exit fullscreen mode

Quando uma ferramenta nativa de API faz mais sentido

O Cypress funciona bem para verificações de API dentro de uma suite de navegador. Mas ele não foi projetado como uma plataforma completa de teste de API.

Em uma suite grande e autônoma de API, algumas limitações aparecem:

  • cada requisição precisa ser escrita em código;
  • headers, bodies e query params ficam espalhados pelos arquivos de teste;
  • não há um construtor visual de requisições;
  • não há uma definição de API compartilhada como fonte central;
  • o Cypress ainda inicializa contexto de navegador, mesmo em execuções focadas em API;
  • colaboração entre QA, backend e frontend pode ficar menos fluida.

É nesse cenário que uma ferramenta nativa de API se encaixa melhor. O Apidog é construído em torno da própria API: você define endpoints, ambientes, autenticação, cenários e asserções em um workspace compartilhado. Para casos comuns, é possível montar requisições e validações visualmente, sem escrever tudo como código.

Para CI, o Apidog CLI executa cenários salvos de forma headless em qualquer etapa que rode Node:

npm install -g apidog-cli

apidog run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t <scenarioOrSuiteId> \
  -e <environmentId> \
  -r cli,html,json,junit
Enter fullscreen mode Exit fullscreen mode

Flags principais:

  • -t: cenário ou suite salvo.
  • -e: ambiente.
  • -r: formatos de relatório, como cli, html, json e junit.
  • -d ou --iteration-data: arquivo de dados para execução iterativa.
  • --upload-report: envia resultados de volta ao workspace.

A saída JUnit se integra bem à maioria dos dashboards de CI.

Uma regra prática:

  • use cy.request() para verificações de API que suportam seus testes de navegador;
  • use uma ferramenta nativa de API quando o teste de API for o trabalho principal.

Se você está comparando opções, veja também as ferramentas de automação de testes de API que rodam em CI/CD e as 30 melhores ferramentas de teste de API.

FAQ

cy.request() é executado no navegador?

Não. cy.request() roda no processo Node do Cypress, fora do navegador. Por isso, ele não é bloqueado por CORS ou pela política de same-origin.

Também por isso cy.intercept() não intercepta cy.request(). Se você precisa capturar uma requisição feita pelo navegador, dispare a chamada através do aplicativo e use cy.intercept().

Como testar uma resposta 400 ou 404 sem falhar o teste?

Use failOnStatusCode: false:

cy.request({
  method: 'GET',
  url: 'https://api.example.com/users/invalid-id',
  failOnStatusCode: false
}).then((response) => {
  expect(response.status).to.eq(404)
})
Enter fullscreen mode Exit fullscreen mode

Sem essa opção, o Cypress falha automaticamente em respostas que não sejam 2xx ou 3xx.

Posso usar cy.request() para fazer login antes de um teste de UI?

Sim. Esse é um padrão comum.

Você pode enviar um POST para o endpoint de login, ler o token em response.body e armazená-lo em Cypress.env(), localStorage ou cookie, dependendo de como sua aplicação autentica o usuário.

Exemplo:

cy.request({
  method: 'POST',
  url: 'https://api.example.com/login',
  body: {
    email: 'user@example.com',
    password: 'secret'
  }
}).then((response) => {
  window.localStorage.setItem('token', response.body.token)
})

cy.visit('/dashboard')
Enter fullscreen mode Exit fullscreen mode

Qual é a diferença entre cy.request() e cy.intercept()?

cy.request() envia uma requisição HTTP real e retorna a resposta real. Use para testar endpoints ou preparar dados.

cy.intercept() observa, espera ou simula requisições feitas pelo front-end no navegador. Use para controlar o que a UI recebe da API.

Em resumo:

Comando Uso principal
cy.request() Testar API real ou preparar estado
cy.intercept() Espionar ou simular chamadas feitas pela UI

Devo usar Cypress ou uma ferramenta dedicada para testes de API?

Use Cypress quando as verificações de API complementam uma suite de testes de navegador que você já executa.

Para uma suite grande de API, execução focada em CI, colaboração entre times e uma definição compartilhada de endpoints, uma ferramenta nativa de API como o Apidog tende a ser mais adequada.

Para decidir a estratégia, consulte também as melhores práticas de teste de API.

Top comments (0)