Mock de requisições do lado do servidor no Playwright (Next.js, TanStack Start)
Em uma aplicação Next.js ou TanStack Start, o servidor chama a sua API enquanto renderiza uma página. O mock de requisições do Playwright nunca vê essas chamadas. As seções abaixo explicam por quê e depois comparam quatro formas de controlá-las em um teste do Playwright: o modo de teste do Next.js (test mode), o MSW dentro do servidor, um proxy de encaminhamento (forward proxy) como o mockttp e a gravação de respostas reais com o test-proxy-recorder. Os fatos sobre as outras ferramentas foram conferidos na documentação e no código-fonte de cada uma em 2026-10-03.
Por que o page.route() não vê as requisições do lado do servidor
Seção intitulada “Por que o page.route() não vê as requisições do lado do servidor”O page.route() do Playwright atua sobre “requisições de rede feitas por uma página”. Já um Server Component, um loader de rota ou uma server function roda no processo Node.js da sua aplicação. O fetch dele vai desse processo direto para a API. A requisição nunca passa pelo navegador, então o Playwright não tem o que interceptar. O page.route() vê, sim, a requisição da página que o navegador envia para a sua aplicação e o HTML que volta. Ele nunca vê as requisições que o servidor fez para montar esse HTML.
Os arquivos HAR têm o mesmo limite, porque o page.routeFromHAR() serve “as requisições de rede feitas na página”.
A comparação do MSW com o Playwright diz o mesmo: o page.route() afeta “o tráfego no navegador iniciado, não o processo Node.js”. A publicação da equipe do Playwright sobre mock do lado do servidor diz que o page.route() funciona para requisições do navegador e que, “para chamadas HTTP do lado do servidor, não funciona”. O pedido de recurso de um mock do lado do servidor embutido, microsoft/playwright#30766, foi fechado em 2026-05-22 com um link para essa publicação.
Modo de teste do Next.js
Seção intitulada “Modo de teste do Next.js”O Next.js traz uma integração experimental com o Playwright em next/experimental/testmode/playwright. A única documentação dela é um README no repositório do Next.js, e o guia de Playwright do Next.js não a menciona. Um teste registra handlers com next.onFetch(), e o Next.js envia as chamadas fetch do servidor para eles:
// Resumido a partir do READMEimport { test, expect } from 'next/experimental/testmode/playwright';
test('/product/shoe', async ({ page, next }) => { next.onFetch((request) => { if (request.url === 'http://my-db/product/shoe') { return new Response(JSON.stringify({ title: 'A shoe' }), { headers: { 'Content-Type': 'application/json' }, }); } return 'abort'; });
await page.goto('/product/shoe'); await expect(page.locator('body')).toHaveText(/Shoe/);});O que ele exige:
experimental: { testProxy: true }nonext.config.js.- Um
playwright.config.tscriado com odefineConfigdenext/experimental/testmode/playwright, e testes que importamtestdo mesmo módulo.
Por baixo dos panos, cada worker do Playwright inicia um pequeno servidor proxy. A fixture adiciona um header Next-Test-Proxy-Port (esse proxy) e um header Next-Test-Data (o id do teste) às requisições da página (next-fixture.ts). Com o testProxy ativado, o servidor lê esses headers e envia cada fetch do lado do servidor para esse proxy. O proxy entrega a requisição aos handlers desse teste (fetch.ts). Os handlers são mantidos por id de teste, então testes em paralelo podem compartilhar um único servidor Next.js. Uma busca do servidor que nenhum handler responde lança Proxy request aborted. Em vez disso, um handler pode retornar 'continue' para deixar a requisição passar. O next.onFetch() também recebe as chamadas fetch da própria página para outras origens.
Situação:
- Experimental. O caminho de importação e a chave de config dizem isso, e o README se chama “Experimental test mode for Playwright”.
- Ainda recebe correções. A mais recente, vercel/next.js#96525, foi mesclada em 2026-08-13.
- O README também oferece handlers do MSW por teste por meio de
next/experimental/testmode/playwright/msw. Com o MSW 3.0 (lançado em 2026-09-28), esse ponto de entrada não carrega. Ele importa ostrict-event-emitter, do qual o MSW 3.0 não depende mais. Ele também chama ohandleRequest()do MSW, que a versão 3.0 removeu (notas de lançamento do MSW 3.0,msw.ts). Com o MSW 2.15.0 ele carrega. Os dois resultados são do Next.js 16.3.8, conferidos em 2026-10-03.
MSW no servidor do Next.js
Seção intitulada “MSW no servidor do Next.js”O MSW intercepta requisições no Node.js com o setupServer de msw/node (integração com Node.js). A documentação dele não tem um guia de Next.js. Quando o autor do MSW fechou a issue sobre o App Router, ele indicou o mswjs/examples#101 como referência de integração (comentário). Esse pull request está aberto desde 2024-01-22. Ele inicia o interceptador a partir do root layout, com uma lista fixa de handlers:
// app/layout.tsx, de mswjs/examples#101if (process.env.NEXT_RUNTIME === 'nodejs') { const { server } = require('@/mocks/node'); // setupServer(...handlers) server.listen();}Os handlers então vivem no processo do Next.js. O exemplo inicia esse processo com o webServer do Playwright, que roda um único processo para a execução inteira (publicação da equipe do Playwright). Todos os workers enviam suas páginas para esse único servidor, e workers em paralelo mudam o comportamento dos handlers dele:
- Um teste não pode chamar
server.use()nesse servidor, porque o teste roda no próprio processo de worker. O MSW não tem uma API lançada para mudar handlers em outro processo. A proposta,setupRemoteServerem mswjs/msw#1617, está aberta desde 2023-05-12. A integração do MSW com o Playwright diz que depende dopage.route()até que isso seja lançado (@msw/playwright). - Se você adicionar um canal próprio, como uma rota de API que chama
server.use(), a mudança atinge todos os testes. Os handlers adicionados comserver.use()“persistem na instância do servidor”. A publicação sobre o server boundary explica que sobrescritas concorrentes em um único servidor se tornam “um estado global compartilhado entre todos os testes”. Na #1617, o autor do MSW observa que, na prática, ou você mantém “uma lista fixa de handlers” ou inicia “uma instância da aplicação por caso de teste”.
Na prática, o MSW dentro de um servidor Next.js compartilhado dá as mesmas respostas a todos os testes em paralelo. Duas ferramentas acrescentam handlers por teste sobre o MSW. O modo de teste do Next.js aceita handlers do MSW (com o MSW 2, veja acima). O scenarist identifica os cenários por um header x-scenarist-test-id que o código do seu servidor repassa em cada fetch (adaptador para Next.js).
Um proxy de encaminhamento como o mockttp
Seção intitulada “Um proxy de encaminhamento como o mockttp”Quando a equipe do Playwright fechou a #30766, ela indicou a publicação de Simon Knott. A publicação coloca o mockttp, um servidor de mock e proxy HTTP e HTTPS, na frente do tráfego de saída do servidor. Cada teste adiciona regras a ele, como mocks.forPost(url).thenJson(200, body).
O código da aplicação não muda. O processo do servidor dela é iniciado com variáveis de ambiente que enviam as requisições de saída pelo proxy:
HTTP_PROXYeHTTPS_PROXYdefinidas com a URL do proxy.NODE_USE_ENV_PROXY=1, para que ofetchembutido do Node use essas variáveis. O Node.js a adicionou nas versões 24.0.0 e 22.21.0 e a marca como em desenvolvimento ativo (documentação do Node.js).NODE_EXTRA_CA_CERTSapontando para o certificado de CA do proxy, para que o servidor confie nos certificados que o mockttp gera para hosts HTTPS.
O proxy pertence a um único worker do Playwright, então a publicação inicia um servidor da aplicação por worker a partir de uma fixture de worker, cada um em uma porta livre. Ela evita o webServer do Playwright, que inicia um único processo para a execução inteira antes de existir qualquer worker. Na configuração da publicação, as requisições sem regra passam direto para a API real. A publicação sugere responder a elas com um erro, para que um mock esquecido apareça.
A equipe do Playwright descreve a abordagem como “agnóstica em relação à linguagem e ao framework do servidor”. A própria publicação usa um servidor Node simples, não Next.js nem TanStack Start.
Grave respostas reais com o test-proxy-recorder
Seção intitulada “Grave respostas reais com o test-proxy-recorder”Com as três opções acima, você mesmo escreve cada resposta. O test-proxy-recorder grava o que a sua API real retorna durante uma execução local e depois reproduz isso na CI.
- O proxy. Inicie o
test-proxy-recorder <target-url>ao lado da sua aplicação durante a execução dos testes. Aponte a URL base da API da aplicação para ele enquantoTEST_PROXY_RECORDER_ENABLEDestiver definido. Cada proxy encaminha para um único backend, o<target-url>com que foi iniciado. registerProxyFetch(). Uma única chamada no servidor faz patch dofetchglobal. Ela copia o headerx-test-rcrd-idda requisição atual para cada requisição de saída. O proxy lê esse header para associar cada chamada do lado do servidor ao respectivo teste. A chamada é um no-op em produção, a menos queTEST_PROXY_RECORDER_ENABLEDesteja definido.- O id por teste. O
playwrightProxy.before(page, testInfo, mode)monta um id de sessão a partir do arquivo de spec, dos seus títulos dedescribee do título do teste. Ele envia esse id comox-test-rcrd-idnas requisições da página e muda essa sessão pararecordoureplay. Workers em paralelo compartilham um único servidor da aplicação e um único proxy, e cada teste ainda tem a própria gravação.
import { registerProxyFetch } from 'test-proxy-recorder/nextjs';
registerProxyFetch();import { registerProxyFetch } from 'test-proxy-recorder/tanstack-start';
registerProxyFetch();test.beforeEach(async ({ page }, testInfo) => { await playwrightProxy.before(page, testInfo, 'replay', { url: /localhost:8100/ });});Grave uma vez contra a API real e faça commit dos arquivos .mock.json (servidor) e .har (navegador). A CI então os reproduz com o backend desligado. Na reprodução, uma requisição sem gravação recebe um 404 que a identifica. Ela nunca chega à API.
As respostas gravadas só cobrem o que a API fez enquanto você gravava. Para forçar um erro ou um caso-limite que a API não produz sob demanda, um handler escrito à mão, de uma das opções acima, é mais simples.
Os detalhes de configuração estão nos guias de Next.js e TanStack Start.
Compare as opções
Seção intitulada “Compare as opções”| Opção | Configuração na aplicação | Testes em paralelo | Handlers ou respostas gravadas | Next.js e TanStack Start |
|---|---|---|---|---|
| Modo de teste do Next.js | experimental.testProxy no next.config.js | Sim, os handlers são mantidos por teste | Handlers (next.onFetch() ou handlers do MSW 2) | Só Next.js |
| MSW no servidor | setupServer iniciado no código do servidor (o root layout, no exemplo do MSW) | Um único conjunto de handlers para todos os testes nesse servidor | Handlers | Next.js: um exemplo em um pull request aberto. TanStack Start: não documentado |
| mockttp | Nenhuma mudança de código. Variáveis de proxy e um certificado de CA no processo do servidor | Sim, com um servidor da aplicação por worker | Handlers. As requisições sem regra passam direto | Não documentado. A equipe do Playwright o chama de agnóstico de framework |
| test-proxy-recorder | URL base da API apontando para o proxy durante os testes, mais registerProxyFetch() | Sim, com um único servidor da aplicação compartilhado | Gravadas da API real | Ambos documentados |
A comparação cobre mais ferramentas, incluindo Mocky Balboa, scenarist, Polly.js, talkback e proxay, e as opções do lado do navegador.