VCR для Playwright

Записать один раз.
Воспроизводить вечно.

Захватывает реальные ответы API, пока ваш набор Playwright выполняется локально, а затем воспроизводит их байт-в-байт в CI. Без бэкенда, без сети и без моков, написанных вручную, которые нужно поддерживать.

npm i -D test-proxy-recorder Поставить звезду на GitHubКоличество звёзд на GitHub

MIT · TypeScript · работает с SSR Next.js и TanStack Start, SPA и расширениями Chrome · поддержка WebSocket

REC · MODE=record · local run

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

REPLAY · MODE=replay · CI

200 OK · 3 ms · zero network

Посмотрите, как он записывает, а затем воспроизводит

Один прогон Playwright записывает реальные ответы на диск; переключитесь на воспроизведение — и тот же набор тестов пройдёт с выключенным бэкендом, без сети.

Два записывающих механизма, один прокси

Запросы исходят из двух мест, поэтому есть два механизма записи. Используйте любой — или оба вместе. Оба записывают один раз и воспроизводят с диска, поэтому CI работает с выключенным бэкендом и без моков, написанных вручную.

Прокси

.mock.json

Next.js / TanStack Start SSR → прокси → реальный API

Находится между вашим сервером и API. Записывает серверные запросы — SSR-fetch, route handlers и всё, что вызывает ваш backend-for-frontend.

Для full-stack-приложений, где сервер вызывает API.

Смотреть пример Next.js →Смотреть пример TanStack Start →

HAR

.har

браузер → перехват HAR → реальный API

Перехватывает в самом браузере. Записывает клиентские fetchвызовы, трафик API расширений Chrome, аналитику и сторонние API.

Для SPA, расширений и приложений только для браузера.

Смотреть пример расширения Chrome →

Где он уместен

Инструменты для моков хороши в разных задачах. Приведённая ниже комбинация — запись реального трафика через SSR, браузер и WebSocket без моков, написанных вручную, — это ниша, которую остальные оставляют незакрытой.

Сравнение возможностей test-proxy-recorder с routeFromHAR в Playwright, MSW, Polly.js, playwright-network-cache и Mocky Balboa.
Возможностьtest-proxy-recorderPlaywright routeFromHARMSWPolly.jsplaywright-network-cacheMocky Balboa
Запись реального трафикаДаДаНетДаДаНет
Серверная сторона (SSR)ДаНетДаЧастичноНетДа
Сторона браузераДаДаДаДаДаДа
WebSocketДаНетДаНетНетНет
Нативно для PlaywrightДаДаНетНетДаДа
ПоддерживаетсяДаДаДаНетДаДа

Polly.js перехватывает HTTP в Node, поэтому мокинг SSR возможен внутри процесса приложения, но не как часть прогона Playwright. MSW и Mocky Balboa тоже воспроизводят реальные ответы — но моки вы пишете вручную. О том, когда стоит выбрать что-то другое, рассказано вдокументации.

Работает с вашим реальным провайдером аутентификации

Входите через Cognito, Auth0, Clerk или WorkOS — по-настоящему, при каждом прогоне. Записывается только API вашего приложения; аутентификация остаётся живой, ваши данные уходят офлайн.

// 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' });
});

Настройка за три шага

Разверните всё одной командой, направьте ваш API на прокси, затем запишите и закоммитьте. Приложение только для браузера? initпропустит шаг SSR за вас.

Самый быстрый путь: отдайте это вашему AI-агенту

Скопируйте это, подставьте URL вашего бэкенда и вставьте в Claude Code, Cursor или любого кодинг-агента — он запустит initи доделает проводку по подсказке, которую initпечатает.

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.

Или подключите вручную:

  1. Установка и разворачивание

    init записывает конфиг прокси, фикстуру Playwright, глобальный тередаун,package.json скрипты и (для Next.js) тегирование SSR-fetch в вашем root layout — неразрушающе.

    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. Направьте API вашего приложения на прокси

    Единственное, что initне может угадать: какая переменная окружения хранит базовый URL вашего API. Направьте её на прокси, когда рекордер включён, на реальный бэкенд в остальных случаях — прокси никогда не запускается в продакшене.

    // 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`);

    Для Next.js initтакже добавляет registerProxyFetch()в ваш root layout, чтобы тегировать серверные fetchвызовы — no-op в продакшене:

    // 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. Запись, коммит, воспроизведение

    Задайте MODE = 'record', запустите один раз против реального API, затем переключите на 'replay'и закоммитьте. Записи живут в git — именно это делает CI детерминированным. Не добавляйте их в .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"

Хватит писать моки вручную

Ваш API уже даёт правильные ответы. Запишите их.

npm i -D test-proxy-recorder Поставить звезду на GitHub

Если это сэкономило вам полдня, звезда займёт одну секунду — именно так следующий человек найдёт проект, а соло-мейнтейнер поймёт, что нужно продолжать. Наткнулись на проблему или есть идея? Создайте issueилиприсоединяйтесь к Discord.