Mockando Chamadas de API em Testes Vue com Vitest
Componentes Vue raramente vivem isolados. A maioria deles busca dados, envia formulários ou consulta endpoints. Quando você testa esses componentes sem controlar a rede, seus testes se tornam lentos, instáveis e dependentes de serviços externos. Mockar chamadas de API em testes Vue ajuda a eliminar esses problemas, permitindo que você controle as respostas que seus componentes recebem.
Este artigo cobre duas estratégias práticas para mocking de API Vue com Vitest: substituir o módulo de API diretamente com vi.mock, e interceptar requisições na camada HTTP usando Mock Service Worker (MSW). Você também aprenderá sobre o tratamento assíncrono específico do Vue que faz ambas as abordagens funcionarem de forma confiável.
Principais Conclusões
- Chamadas de rede reais em testes produzem resultados instáveis, lentos e não-determinísticos — mocking dá a você controle total sobre as respostas.
vi.mocksubstitui o módulo de API no nível de importação, sendo ideal para testes unitários rápidos e isolados.- MSW intercepta requisições na camada de rede, permitindo que sua lógica real de fetch ou axios execute para testes de integração mais realistas.
flushPromises()do@vue/test-utilsé comumente necessário quando componentes aguardam requisições assíncronas antes de atualizar o DOM.
Por Que Você Deve Mockar Chamadas de API em Testes de Componentes Vue com Vitest
Chamadas de rede reais em testes produzem resultados não-determinísticos. O mesmo teste pode passar localmente e falhar no CI simplesmente porque uma API externa está lenta ou indisponível. Mocking dá a você controle sobre o que a rede retorna, mantendo seus testes rápidos e previsíveis.
Estratégia 1: Mockando o Módulo de API com vi.mock
A abordagem mais direta é substituir o módulo responsável pelas chamadas HTTP antes que seu componente o veja.
// quote.service.ts
export async function fetchQuote() {
const response = await fetch('https://api.example.com/quotes/random')
return response.json()
}
// QuoteCard.test.ts
import { mount, flushPromises } from '@vue/test-utils'
import { vi, test, expect } from 'vitest'
import { fetchQuote } from './quote.service'
import QuoteCard from './QuoteCard.vue'
// vi.mock é elevado acima das importações automaticamente
vi.mock('./quote.service')
test('exibe uma citação após a montagem', async () => {
vi.mocked(fetchQuote).mockResolvedValue({
id: 1,
quote: 'Citação de teste',
author: 'Testador',
})
const wrapper = mount(QuoteCard)
// Aguarda todas as promises pendentes e atualizações do DOM se resolverem
await flushPromises()
expect(wrapper.text()).toContain('Citação de teste')
})
Um detalhe crítico: vi.mock é elevado para o topo do arquivo pelo Vitest, então é executado antes de qualquer importação. Este é um comportamento intencional documentado na API de mocking do Vitest. Isso significa que você pode importar com segurança a função real e ainda receber a versão mockada dentro do seu teste.
A chamada flushPromises() é frequentemente necessária neste padrão. Componentes Vue que buscam dados na montagem atualizam seu DOM de forma assíncrona. Utilitários como flushPromises garantem que promises pendentes sejam resolvidas antes que as asserções sejam executadas, evitando que os testes façam asserções contra estados de carregamento.
Quando usar esta abordagem: Teste unitário de um componente ou serviço específico em isolamento, onde você deseja controle rigoroso sobre valores de retorno e contagens de chamadas.
Discover how at OpenReplay.com.
Estratégia 2: MSW com Testes Vue Vitest para Mocking na Camada HTTP
Mock Service Worker intercepta requisições na camada de rede em vez de substituir módulos JavaScript. Isso torna seus testes mais realistas porque a chamada real de fetch ou axios ainda é executada — MSW apenas a intercepta antes que ela saia do processo.
Instale o MSW e configure-o para um ambiente Node (o padrão para Vitest):
npm install -D msw
// test/server.ts
import { setupServer } from 'msw/node'
import { http, HttpResponse } from 'msw'
export const server = setupServer(
http.get('https://api.example.com/quotes/random', () => {
return HttpResponse.json({ id: 1, quote: 'Citação MSW', author: 'MSW' })
})
)
// QuoteCard.test.ts
import { mount, flushPromises } from '@vue/test-utils'
import { test, expect, beforeAll, afterEach, afterAll } from 'vitest'
import { server } from './test/server'
import QuoteCard from './QuoteCard.vue'
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
test('exibe uma citação buscada via MSW', async () => {
const wrapper = mount(QuoteCard)
await flushPromises()
expect(wrapper.text()).toContain('Citação MSW')
})
flushPromises() ainda pode ser necessário aqui pela mesma razão — o sistema de reatividade do Vue precisa de um tick para aplicar atualizações do DOM após a resolução da promise.
Quando usar esta abordagem: Testes de estilo integração onde você deseja verificar que seu componente funciona com comportamento HTTP realista, ou quando múltiplos componentes compartilham o mesmo endpoint. A própria documentação do Vitest recomenda MSW para mocking no nível de requisição em ambientes de teste baseados em Node.
Escolhendo Entre vi.mock e MSW
vi.mock | MSW | |
|---|---|---|
| Intercepta em | Nível de módulo | Nível de rede |
| Testa lógica real de fetch | ❌ | ✅ |
| Controle por teste | ✅ Fácil | ✅ Via server.use() |
| Melhor para | Testes unitários | Testes de integração |
Conclusão
Ambas as estratégias são ferramentas válidas para mockar chamadas de API em testes Vue. Use vi.mock quando quiser testes unitários rápidos e isolados com controle preciso sobre valores de retorno. Use MSW quando quiser que seus testes exercitem o caminho completo da requisição. Em qualquer caso, utilitários como flushPromises() ajudam a garantir que o Vue termine de renderizar atualizações assíncronas antes que as asserções sejam executadas.
Perguntas Frequentes
Sim. Muitas equipes usam vi.mock para testes unitários focados de componentes individuais e MSW para testes de integração mais amplos que abrangem múltiplos componentes ou serviços. Mantenha-os em arquivos de teste separados para evitar confusão sobre qual camada está lidando com o mock.
O Vue ainda pode renderizar o estado de carregamento quando sua asserção é executada. Se sua asserção por acaso corresponder ao texto de carregamento, o teste passa por coincidência. O aviso no console normalmente sinaliza rejeições de promise não tratadas ou awaits faltando. Chamar flushPromises após montar componentes que disparam requisições assíncronas ajuda a evitar esses problemas de timing.
MSW intercepta na camada de rede, então funciona com qualquer cliente HTTP incluindo axios, fetch e bibliotecas construídas sobre eles como ky ou got. Sua escolha de cliente HTTP não afeta como o MSW lida com a interceptação.
Com vi.mock, chame mockRejectedValue para simular um erro assíncrono lançado. Com MSW, use server.use dentro de um teste específico para registrar um handler que retorna HttpResponse.json com um código de status 4xx ou 5xx. Ambas as abordagens permitem que você verifique o tratamento de erros do seu componente.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.