VCR para Playwright

Grave uma vez.
Reproduza para sempre.

Captura respostas reais da API enquanto sua suite do Playwright roda localmente e depois as reproduz byte por byte na CI. Sem backend, sem rede, sem mocks escritos à mão para manter.

npm i -D test-proxy-recorder Estrelar no GitHub Contagem de estrelas do GitHub

MIT · TypeScript · funciona com SSR de Next.js e TanStack Start, SPAs e extensões do Chrome · suporte a WebSocket

REC · MODE=record · local run

saved e2e/recordings/todos.GET.mock.json

REPLAY · MODE=replay · CI

200 OK · 3 ms · zero network

Veja gravar e depois reproduzir

Uma execução do Playwright grava respostas reais no disco; mude para reproduzir e a mesma suite passa com o backend desligado — sem rede.

Dois gravadores, um proxy

As requisições se originam em dois lugares, então há dois mecanismos de gravação. Use um ou outro — ou ambos juntos. Ambos gravam uma vez e reproduzem a partir do disco, então a CI roda com o backend desligado e sem mocks escritos à mão.

Proxy

.mock.json

SSR de Next.js / TanStack Start → proxy → API real

Fica entre o seu servidor e a API. Grava requisições do lado do servidor — fetches SSR, route handlers, tudo o que seu backend-for-frontend chama.

Para aplicações full-stack onde o servidor chama a API.

Ver o exemplo de Next.js → Ver o exemplo de TanStack Start →

HAR

.har

navegador → interceptação HAR → API real

Intercepta no próprio navegador. Grava chamadas fetch do lado do cliente, tráfego de API de extensões do Chrome, analytics e APIs de terceiros.

Para SPAs, extensões e aplicações somente de navegador.

Ver o exemplo de extensão do Chrome →

Onde ele se encaixa

As ferramentas de mock são boas em trabalhos diferentes. A combinação abaixo — gravar tráfego real em SSR, navegador e WebSockets, sem mocks escritos à mão — é a lacuna que as outras deixam em aberto.

Comparação de recursos do test-proxy-recorder com o routeFromHAR do Playwright, MSW, Polly.js, playwright-network-cache e Mocky Balboa.
Recurso test-proxy-recorder Playwright routeFromHAR MSW Polly.js playwright-network-cache Mocky Balboa
Grava tráfego real Sim Sim Não Sim Sim Não
Lado do servidor (SSR) Sim Não Sim Parcial Não Sim
Lado do navegador Sim Sim Sim Sim Sim Sim
WebSocket Sim Não Sim Não Não Não
Nativo do Playwright Sim Sim Não Não Sim Sim
Mantido Sim Sim Sim Não Sim Sim

O Polly.js intercepta o HTTP do Node, então mockar SSR é possível dentro do processo da aplicação, mas não como parte de uma execução do Playwright. O MSW e o Mocky Balboa também reproduzem respostas reais — mas você escreve os mocks à mão. Quando optar por outra ferramenta é explicado na documentação.

Funciona com o seu provedor de autenticação real

Faça login via Cognito, Auth0, Clerk ou WorkOS — de verdade, em cada execução. Somente a API da sua aplicação é gravada; a autenticação permanece ao vivo e seus dados ficam offline.

// e2e/auth.setup.ts — log in for real, once. Never recorded.
import { test as setup } from '@playwright/test';
import { setProxyMode } from 'test-proxy-recorder';
setup('authenticate', async ({ page }) => {
await setProxyMode('transparent'); // login bypasses the recorder
await page.goto('/login');
await page.getByTestId('email').fill(process.env.TEST_EMAIL!);
await page.getByTestId('password').fill(process.env.TEST_PASSWORD!);
await page.getByTestId('signinButton').click();
await page.waitForURL('/dashboard');
// Reused by every test — they start already signed in.
await page.context().storageState({ path: 'e2e/.auth/state.json' });
});

Configure em três passos

Gere tudo com um comando, aponte sua API para o proxy, depois grave e faça commit. Aplicação somente de navegador? init pula a etapa de SSR para você.

Caminho mais rápido: entregue ao seu agente de IA

