Configuração manual
A maioria das pessoas deve executar o init — ele escreve todos os arquivos abaixo para você. Esta página é a referência do que o init gera, para que você possa configurar à mão, dispensar a geração de código ou entender cada parte.
Full-stack (SSR + navegador)
Seção intitulada “Full-stack (SSR + navegador)”Para Next.js e frameworks semelhantes, onde tanto o servidor quanto o navegador fazem chamadas de API. Use os dois mecanismos de gravação juntos — veja como funciona.
O proxy é um processo leve que você inicia junto com a sua aplicação durante a execução dos testes (por um script, como abaixo, ou pelo webServer do Playwright) — não é infraestrutura que você implanta ou mantém. A configuração inteira é: iniciá-lo ao lado da sua aplicação, apontar a URL base da API da aplicação para ele, propagar o header de sessão a partir do SSR e escrever uma fixture.
1. Adicione scripts ao package.json
Seção intitulada “1. Adicione scripts ao package.json”{ "scripts": { "proxy": "test-proxy-recorder http://localhost:8000 --port 8100 --dir ./e2e/recordings", "dev:proxy": "concurrently \"npm run proxy\" \"TEST_PROXY_RECORDER_ENABLED=1 npm run dev\"", "serve:proxy": "concurrently \"npm run proxy\" \"TEST_PROXY_RECORDER_ENABLED=1 npm run serve\"" }}No código da sua aplicação, aponte a URL base da API para o proxy quando o recorder estiver habilitado e para o backend real caso contrário — o proxy nunca roda em produção:
const API_BASE = process.env.NODE_ENV === 'production' && !process.env.TEST_PROXY_RECORDER_ENABLED ? 'https://api.example.com' : 'http://localhost:8100'; // endereço do proxyO TEST_PROXY_RECORDER_ENABLED é definido pelos scripts dev:proxy / serve:proxy acima e pelos scripts gerados pelo init. Use a variável de ambiente que sua aplicação já usa para a URL base da API (por exemplo API_URL, NEXT_PUBLIC_API_URL) — a mesma condicional se aplica.
2. Marque as buscas do lado do servidor (Next.js)
Seção intitulada “2. Marque as buscas do lado do servidor (Next.js)”As chamadas fetch do lado do servidor precisam do header de sessão de gravação para que o proxy saiba a qual teste elas pertencem. O Playwright já o define na navegação do navegador, então o id fica em next/headers — você só precisa anexá-lo às requisições SSR de saída. Adicione uma linha ao seu root layout (o init faz isso por você):
import { registerProxyFetch } from 'test-proxy-recorder/nextjs';
registerProxyFetch(); // no-op em produção a menos que TEST_PROXY_RECORDER_ENABLED=true
export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en"> <body>{children}</body> </html> );}Isso funciona nos runtimes Node e Edge. Para aplicações com axios, chame registerProxyAxios(instance) em cada instância do lado do servidor em vez disso; para um único fetch, createHeadersWithRecordingId(await headers()) é uma alternativa sem patch. Um proxy.ts/middleware.ts com setNextProxyHeaders é opcional — ele apenas expõe o id, não marca as buscas. Grave contra um build de produção (next build && next start), não next dev. Veja a integração com Next.js para detalhes. Aplicações somente de navegador podem pular esta etapa.
3. Escreva um teste
Seção intitulada “3. Escreva um teste”import { test, expect } from '@playwright/test';import { playwrightProxy } from 'test-proxy-recorder';
// Requisições SSR (servidor → proxy) são gravadas em .mock.json.// Requisições do navegador para a URL do proxy também são cobertas.const CLIENT_SIDE_URL = /localhost:8100/;
// Mude para 'record' para atualizar as gravações.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();});4. Grave
Seção intitulada “4. Grave”# Terminal 1npm run serve:proxy
# Terminal 2 — arquivos .mock.json e .har são gravados automaticamentenpx playwright test5. Mude para replay e faça commit
Seção intitulada “5. Mude para replay e faça commit”git add e2e/recordings/git commit -m "add e2e recordings"Somente navegador / SPA / extensão
Seção intitulada “Somente navegador / SPA / extensão”Quando todas as chamadas de API vêm do navegador (sem SSR), você só precisa do mecanismo HAR. Nenhum backend de proxy é necessário para a gravação em si — o processo do proxy apenas fornece o gerenciamento de sessão.
1. Instale
Seção intitulada “1. Instale”npm install --save-dev test-proxy-recorder2. Adicione o proxy ao playwright.config.ts
Seção intitulada “2. Adicione o proxy ao playwright.config.ts”import { defineConfig } from '@playwright/test';
export default defineConfig({ webServer: { command: 'test-proxy-recorder https://api.example.com --port 8100 --dir ./e2e/recordings', url: 'http://localhost:8100/__control', reuseExistingServer: true, },});O alvo do proxy (https://api.example.com) não importa para gravação somente de navegador — ele só é usado se as requisições do lado do servidor (SSR) também precisarem ser proxied. O processo do proxy deve estar em execução para que o endpoint /__control fique disponível para o gerenciamento de sessão.
3. Escreva uma fixture
Seção intitulada “3. Escreva uma fixture”import { test as base, type Page, type BrowserContext } from '@playwright/test';import { playwrightProxy } from 'test-proxy-recorder';
// Corresponda ao domínio da API externa para o qual seu navegador faz requisições.// No modo record essas requisições vão para a API real e são salvas.// No modo replay elas são servidas a partir do disco — sem necessidade de rede.const CLIENT_SIDE_URL = /api\.example\.com/;
// Mude para 'record' para acessar a API real e atualizar as gravações.const MODE = 'replay' as const;
export const test = base.extend<{ page: Page }>({ page: async ({ context }, use, testInfo) => { const page = await context.newPage(); await playwrightProxy.before(page, testInfo, MODE, { url: CLIENT_SIDE_URL }); await use(page); },});4. Escreva um teste
Seção intitulada “4. Escreva um teste”import { test, expect } from './fixtures';
test('homepage loads', async ({ page }) => { await page.goto('https://myapp.com/'); await expect(page.getByText('Welcome')).toBeVisible();});5. Grave — execute uma vez contra a API real
Seção intitulada “5. Grave — execute uma vez contra a API real”# No fixtures.ts: const MODE = 'record' as const;npx playwright test# arquivos .har são gravados em e2e/recordings/ automaticamente6. Mude para replay e faça commit
Seção intitulada “6. Mude para replay e faça commit”# No fixtures.ts: const MODE = 'replay' as const;git add e2e/recordings/git commit -m "add e2e recordings"A CI agora roda sem nenhum acesso à rede.
Adicione isto ao .gitattributes para recolher arquivos de gravação grandes nos diffs de PR:
/e2e/recordings/** binary