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-recorder Playwright routeFromHAR MSW Polly.js playwright-network-cache Mocky 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.