Copie isto, troque pela URL do seu backend e cole no Claude Code, Cursor ou em qualquer agente de codificação — ele executa init e conclui a configuração a partir do prompt que init imprime.

Set up test-proxy-recorder for end-to-end tests in this project, then follow the
instructions that `init` prints. Run these commands:
npx @tanstack/intent@latest install
npm install --save-dev test-proxy-recorder
Then run init, passing this project's backend API base URL as the target — find
it yourself from the app's env/config (the URL the app calls in dev); don't
assume the default:
npx test-proxy-recorder init <your-backend-api-url> --port 8100 --dir ./e2e/recordings
Then complete the app-specific steps init prints: point the app's API base URL at
the proxy in dev/test only, tag server-side fetches (Next.js), add a smoke test,
and verify record → replay.

Ou configure à mão:

  1. Instale e gere

    init escreve a config do proxy, uma fixture do Playwright, um teardown global e os scripts de package.json e (no Next.js) conecta a marcação das buscas SSR ao seu root layout — de forma não destrutiva.

    Terminal window
    npm install --save-dev test-proxy-recorder
    # http://localhost:3002 is your API endpoint; 8100 is the proxy. Flags are optional.
    npx test-proxy-recorder init http://localhost:3002 --port 8100 --dir ./e2e/recordings
  2. Aponte a API da sua aplicação para o proxy

    A única coisa que o init não consegue adivinhar: qual variável de ambiente guarda a URL base da sua API. Aponte-a para o proxy quando o recorder estiver habilitado e para o backend real caso contrário — o proxy nunca roda em produção.

    // Point your app at the proxy when the recorder is enabled, at the real backend otherwise.
    // The proxy never runs in production — TEST_PROXY_RECORDER_ENABLED is set only for e2e.
    const API_BASE =
    process.env.NODE_ENV === 'production' && !process.env.TEST_PROXY_RECORDER_ENABLED
    ? 'https://api.example.com'
    : 'http://localhost:8100'; // proxy address from `init`
    const res = await fetch(`${API_BASE}/todos`);

    No Next.js, o init também adiciona registerProxyFetch() ao seu root layout para marcar as chamadas fetch do lado do servidor — um no-op em produção:

    // app/layout.tsx — tag server-side fetches so SSR is recorded/replayed
    import { registerProxyFetch } from 'test-proxy-recorder/nextjs';
    registerProxyFetch(); // no-op in production unless TEST_PROXY_RECORDER_ENABLED=true
  3. Grave, faça commit, reproduza

    Defina MODE = 'record', execute uma vez contra a API real, depois mude para 'replay' e faça commit. As gravações vivem no git — é isso que torna a CI determinística. Não as coloque no .gitignore.

    e2e/my.test.ts
    import { test, expect } from '@playwright/test';
    import { playwrightProxy } from 'test-proxy-recorder';
    // Full-stack: the browser also talks to the proxy, so match its URL.
    // (Browser-only app? Match your real API domain instead, e.g. /api\.example\.com/.)
    const CLIENT_SIDE_URL = /localhost:8100/;
    // 'record' hits the real API and saves responses.
    // 'replay' serves them from disk — no network needed.
    const MODE = 'replay' as const;
    test.beforeEach(async ({ page }, testInfo) => {
    await playwrightProxy.before(page, testInfo, MODE, { url: CLIENT_SIDE_URL });
    });
    test('homepage loads', async ({ page }) => {
    await page.goto('/');
    await expect(page.getByText('Welcome')).toBeVisible();
    });
    Terminal window
    # 1. Set MODE = 'record' in your test file, run against the real API
    npx playwright test --ui # recordings written to e2e/recordings/
    # 2. Flip MODE back to 'replay' and commit the recordings
    git add e2e/recordings/
    git commit -m "add e2e recordings"

Pare de escrever mocks à mão

Sua API já dá as respostas certas. Grave-as.

npm i -D test-proxy-recorder Estrelar no GitHub

Se isso economizou uma tarde, uma estrela leva um segundo — é assim que a próxima pessoa encontra e diz a um mantenedor solo para continuar construindo. Esbarrou em um problema ou teve uma ideia? Abra uma issue ou entre no Discord.