test-proxy-recorder 0.3.5 → 0.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +295 -100
- package/dist/{index-BlBWqSE4.d.cts → index-BloXCw69.d.cts} +4 -0
- package/dist/{index-BlBWqSE4.d.ts → index-BloXCw69.d.ts} +4 -0
- package/dist/index.cjs +488 -400
- package/dist/index.d.cts +10 -42
- package/dist/index.d.ts +10 -42
- package/dist/index.mjs +486 -398
- package/dist/playwright/index.cjs +8 -0
- package/dist/playwright/index.d.cts +1 -1
- package/dist/playwright/index.d.ts +1 -1
- package/dist/playwright/index.mjs +8 -0
- package/dist/proxy.js +478 -398
- package/package.json +13 -17
- package/skills/nextjs-ssr/SKILL.md +377 -0
- package/skills/proxy-setup/SKILL.md +458 -0
package/README.md
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
Fast, deterministic Playwright tests without maintaining manual mocks.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Records real API responses during test runs and replays them on CI — no backend required. Supports two recording mechanisms depending on where your requests originate:
|
|
9
9
|
|
|
10
|
-
```
|
|
10
|
+
```text
|
|
11
11
|
Record mode Replay mode
|
|
12
12
|
|
|
13
13
|
Browser/App ──> Proxy ──> Real API Browser/App ──> Proxy ──> Disk
|
|
@@ -16,83 +16,202 @@ An HTTP proxy that records real API responses during test runs and replays them
|
|
|
16
16
|
(.mock.json) (.mock.json)
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
| Mechanism | What it records | Use case |
|
|
20
|
+
| --------- | --------------- | -------- |
|
|
21
|
+
| **Proxy** (`.mock.json`) | Server-side requests (SSR fetches from Next.js etc.) | Full-stack apps where the server calls the API |
|
|
22
|
+
| **HAR** (`.har`) | Browser-side requests (browser `fetch`, extensions, SPAs) | SPAs, Chrome extensions, 3rd-party APIs |
|
|
23
|
+
|
|
24
|
+
Both can be used together or independently.
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
Server-side (proxy) Browser-side (HAR)
|
|
28
|
+
|
|
29
|
+
Next.js SSR ──> Proxy ──> Real API Browser ──> HAR intercept ──> Real API
|
|
30
|
+
│ │
|
|
31
|
+
└──> .mock.json └──> .har
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Contents
|
|
35
|
+
|
|
36
|
+
- [Why](#why)
|
|
37
|
+
- [Full-stack (SSR + browser) Quick Start](#full-stack-ssr--browser-quick-start)
|
|
38
|
+
- [Browser-only / SPA / Extension Quick Start](#browser-only--spa--extension-quick-start)
|
|
39
|
+
- [CLI](#cli)
|
|
40
|
+
- [Example Apps](#example-apps)
|
|
41
|
+
- [Playwright Integration](#playwright-integration)
|
|
42
|
+
- [Next.js Integration](#nextjs-integration)
|
|
43
|
+
- [Control Endpoint](#control-endpoint)
|
|
44
|
+
- [API Reference](#api-reference)
|
|
45
|
+
- [Next.js 16](#nextjs-16)
|
|
46
|
+
- [FAQ](#faq)
|
|
47
|
+
- [AI Agent Skills](#ai-agent-skills)
|
|
48
|
+
- [Roadmap](#roadmap)
|
|
49
|
+
- [Requirements](#requirements)
|
|
50
|
+
- [Contributing](#contributing)
|
|
51
|
+
- [License](#license)
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
19
55
|
## Why
|
|
20
56
|
|
|
21
|
-
- **No backend on CI**
|
|
22
|
-
- **No manual mocks**
|
|
23
|
-
- **SSR support**
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
57
|
+
- **No backend on CI** — record once against the real API, replay on every CI run
|
|
58
|
+
- **No manual mocks** — capture real interactions instead of hand-writing fixtures
|
|
59
|
+
- **SSR support** — records server-side requests from Next.js and similar frameworks
|
|
60
|
+
- **Browser-side support** — records browser `fetch` calls, Chrome extension API calls, analytics, etc.
|
|
61
|
+
- **Deterministic** — same responses every time, no flaky network
|
|
62
|
+
- **WebSocket support** — records and replays WebSocket connections
|
|
26
63
|
|
|
27
|
-
|
|
64
|
+
---
|
|
28
65
|
|
|
29
|
-
|
|
66
|
+
## Full-stack (SSR + browser) Quick Start
|
|
30
67
|
|
|
31
|
-
|
|
32
|
-
npm install --save-dev test-proxy-recorder
|
|
33
|
-
```
|
|
68
|
+
For apps like Next.js where both the server AND the browser make API calls, use both mechanisms together.
|
|
34
69
|
|
|
35
|
-
###
|
|
70
|
+
### 1. Add scripts to `package.json`
|
|
36
71
|
|
|
37
72
|
```json
|
|
38
73
|
{
|
|
39
74
|
"scripts": {
|
|
40
|
-
"proxy": "test-proxy-recorder http://localhost:8000 --port 8100 --dir ./e2e/recordings"
|
|
75
|
+
"proxy": "test-proxy-recorder http://localhost:8000 --port 8100 --dir ./e2e/recordings",
|
|
76
|
+
"dev:proxy": "concurrently \"npm run proxy\" \"INTERNAL_API_URL=http://localhost:8100 npm run dev\"",
|
|
77
|
+
"serve:proxy": "concurrently \"npm run proxy\" \"INTERNAL_API_URL=http://localhost:8100 npm run serve\""
|
|
41
78
|
}
|
|
42
79
|
}
|
|
43
80
|
```
|
|
44
81
|
|
|
45
|
-
>
|
|
46
|
-
> `INTERNAL_API_URL` is the env var your app uses for the API base URL -- point it at the proxy instead of the real backend. Use proxy address for dev/test and real backend for production environment.
|
|
47
|
-
> Replace it with whatever env var your app uses (e.g. `API_URL`, `NEXT_PUBLIC_API_URL`).
|
|
48
|
-
>
|
|
49
|
-
> ```json
|
|
50
|
-
> {
|
|
51
|
-
> "scripts": {
|
|
52
|
-
> "proxy": "test-proxy-recorder http://localhost:8000 --port 8100 --dir ./e2e/recordings",
|
|
53
|
-
> "dev:proxy": "concurrently \"npm run proxy\" \"INTERNAL_API_URL=http://localhost:8100 npm run dev\"",
|
|
54
|
-
> "serve:proxy": "concurrently \"npm run proxy\" \"INTERNAL_API_URL=http://localhost:8100 npm run serve\""
|
|
55
|
-
> }
|
|
56
|
-
> }
|
|
57
|
-
> ```
|
|
82
|
+
> `INTERNAL_API_URL` is the env var your app uses for the API base URL — point it at the proxy instead of the real backend. Replace it with whatever env var your app uses (e.g. `API_URL`, `NEXT_PUBLIC_API_URL`).
|
|
58
83
|
>
|
|
59
84
|
> **Next.js note:** Prefer `build` + `serve` over `dev` for recording/replaying tests. The Next.js dev server is slow and can cause timeouts or flaky recordings.
|
|
60
85
|
|
|
61
|
-
###
|
|
86
|
+
### 2. Write a test
|
|
62
87
|
|
|
63
88
|
```typescript
|
|
64
89
|
import { test, expect } from '@playwright/test';
|
|
65
90
|
import { playwrightProxy } from 'test-proxy-recorder';
|
|
66
91
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
92
|
+
// SSR requests (server → proxy) are recorded to .mock.json.
|
|
93
|
+
// Browser requests to the proxy URL are also covered.
|
|
94
|
+
const CLIENT_SIDE_URL = /localhost:8100/;
|
|
70
95
|
|
|
96
|
+
// Change to 'record' to update recordings.
|
|
97
|
+
const MODE = 'replay' as const;
|
|
98
|
+
|
|
99
|
+
test.beforeEach(async ({ page }, testInfo) => {
|
|
100
|
+
await playwrightProxy.before(page, testInfo, MODE, { url: CLIENT_SIDE_URL });
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('homepage loads', async ({ page }) => {
|
|
71
104
|
await page.goto('/');
|
|
72
105
|
await expect(page.getByText('Welcome')).toBeVisible();
|
|
73
106
|
});
|
|
74
107
|
```
|
|
75
108
|
|
|
76
|
-
###
|
|
77
|
-
|
|
78
|
-
Start the proxy + app first (e.g. `npm run serve:proxy`), then run tests in a separate terminal:
|
|
109
|
+
### 3. Record
|
|
79
110
|
|
|
80
111
|
```bash
|
|
81
|
-
# Terminal 1
|
|
112
|
+
# Terminal 1
|
|
82
113
|
npm run serve:proxy
|
|
83
114
|
|
|
84
|
-
# Terminal 2
|
|
115
|
+
# Terminal 2 — .mock.json and .har files are written automatically
|
|
85
116
|
npx playwright test
|
|
86
117
|
```
|
|
87
118
|
|
|
88
|
-
###
|
|
119
|
+
### 4. Switch to replay and commit
|
|
89
120
|
|
|
90
121
|
```bash
|
|
91
|
-
|
|
92
|
-
|
|
122
|
+
git add e2e/recordings/
|
|
123
|
+
git commit -m "add e2e recordings"
|
|
93
124
|
```
|
|
94
125
|
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Browser-only / SPA / Extension Quick Start
|
|
129
|
+
|
|
130
|
+
If your app or extension makes API calls entirely from the browser (no SSR), you only need the HAR mechanism. No proxy backend is required for the actual recording — the proxy process just provides session management.
|
|
131
|
+
|
|
132
|
+
### 1. Install
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
npm install --save-dev test-proxy-recorder
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 2. Add the proxy to `playwright.config.ts`
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { defineConfig } from '@playwright/test';
|
|
142
|
+
|
|
143
|
+
export default defineConfig({
|
|
144
|
+
webServer: {
|
|
145
|
+
command: 'test-proxy-recorder https://api.example.com --port 8100 --dir ./e2e/recordings',
|
|
146
|
+
url: 'http://localhost:8100/__control',
|
|
147
|
+
reuseExistingServer: true,
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
> The proxy target (`https://api.example.com`) does not matter for browser-only recording — it is only used if server-side (SSR) requests also need to be proxied. The proxy process must run so its `/__control` endpoint is available for session management.
|
|
153
|
+
|
|
154
|
+
### 3. Write a fixture
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// e2e/fixtures.ts
|
|
158
|
+
import { test as base, type Page, type BrowserContext } from '@playwright/test';
|
|
159
|
+
import { playwrightProxy } from 'test-proxy-recorder';
|
|
160
|
+
|
|
161
|
+
// Match the external API domain your browser makes requests to.
|
|
162
|
+
// In record mode these requests go to the real API and are saved.
|
|
163
|
+
// In replay mode they are served from disk — no network needed.
|
|
164
|
+
const CLIENT_SIDE_URL = /api\.example\.com/;
|
|
165
|
+
|
|
166
|
+
// Change to 'record' to hit the real API and update recordings.
|
|
167
|
+
const MODE = 'replay' as const;
|
|
168
|
+
|
|
169
|
+
export const test = base.extend<{ page: Page }>({
|
|
170
|
+
page: async ({ context }, use, testInfo) => {
|
|
171
|
+
const page = await context.newPage();
|
|
172
|
+
await playwrightProxy.before(page, testInfo, MODE, { url: CLIENT_SIDE_URL });
|
|
173
|
+
await use(page);
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### 4. Write a test
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
// e2e/my.test.ts
|
|
182
|
+
import { test, expect } from './fixtures';
|
|
183
|
+
|
|
184
|
+
test('homepage loads', async ({ page }) => {
|
|
185
|
+
await page.goto('https://myapp.com/');
|
|
186
|
+
await expect(page.getByText('Welcome')).toBeVisible();
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 5. Record — run once against the real API
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# In fixtures.ts: const MODE = 'record' as const;
|
|
194
|
+
npx playwright test
|
|
195
|
+
# .har files are written to e2e/recordings/ automatically
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 6. Switch to replay and commit
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# In fixtures.ts: const MODE = 'replay' as const;
|
|
202
|
+
git add e2e/recordings/
|
|
203
|
+
git commit -m "add e2e recordings"
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
CI now runs without any network access.
|
|
207
|
+
|
|
95
208
|
> Do **not** add `e2e/recordings` to `.gitignore`. Recordings must be in git for CI replay.
|
|
209
|
+
>
|
|
210
|
+
> Add this to `.gitattributes` to collapse large recording files in PR diffs:
|
|
211
|
+
>
|
|
212
|
+
> ```text
|
|
213
|
+
> /e2e/recordings/** binary
|
|
214
|
+
> ```
|
|
96
215
|
|
|
97
216
|
---
|
|
98
217
|
|
|
@@ -114,21 +233,49 @@ test-proxy-recorder http://localhost:8000
|
|
|
114
233
|
test-proxy-recorder http://localhost:8000 --port 8100 --dir ./mocks
|
|
115
234
|
```
|
|
116
235
|
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Example Apps
|
|
239
|
+
|
|
240
|
+
Two full working examples live in [`apps/`](https://github.com/asmyshlyaev177/test-proxy-recorder/tree/master/apps) — one for each recording mechanism. Each has its own README with the full setup and record/replay workflow.
|
|
241
|
+
|
|
242
|
+
### Next.js 16 — server-side (proxy / `.mock.json`)
|
|
243
|
+
|
|
244
|
+
[`apps/example-nextjs16`](https://github.com/asmyshlyaev177/test-proxy-recorder/tree/master/apps/example-nextjs16) — a Next.js 16 todo app with a mock backend, proxy, and Playwright e2e tests. Records both SSR fetches (`.mock.json`) and browser fetches (`.har`). See its [README](https://github.com/asmyshlyaev177/test-proxy-recorder/blob/master/apps/example-nextjs16/README.md).
|
|
245
|
+
|
|
246
|
+
### Chrome extension — browser-side (HAR / `.har`)
|
|
247
|
+
|
|
248
|
+
[`apps/example-extension`](https://github.com/asmyshlyaev177/test-proxy-recorder/tree/master/apps/example-extension) — a real Chrome extension that calls X/Twitter's API from a content script; browser requests are recorded to `.har` and replayed offline, with no live API or account needed on CI. See its [README](https://github.com/asmyshlyaev177/test-proxy-recorder/blob/master/apps/example-extension/README.md).
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
117
252
|
## Playwright Integration
|
|
118
253
|
|
|
119
|
-
|
|
254
|
+
<details>
|
|
255
|
+
<summary>Show details</summary>
|
|
120
256
|
|
|
121
|
-
|
|
122
|
-
import { test } from '@playwright/test';
|
|
123
|
-
import { playwrightProxy } from 'test-proxy-recorder';
|
|
257
|
+
### `playwrightProxy.before(page, testInfo, mode, options?)`
|
|
124
258
|
|
|
125
|
-
test(
|
|
126
|
-
|
|
127
|
-
|
|
259
|
+
Call this at the start of each test (or in a `beforeEach` / page fixture). It sets the proxy mode for the session and, if `url` is provided, sets up HAR recording for browser-side requests.
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
await playwrightProxy.before(page, testInfo, 'replay', {
|
|
263
|
+
// url: pattern for browser-side requests to record/replay via HAR.
|
|
264
|
+
//
|
|
265
|
+
// Use the ACTUAL external API domain — not the proxy URL.
|
|
266
|
+
// Examples:
|
|
267
|
+
// /api\.example\.com/ — your own API
|
|
268
|
+
// /x\.com/ — record all x.com browser traffic (Chrome extension tests)
|
|
269
|
+
// /cognito-.*amazonaws\.com/ — 3rd-party auth
|
|
270
|
+
url: /api\.example\.com/,
|
|
128
271
|
});
|
|
129
272
|
```
|
|
130
273
|
|
|
131
|
-
`
|
|
274
|
+
**`url` pattern:** matches the real external domain that the browser calls. In record mode requests go to the real API and are saved to a `.har` file. In replay mode they are served from that file — no network needed. This pattern does **not** point to the proxy (`localhost:8100`).
|
|
275
|
+
|
|
276
|
+
**Exception — full-stack apps:** when the browser also calls `localhost:8100` (because the frontend is configured with the proxy URL as its API base), use `/localhost:8100/` as the pattern.
|
|
277
|
+
|
|
278
|
+
Recording filenames are derived from test names (`"create a user"` → `create-a-user.mock.json` / `.har`).
|
|
132
279
|
|
|
133
280
|
### Global teardown (recommended)
|
|
134
281
|
|
|
@@ -148,27 +295,26 @@ export default defineConfig({
|
|
|
148
295
|
});
|
|
149
296
|
```
|
|
150
297
|
|
|
151
|
-
###
|
|
298
|
+
### Recording files
|
|
152
299
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
url: /cognito-.*amazonaws\.com|\.stream-io-api\.com/,
|
|
158
|
-
});
|
|
300
|
+
```text
|
|
301
|
+
e2e/recordings/
|
|
302
|
+
my-test.mock.json # server-side (proxy) — SSR fetches
|
|
303
|
+
my-test.har # client-side (HAR) — browser fetches
|
|
159
304
|
```
|
|
160
305
|
|
|
161
|
-
|
|
306
|
+
</details>
|
|
162
307
|
|
|
163
|
-
|
|
164
|
-
e2e/recordings/
|
|
165
|
-
my-test.mock.json # server-side (proxy)
|
|
166
|
-
my-test.har # client-side (HAR)
|
|
167
|
-
```
|
|
308
|
+
---
|
|
168
309
|
|
|
169
310
|
## Next.js Integration
|
|
170
311
|
|
|
171
|
-
|
|
312
|
+
<details>
|
|
313
|
+
<summary>Show details</summary>
|
|
314
|
+
|
|
315
|
+
SSR frameworks like Next.js make server-side `fetch` calls that go through the proxy without a browser context. The proxy identifies which session those requests belong to via the `x-test-rcrd-id` header — the same header `playwrightProxy.before()` sets on the browser `page`. This header is **only required for SSR** — for browser-only tests the proxy falls back to the globally set session automatically.
|
|
316
|
+
|
|
317
|
+
For SSR requests to carry this header, use one of:
|
|
172
318
|
|
|
173
319
|
### Middleware (recommended)
|
|
174
320
|
|
|
@@ -198,8 +344,15 @@ const res = await fetch('http://localhost:8100/api/data', {
|
|
|
198
344
|
});
|
|
199
345
|
```
|
|
200
346
|
|
|
347
|
+
</details>
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
201
351
|
## Control Endpoint
|
|
202
352
|
|
|
353
|
+
<details>
|
|
354
|
+
<summary>Show details</summary>
|
|
355
|
+
|
|
203
356
|
The proxy exposes `/__control` for programmatic mode switching.
|
|
204
357
|
|
|
205
358
|
```bash
|
|
@@ -220,8 +373,15 @@ interface ControlRequest {
|
|
|
220
373
|
}
|
|
221
374
|
```
|
|
222
375
|
|
|
376
|
+
</details>
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
223
380
|
## API Reference
|
|
224
381
|
|
|
382
|
+
<details>
|
|
383
|
+
<summary>Show details</summary>
|
|
384
|
+
|
|
225
385
|
### `playwrightProxy`
|
|
226
386
|
|
|
227
387
|
```typescript
|
|
@@ -230,7 +390,7 @@ const playwrightProxy: {
|
|
|
230
390
|
page: Page,
|
|
231
391
|
testInfo: TestInfo,
|
|
232
392
|
mode: 'record' | 'replay' | 'transparent',
|
|
233
|
-
options?:
|
|
393
|
+
options?: { url?: string | RegExp; timeout?: number }
|
|
234
394
|
): Promise<void>;
|
|
235
395
|
|
|
236
396
|
teardown(): Promise<void>;
|
|
@@ -258,17 +418,15 @@ function createHeadersWithRecordingId(
|
|
|
258
418
|
): Record<string, string>;
|
|
259
419
|
```
|
|
260
420
|
|
|
261
|
-
|
|
421
|
+
</details>
|
|
262
422
|
|
|
263
|
-
|
|
264
|
-
1. Record start proxy + app + backend, run tests with 'record' mode
|
|
265
|
-
2. Commit git add e2e/recordings/
|
|
266
|
-
3. Replay start proxy + app (no backend), run tests with 'replay' mode
|
|
267
|
-
4. Update re-record when API changes, commit new recordings
|
|
268
|
-
```
|
|
423
|
+
---
|
|
269
424
|
|
|
270
425
|
## Next.js 16
|
|
271
426
|
|
|
427
|
+
<details>
|
|
428
|
+
<summary>Show details</summary>
|
|
429
|
+
|
|
272
430
|
Next.js 16 uses `proxy.ts` as the middleware entry point (replaces `middleware.ts`). Place it at the project root alongside `next.config.ts`:
|
|
273
431
|
|
|
274
432
|
```typescript
|
|
@@ -277,7 +435,7 @@ import { NextResponse } from 'next/server';
|
|
|
277
435
|
import type { NextRequest } from 'next/server';
|
|
278
436
|
import { setNextProxyHeaders } from 'test-proxy-recorder/nextjs';
|
|
279
437
|
|
|
280
|
-
export function
|
|
438
|
+
export function proxy(request: NextRequest) {
|
|
281
439
|
const response = NextResponse.next();
|
|
282
440
|
setNextProxyHeaders(request, response);
|
|
283
441
|
return response;
|
|
@@ -300,62 +458,99 @@ export const config = {
|
|
|
300
458
|
}
|
|
301
459
|
```
|
|
302
460
|
|
|
303
|
-
|
|
461
|
+
</details>
|
|
462
|
+
|
|
463
|
+
---
|
|
304
464
|
|
|
305
|
-
|
|
465
|
+
## FAQ
|
|
306
466
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
467
|
+
<details>
|
|
468
|
+
<summary><strong>My parallel replay tests sometimes hit the real backend — why?</strong></summary>
|
|
469
|
+
|
|
470
|
+
You're likely calling `playwrightProxy.teardown()` in a per-test hook. It sets the **global** proxy mode to `transparent`, and with `fullyParallel: true` each Playwright worker runs its own `test.afterAll`. If a fast test finishes and calls `teardown()` while a slower test is still running, the proxy flips to transparent mid-test and the remaining requests are forwarded to the real backend instead of being replayed.
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
// ❌ breaks parallel replay — teardown() affects all sessions globally
|
|
474
|
+
test.afterAll(async () => {
|
|
475
|
+
await playwrightProxy.teardown();
|
|
476
|
+
});
|
|
313
477
|
```
|
|
314
478
|
|
|
315
|
-
**
|
|
479
|
+
**Fix:** omit `test.afterAll`. Session cleanup is automatic via `context.on('close')` → `cleanupSession()`. Use a [global teardown](https://playwright.dev/docs/test-global-setup-teardown) only if you need to reset the proxy after the entire run.
|
|
480
|
+
|
|
481
|
+
</details>
|
|
482
|
+
|
|
483
|
+
<details>
|
|
484
|
+
<summary><strong>Should I commit recordings to git?</strong></summary>
|
|
485
|
+
|
|
486
|
+
Yes. Recordings must be in git so CI can replay them with no network — do **not** add `e2e/recordings` to `.gitignore`. To keep large recording files from bloating PR diffs, mark them binary in `.gitattributes`:
|
|
316
487
|
|
|
317
488
|
```text
|
|
318
|
-
|
|
319
|
-
Next.js SSR ──> Proxy (8100) ──> Mock Backend (3002)
|
|
489
|
+
/e2e/recordings/** binary
|
|
320
490
|
```
|
|
321
491
|
|
|
322
|
-
|
|
492
|
+
</details>
|
|
323
493
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
pnpm --filter example-nextjs16 start:all
|
|
494
|
+
<details>
|
|
495
|
+
<summary><strong>Does the proxy <code><target-url></code> matter for browser-only (HAR) recording?</strong></summary>
|
|
327
496
|
|
|
328
|
-
|
|
329
|
-
pnpm --filter example-nextjs16 test:e2e:record
|
|
497
|
+
No. For browser-only recording the target is irrelevant — the proxy process just needs to run so its `/__control` endpoint is available for session management. The target only matters when server-side (SSR) requests are also routed through the proxy.
|
|
330
498
|
|
|
331
|
-
|
|
332
|
-
pnpm --filter example-nextjs16 test:e2e
|
|
333
|
-
```
|
|
499
|
+
</details>
|
|
334
500
|
|
|
335
|
-
|
|
501
|
+
<details>
|
|
502
|
+
<summary><strong>Can I record against the Next.js dev server?</strong></summary>
|
|
336
503
|
|
|
337
|
-
`
|
|
504
|
+
Prefer `next build` + `next start` over `next dev` for recording and replaying. The dev server is slow and can cause timeouts or flaky recordings.
|
|
338
505
|
|
|
339
|
-
|
|
506
|
+
</details>
|
|
340
507
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
508
|
+
<details>
|
|
509
|
+
<summary><strong>How do I update a recording?</strong></summary>
|
|
510
|
+
|
|
511
|
+
Re-run in record mode (set `MODE = 'record'` in your fixture, or `RECORD_MODE=1`) against the real API, then switch back to replay and commit the updated files in `e2e/recordings/`.
|
|
512
|
+
|
|
513
|
+
</details>
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
517
|
+
## AI Agent Skills
|
|
518
|
+
|
|
519
|
+
If you use an AI coding agent (Claude Code, Cursor, Copilot, etc.), install the skills for this library so the agent generates correct setup code:
|
|
520
|
+
|
|
521
|
+
```bash
|
|
522
|
+
npx @tanstack/intent@latest install
|
|
346
523
|
```
|
|
347
524
|
|
|
348
|
-
|
|
525
|
+
This adds `test-proxy-recorder` skills to your project. The agent will then know the correct proxy/fixture setup, record vs. replay workflow, and Next.js SSR header patterns without needing guidance.
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
## Roadmap
|
|
530
|
+
|
|
531
|
+
First-class integrations on the way:
|
|
532
|
+
|
|
533
|
+
- **TanStack Start**
|
|
534
|
+
- **Remix**
|
|
535
|
+
- **Vite + SSR**
|
|
536
|
+
|
|
537
|
+
Need one sooner, or a different framework? [Open an issue](https://github.com/asmyshlyaev177/test-proxy-recorder/issues).
|
|
538
|
+
|
|
539
|
+
---
|
|
349
540
|
|
|
350
541
|
## Requirements
|
|
351
542
|
|
|
352
|
-
- Node.js >=
|
|
543
|
+
- Node.js >= 20.0.0
|
|
353
544
|
- @playwright/test >= 1.0.0 (peer dependency)
|
|
354
545
|
|
|
546
|
+
---
|
|
547
|
+
|
|
355
548
|
## Contributing
|
|
356
549
|
|
|
357
550
|
Contributions welcome! Please submit a Pull Request.
|
|
358
551
|
|
|
552
|
+
---
|
|
553
|
+
|
|
359
554
|
## License
|
|
360
555
|
|
|
361
556
|
MIT
|
|
@@ -42,6 +42,10 @@ interface WebSocketRecording {
|
|
|
42
42
|
messages: WebSocketMessage[];
|
|
43
43
|
timestamp: string;
|
|
44
44
|
key: string;
|
|
45
|
+
/** Client handshake headers (minus WebSocket internals like sec-websocket-key) */
|
|
46
|
+
headers?: http.IncomingHttpHeaders;
|
|
47
|
+
/** Subprotocol negotiated with the backend (from Sec-WebSocket-Protocol) */
|
|
48
|
+
protocol?: string;
|
|
45
49
|
}
|
|
46
50
|
interface RecordingSession {
|
|
47
51
|
id: string;
|
|
@@ -42,6 +42,10 @@ interface WebSocketRecording {
|
|
|
42
42
|
messages: WebSocketMessage[];
|
|
43
43
|
timestamp: string;
|
|
44
44
|
key: string;
|
|
45
|
+
/** Client handshake headers (minus WebSocket internals like sec-websocket-key) */
|
|
46
|
+
headers?: http.IncomingHttpHeaders;
|
|
47
|
+
/** Subprotocol negotiated with the backend (from Sec-WebSocket-Protocol) */
|
|
48
|
+
protocol?: string;
|
|
45
49
|
}
|
|
46
50
|
interface RecordingSession {
|
|
47
51
|
id: string;
|