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.
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:
-
/loginretorna um token. -
/usersretorna uma lista no formato esperado. -
POST /orderscria um registro. - Uma resposta
500exibe uma mensagem de erro na tela.
Testar esses endpoints diretamente ajuda em dois cenários:
- Verificações mais rápidas: não há renderização, seleção de elementos ou espera por componentes da UI.
- 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)
A chamada mais simples usa GET por padrão:
cy.request('https://jsonplaceholder.typicode.com/users')
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
}
})
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')
})
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)
})
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 oContent-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')
})
})
})
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(/@/)
})
Também é comum validar headers:
cy.request('https://jsonplaceholder.typicode.com/users').then((response) => {
expect(response.headers['content-type']).to.include('application/json')
})
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 é:
- Fazer login.
- Ler o token da resposta.
- 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')
})
})
})
})
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)
})
})
})
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')
})
})
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 comcy.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' }]
})
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')
})
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')
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')
})
})
})
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
Flags principais:
-
-t: cenário ou suite salvo. -
-e: ambiente. -
-r: formatos de relatório, comocli,html,jsonejunit. -
-dou--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)
})
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')
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)