test-proxy-recorder 0.3.4 → 0.3.6
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 +334 -483
- 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 +551 -445
- package/dist/index.d.cts +15 -43
- package/dist/index.d.ts +15 -43
- package/dist/index.mjs +549 -443
- package/dist/playwright/index.cjs +15 -8
- package/dist/playwright/index.d.cts +1 -1
- package/dist/playwright/index.d.ts +1 -1
- package/dist/playwright/index.mjs +15 -8
- package/dist/proxy.js +560 -450
- package/package.json +14 -12
- package/skills/nextjs-ssr/SKILL.md +377 -0
- package/skills/proxy-setup/SKILL.md +458 -0
package/README.md
CHANGED
|
@@ -3,702 +3,553 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/test-proxy-recorder)
|
|
4
4
|
[](https://github.com/asmyshlyaev177/test-proxy-recorder/blob/master/LICENSE)
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
- **Fast CI/CD Tests**: Record API responses once with real backend, replay them on CI/CD without backend
|
|
13
|
-
- **Fast Workflow**: Record real interactions with API instead of mocking every request manually
|
|
14
|
-
- **Server Side Rendering**: Can record SSR requests from JS frameworks like Next.js
|
|
15
|
-
- **Deterministic Tests**: Same responses every time, no flaky network issues, no need to wire up the whole Backend API for testing
|
|
16
|
-
- **WebSocket Support**: Records and replays WebSocket connections
|
|
17
|
-
|
|
18
|
-
## Table of Contents
|
|
10
|
+
```text
|
|
11
|
+
Record mode Replay mode
|
|
19
12
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- [Control Endpoint](#control-endpoint)
|
|
26
|
-
- [Typical Workflow](#typical-workflow)
|
|
27
|
-
- [Recording Format](#recording-format)
|
|
28
|
-
- [Troubleshooting](#troubleshooting)
|
|
29
|
-
- [API Reference](#api-reference)
|
|
13
|
+
Browser/App ──> Proxy ──> Real API Browser/App ──> Proxy ──> Disk
|
|
14
|
+
│ │
|
|
15
|
+
└──> saves to disk └──> serves saved responses
|
|
16
|
+
(.mock.json) (.mock.json)
|
|
17
|
+
```
|
|
30
18
|
|
|
31
|
-
|
|
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 |
|
|
32
23
|
|
|
33
|
-
|
|
24
|
+
Both can be used together or independently.
|
|
34
25
|
|
|
35
|
-
|
|
26
|
+
```text
|
|
27
|
+
Server-side (proxy) Browser-side (HAR)
|
|
36
28
|
|
|
37
|
-
|
|
29
|
+
Next.js SSR ──> Proxy ──> Real API Browser ──> HAR intercept ──> Real API
|
|
30
|
+
│ │
|
|
31
|
+
└──> .mock.json └──> .har
|
|
32
|
+
```
|
|
38
33
|
|
|
39
|
-
|
|
34
|
+
## Contents
|
|
40
35
|
|
|
41
|
-
|
|
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)
|
|
42
52
|
|
|
43
|
-
|
|
53
|
+
---
|
|
44
54
|
|
|
45
|
-
|
|
55
|
+
## Why
|
|
46
56
|
|
|
47
|
-
|
|
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
|
|
48
63
|
|
|
49
|
-
|
|
64
|
+
---
|
|
50
65
|
|
|
51
|
-
|
|
52
|
-
npm install --save-dev test-proxy-recorder
|
|
53
|
-
```
|
|
66
|
+
## Full-stack (SSR + browser) Quick Start
|
|
54
67
|
|
|
55
|
-
|
|
68
|
+
For apps like Next.js where both the server AND the browser make API calls, use both mechanisms together.
|
|
56
69
|
|
|
57
|
-
Add to `package.json
|
|
70
|
+
### 1. Add scripts to `package.json`
|
|
58
71
|
|
|
59
72
|
```json
|
|
60
73
|
{
|
|
61
74
|
"scripts": {
|
|
62
|
-
"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\""
|
|
63
78
|
}
|
|
64
79
|
}
|
|
65
80
|
```
|
|
66
81
|
|
|
67
|
-
|
|
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`).
|
|
83
|
+
>
|
|
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.
|
|
68
85
|
|
|
69
|
-
|
|
70
|
-
npm install --save-dev concurrently
|
|
71
|
-
```
|
|
86
|
+
### 2. Write a test
|
|
72
87
|
|
|
73
|
-
```
|
|
74
|
-
{
|
|
75
|
-
|
|
76
|
-
"proxy": "test-proxy-recorder http://localhost:8000 --port 8100 --dir ./e2e/recordings",
|
|
77
|
-
"dev:proxy": "concurrently -n \"proxy,app\" -c \"blue,green\" \"npm run proxy\" \"INTERNAL_API_URL=http://localhost:8100 npm run dev\""
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
```
|
|
88
|
+
```typescript
|
|
89
|
+
import { test, expect } from '@playwright/test';
|
|
90
|
+
import { playwrightProxy } from 'test-proxy-recorder';
|
|
81
91
|
|
|
82
|
-
|
|
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/;
|
|
83
95
|
|
|
84
|
-
|
|
96
|
+
// Change to 'record' to update recordings.
|
|
97
|
+
const MODE = 'replay' as const;
|
|
85
98
|
|
|
86
|
-
|
|
99
|
+
test.beforeEach(async ({ page }, testInfo) => {
|
|
100
|
+
await playwrightProxy.before(page, testInfo, MODE, { url: CLIENT_SIDE_URL });
|
|
101
|
+
});
|
|
87
102
|
|
|
88
|
-
|
|
89
|
-
/
|
|
103
|
+
test('homepage loads', async ({ page }) => {
|
|
104
|
+
await page.goto('/');
|
|
105
|
+
await expect(page.getByText('Welcome')).toBeVisible();
|
|
106
|
+
});
|
|
90
107
|
```
|
|
91
108
|
|
|
92
|
-
|
|
109
|
+
### 3. Record
|
|
93
110
|
|
|
94
|
-
|
|
111
|
+
```bash
|
|
112
|
+
# Terminal 1
|
|
113
|
+
npm run serve:proxy
|
|
95
114
|
|
|
96
|
-
|
|
115
|
+
# Terminal 2 — .mock.json and .har files are written automatically
|
|
116
|
+
npx playwright test
|
|
117
|
+
```
|
|
97
118
|
|
|
98
|
-
###
|
|
119
|
+
### 4. Switch to replay and commit
|
|
99
120
|
|
|
100
|
-
|
|
121
|
+
```bash
|
|
122
|
+
git add e2e/recordings/
|
|
123
|
+
git commit -m "add e2e recordings"
|
|
124
|
+
```
|
|
101
125
|
|
|
102
|
-
|
|
103
|
-
import { playwrightProxy } from 'test-proxy-recorder';
|
|
126
|
+
---
|
|
104
127
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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.
|
|
108
131
|
|
|
109
|
-
|
|
132
|
+
### 1. Install
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
npm install --save-dev test-proxy-recorder
|
|
110
136
|
```
|
|
111
137
|
|
|
112
|
-
|
|
138
|
+
### 2. Add the proxy to `playwright.config.ts`
|
|
113
139
|
|
|
114
140
|
```typescript
|
|
115
141
|
import { defineConfig } from '@playwright/test';
|
|
116
142
|
|
|
117
143
|
export default defineConfig({
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
+
},
|
|
121
149
|
});
|
|
122
150
|
```
|
|
123
151
|
|
|
124
|
-
|
|
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.
|
|
125
153
|
|
|
126
|
-
|
|
154
|
+
### 3. Write a fixture
|
|
127
155
|
|
|
128
156
|
```typescript
|
|
129
|
-
|
|
157
|
+
// e2e/fixtures.ts
|
|
158
|
+
import { test as base, type Page, type BrowserContext } from '@playwright/test';
|
|
130
159
|
import { playwrightProxy } from 'test-proxy-recorder';
|
|
131
160
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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/;
|
|
136
165
|
|
|
137
|
-
|
|
138
|
-
|
|
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
|
+
},
|
|
139
175
|
});
|
|
140
176
|
```
|
|
141
177
|
|
|
142
|
-
###
|
|
143
|
-
|
|
144
|
-
**First run (record mode)**:
|
|
178
|
+
### 4. Write a test
|
|
145
179
|
|
|
146
180
|
```typescript
|
|
147
|
-
|
|
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
|
+
});
|
|
148
188
|
```
|
|
149
189
|
|
|
150
|
-
|
|
190
|
+
### 5. Record — run once against the real API
|
|
151
191
|
|
|
152
|
-
```
|
|
153
|
-
|
|
192
|
+
```bash
|
|
193
|
+
# In fixtures.ts: const MODE = 'record' as const;
|
|
194
|
+
npx playwright test
|
|
195
|
+
# .har files are written to e2e/recordings/ automatically
|
|
154
196
|
```
|
|
155
197
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
### Basic Command
|
|
198
|
+
### 6. Switch to replay and commit
|
|
159
199
|
|
|
160
200
|
```bash
|
|
161
|
-
|
|
201
|
+
# In fixtures.ts: const MODE = 'replay' as const;
|
|
202
|
+
git add e2e/recordings/
|
|
203
|
+
git commit -m "add e2e recordings"
|
|
162
204
|
```
|
|
163
205
|
|
|
164
|
-
|
|
206
|
+
CI now runs without any network access.
|
|
165
207
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
+
> ```
|
|
170
215
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
```bash
|
|
174
|
-
# Basic usage
|
|
175
|
-
test-proxy-recorder http://localhost:8000
|
|
216
|
+
---
|
|
176
217
|
|
|
177
|
-
|
|
178
|
-
test-proxy-recorder http://localhost:8000 --port 8100 --dir ./mocks
|
|
218
|
+
## CLI
|
|
179
219
|
|
|
180
|
-
|
|
181
|
-
test-proxy-recorder
|
|
220
|
+
```bash
|
|
221
|
+
test-proxy-recorder <target-url> [options]
|
|
182
222
|
```
|
|
183
223
|
|
|
184
|
-
|
|
224
|
+
| Option | Default | Description |
|
|
225
|
+
| -------------- | -------------- | ----------------------------- |
|
|
226
|
+
| `<target-url>` | *(required)* | Backend URL to proxy |
|
|
227
|
+
| `--port, -p` | `8080` | Proxy listen port |
|
|
228
|
+
| `--dir, -d` | `./recordings` | Directory for recording files |
|
|
185
229
|
|
|
186
|
-
|
|
230
|
+
```bash
|
|
231
|
+
# Examples
|
|
232
|
+
test-proxy-recorder http://localhost:8000
|
|
233
|
+
test-proxy-recorder http://localhost:8000 --port 8100 --dir ./mocks
|
|
234
|
+
```
|
|
187
235
|
|
|
188
|
-
|
|
236
|
+
---
|
|
189
237
|
|
|
190
|
-
|
|
238
|
+
## Example Apps
|
|
191
239
|
|
|
192
|
-
|
|
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.
|
|
193
241
|
|
|
194
|
-
|
|
242
|
+
### Next.js 16 — server-side (proxy / `.mock.json`)
|
|
195
243
|
|
|
196
|
-
|
|
197
|
-
import { test } from '@playwright/test';
|
|
198
|
-
import { playwrightProxy } from 'test-proxy-recorder';
|
|
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).
|
|
199
245
|
|
|
200
|
-
|
|
201
|
-
// Set mode BEFORE test actions
|
|
202
|
-
// This automatically sets the recording ID header and cleanup handler
|
|
203
|
-
await playwrightProxy.before(page, testInfo, 'replay');
|
|
246
|
+
### Chrome extension — browser-side (HAR / `.har`)
|
|
204
247
|
|
|
205
|
-
|
|
206
|
-
await page.goto('/page');
|
|
207
|
-
// Test assertions...
|
|
208
|
-
});
|
|
209
|
-
```
|
|
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).
|
|
210
249
|
|
|
211
|
-
|
|
250
|
+
---
|
|
212
251
|
|
|
213
|
-
|
|
214
|
-
import { test } from '@playwright/test';
|
|
215
|
-
import { playwrightProxy } from 'test-proxy-recorder';
|
|
252
|
+
## Playwright Integration
|
|
216
253
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
await playwrightProxy.before(page, testInfo, 'record');
|
|
254
|
+
<details>
|
|
255
|
+
<summary>Show details</summary>
|
|
220
256
|
|
|
221
|
-
|
|
222
|
-
await page.fill('[name="username"]', 'testuser');
|
|
223
|
-
await page.click('button[type="submit"]');
|
|
224
|
-
});
|
|
257
|
+
### `playwrightProxy.before(page, testInfo, mode, options?)`
|
|
225
258
|
|
|
226
|
-
|
|
227
|
-
test('create user', async ({ page }, testInfo) => {
|
|
228
|
-
await playwrightProxy.before(page, testInfo, 'replay');
|
|
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.
|
|
229
260
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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/,
|
|
233
271
|
});
|
|
234
272
|
```
|
|
235
273
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
Recording files are auto-generated from test names:
|
|
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`).
|
|
239
275
|
|
|
240
|
-
-
|
|
241
|
-
- File: `create-a-user.mock.json`
|
|
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.
|
|
242
277
|
|
|
243
|
-
|
|
278
|
+
Recording filenames are derived from test names (`"create a user"` → `create-a-user.mock.json` / `.har`).
|
|
244
279
|
|
|
245
|
-
### Global
|
|
246
|
-
|
|
247
|
-
Create `e2e/global-teardown.ts`:
|
|
280
|
+
### Global teardown (recommended)
|
|
248
281
|
|
|
249
282
|
```typescript
|
|
283
|
+
// e2e/global-teardown.ts
|
|
250
284
|
import { playwrightProxy } from 'test-proxy-recorder';
|
|
251
285
|
|
|
252
|
-
async function globalTeardown() {
|
|
286
|
+
export default async function globalTeardown() {
|
|
253
287
|
await playwrightProxy.teardown();
|
|
254
288
|
}
|
|
255
|
-
|
|
256
|
-
export default globalTeardown;
|
|
257
289
|
```
|
|
258
290
|
|
|
259
|
-
Update `playwright.config.ts`:
|
|
260
|
-
|
|
261
291
|
```typescript
|
|
262
|
-
|
|
263
|
-
|
|
292
|
+
// playwright.config.ts
|
|
264
293
|
export default defineConfig({
|
|
265
|
-
testDir: './e2e',
|
|
266
294
|
globalTeardown: './e2e/global-teardown.ts',
|
|
267
|
-
// ... rest of config
|
|
268
|
-
});
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### Client-Side Recording for 3rd Party APIs
|
|
272
|
-
|
|
273
|
-
For applications that make client-side requests to 3rd party services (e.g., AWS Cognito, Stream.io, analytics services), you can use client-side recording to capture these requests directly in the browser using Playwright's HAR (HTTP Archive) format.
|
|
274
|
-
|
|
275
|
-
**Why use client-side recording?**
|
|
276
|
-
- Server-side proxy cannot intercept requests made directly from the browser to external services
|
|
277
|
-
- HAR files are a standard format supported by Playwright and browser dev tools
|
|
278
|
-
- Automatically handles CORS and other browser-specific request behaviors
|
|
279
|
-
|
|
280
|
-
**Example:**
|
|
281
|
-
|
|
282
|
-
```typescript
|
|
283
|
-
import { test } from '@playwright/test';
|
|
284
|
-
import { playwrightProxy } from 'test-proxy-recorder';
|
|
285
|
-
|
|
286
|
-
test('authentication flow', async ({ page }, testInfo) => {
|
|
287
|
-
// Record both server-side (via proxy) and client-side (via HAR) requests
|
|
288
|
-
await playwrightProxy.before(
|
|
289
|
-
page,
|
|
290
|
-
testInfo,
|
|
291
|
-
'replay',
|
|
292
|
-
{
|
|
293
|
-
// Client-side URL pattern using Playwright's format
|
|
294
|
-
url: /cognito-.*amazonaws\.com|\.stream-io-api\.com/,
|
|
295
|
-
timeout: 60000 // Optional: custom timeout
|
|
296
|
-
}
|
|
297
|
-
);
|
|
298
|
-
|
|
299
|
-
await page.goto('/login');
|
|
300
|
-
// Cognito authentication requests are recorded to HAR files
|
|
301
|
-
await page.fill('[name="email"]', 'user@example.com');
|
|
302
|
-
await page.click('button[type="submit"]');
|
|
303
295
|
});
|
|
304
296
|
```
|
|
305
297
|
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
// RegExp pattern (recommended for multiple domains)
|
|
309
|
-
{ url: /cognito-.*amazonaws\.com|\.stream-io-api\.com/ }
|
|
310
|
-
|
|
311
|
-
// String glob pattern
|
|
312
|
-
{ url: 'https://api.example.com/**' }
|
|
298
|
+
### Recording files
|
|
313
299
|
|
|
314
|
-
|
|
315
|
-
{ url: /api\.external-service\.com/ }
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
**Storage:**
|
|
319
|
-
Client-side recordings are stored as HAR files alongside server-side recordings:
|
|
320
|
-
```
|
|
300
|
+
```text
|
|
321
301
|
e2e/recordings/
|
|
322
|
-
|
|
323
|
-
|
|
302
|
+
my-test.mock.json # server-side (proxy) — SSR fetches
|
|
303
|
+
my-test.har # client-side (HAR) — browser fetches
|
|
324
304
|
```
|
|
325
305
|
|
|
326
|
-
|
|
327
|
-
- **Record mode**: Creates/updates HAR file with actual responses from 3rd party services
|
|
328
|
-
- **Replay mode**: Uses recorded HAR file, no network requests made to 3rd party services
|
|
306
|
+
</details>
|
|
329
307
|
|
|
330
|
-
|
|
308
|
+
---
|
|
331
309
|
|
|
332
310
|
## Next.js Integration
|
|
333
311
|
|
|
334
|
-
|
|
312
|
+
<details>
|
|
313
|
+
<summary>Show details</summary>
|
|
335
314
|
|
|
336
|
-
|
|
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.
|
|
337
316
|
|
|
338
|
-
|
|
317
|
+
For SSR requests to carry this header, use one of:
|
|
318
|
+
|
|
319
|
+
### Middleware (recommended)
|
|
339
320
|
|
|
340
321
|
```typescript
|
|
322
|
+
// middleware.ts
|
|
341
323
|
import { NextResponse } from 'next/server';
|
|
342
324
|
import type { NextRequest } from 'next/server';
|
|
343
325
|
import { setNextProxyHeaders } from 'test-proxy-recorder/nextjs';
|
|
344
326
|
|
|
345
327
|
export function middleware(request: NextRequest) {
|
|
346
328
|
const response = NextResponse.next();
|
|
347
|
-
|
|
348
|
-
// Forward the recording ID header during tests
|
|
349
|
-
// Only runs in non-production or when TEST_PROXY_RECORDER_ENABLED=true
|
|
350
|
-
setNextProxyHeaders(request, response);
|
|
351
|
-
|
|
329
|
+
setNextProxyHeaders(request, response); // no-op in production
|
|
352
330
|
return response;
|
|
353
331
|
}
|
|
354
332
|
```
|
|
355
333
|
|
|
356
|
-
|
|
357
|
-
- Automatically skipped when `NODE_ENV=production`
|
|
358
|
-
- Can be explicitly enabled in production with `TEST_PROXY_RECORDER_ENABLED=true`
|
|
359
|
-
|
|
360
|
-
### Option 2: Manual Header Forwarding in API Routes
|
|
361
|
-
|
|
362
|
-
For API routes or server components, manually include the header in fetch requests:
|
|
334
|
+
### Manual header forwarding
|
|
363
335
|
|
|
364
336
|
```typescript
|
|
365
|
-
// app/api/data/route.ts
|
|
366
337
|
import { headers } from 'next/headers';
|
|
367
338
|
import { createHeadersWithRecordingId } from 'test-proxy-recorder/nextjs';
|
|
368
339
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
'Content-Type': 'application/json',
|
|
375
|
-
})
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
return Response.json(await response.json());
|
|
379
|
-
}
|
|
340
|
+
const res = await fetch('http://localhost:8100/api/data', {
|
|
341
|
+
headers: createHeadersWithRecordingId(await headers(), {
|
|
342
|
+
'Content-Type': 'application/json',
|
|
343
|
+
}),
|
|
344
|
+
});
|
|
380
345
|
```
|
|
381
346
|
|
|
382
|
-
|
|
347
|
+
</details>
|
|
383
348
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
```typescript
|
|
387
|
-
import { headers } from 'next/headers';
|
|
388
|
-
import { getRecordingId, RECORDING_ID_HEADER } from 'test-proxy-recorder/nextjs';
|
|
389
|
-
|
|
390
|
-
export async function GET() {
|
|
391
|
-
const recordingId = getRecordingId(await headers());
|
|
392
|
-
|
|
393
|
-
const response = await fetch('http://localhost:8100/api/data', {
|
|
394
|
-
headers: {
|
|
395
|
-
'Content-Type': 'application/json',
|
|
396
|
-
...(recordingId && { [RECORDING_ID_HEADER]: recordingId })
|
|
397
|
-
}
|
|
398
|
-
});
|
|
399
|
-
|
|
400
|
-
return Response.json(await response.json());
|
|
401
|
-
}
|
|
402
|
-
```
|
|
349
|
+
---
|
|
403
350
|
|
|
404
351
|
## Control Endpoint
|
|
405
352
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
### GET - Retrieve Proxy Configuration
|
|
353
|
+
<details>
|
|
354
|
+
<summary>Show details</summary>
|
|
409
355
|
|
|
410
|
-
|
|
356
|
+
The proxy exposes `/__control` for programmatic mode switching.
|
|
411
357
|
|
|
412
|
-
**Via HTTP:**
|
|
413
358
|
```bash
|
|
359
|
+
# Get current state
|
|
414
360
|
curl http://localhost:8100/__control
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
**Response:**
|
|
418
|
-
```json
|
|
419
|
-
{
|
|
420
|
-
"recordingsDir": "/path/to/e2e/recordings",
|
|
421
|
-
"mode": "replay",
|
|
422
|
-
"id": "my-test-1"
|
|
423
|
-
}
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
**Via JavaScript:**
|
|
427
|
-
```javascript
|
|
428
|
-
const config = await fetch('http://localhost:8100/__control').then(r => r.json());
|
|
429
|
-
console.log(config.recordingsDir); // "/path/to/e2e/recordings"
|
|
430
|
-
console.log(config.mode); // "replay"
|
|
431
|
-
console.log(config.id); // "my-test-1"
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
### POST - Switch Proxy Mode
|
|
435
|
-
|
|
436
|
-
**Via HTTP:**
|
|
437
|
-
```bash
|
|
438
|
-
# Switch to record mode
|
|
439
|
-
curl -X POST http://localhost:8100/__control \
|
|
440
|
-
-H "Content-Type: application/json" \
|
|
441
|
-
-d '{"mode": "record", "id": "my-test-1", "timeout": 30000}'
|
|
442
|
-
|
|
443
|
-
# Switch to replay mode
|
|
444
|
-
curl -X POST http://localhost:8100/__control \
|
|
445
|
-
-H "Content-Type: application/json" \
|
|
446
|
-
-d '{"mode": "replay", "id": "my-test-1"}'
|
|
447
361
|
|
|
448
|
-
# Switch
|
|
362
|
+
# Switch modes
|
|
449
363
|
curl -X POST http://localhost:8100/__control \
|
|
450
364
|
-H "Content-Type: application/json" \
|
|
451
|
-
-d '{"mode": "
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
**Via JavaScript:**
|
|
455
|
-
```javascript
|
|
456
|
-
await fetch('http://localhost:8100/__control', {
|
|
457
|
-
method: 'POST',
|
|
458
|
-
headers: { 'Content-Type': 'application/json' },
|
|
459
|
-
body: JSON.stringify({
|
|
460
|
-
mode: 'record',
|
|
461
|
-
id: 'my-test-1',
|
|
462
|
-
timeout: 30000 // Optional: auto-reset after 30s
|
|
463
|
-
})
|
|
464
|
-
});
|
|
365
|
+
-d '{"mode": "record", "id": "my-test-1"}'
|
|
465
366
|
```
|
|
466
367
|
|
|
467
|
-
### Control Request Interface
|
|
468
|
-
|
|
469
368
|
```typescript
|
|
470
369
|
interface ControlRequest {
|
|
471
370
|
mode: 'transparent' | 'record' | 'replay';
|
|
472
|
-
id?: string;
|
|
473
|
-
timeout?: number;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
interface ControlResponse {
|
|
477
|
-
recordingsDir: string;
|
|
478
|
-
mode: string;
|
|
479
|
-
id?: string;
|
|
371
|
+
id?: string; // required for record/replay
|
|
372
|
+
timeout?: number; // auto-reset timeout in ms (default: 120000)
|
|
480
373
|
}
|
|
481
374
|
```
|
|
482
375
|
|
|
483
|
-
|
|
376
|
+
</details>
|
|
484
377
|
|
|
485
|
-
|
|
378
|
+
---
|
|
486
379
|
|
|
487
|
-
|
|
488
|
-
2. Start proxy and app: `npm run dev:proxy`
|
|
489
|
-
3. Set test to `'record'` mode
|
|
490
|
-
4. Run test: Recordings saved to `./e2e/recordings/` (directory created automatically)
|
|
491
|
-
5. Commit `.mock.json` files to git
|
|
492
|
-
6. Change mode to `'replay'`
|
|
380
|
+
## API Reference
|
|
493
381
|
|
|
494
|
-
|
|
382
|
+
<details>
|
|
383
|
+
<summary>Show details</summary>
|
|
495
384
|
|
|
496
|
-
|
|
497
|
-
2. Set test to `'replay'` mode
|
|
498
|
-
3. Run test: Uses recorded responses
|
|
499
|
-
4. Tests run fast without backend
|
|
385
|
+
### `playwrightProxy`
|
|
500
386
|
|
|
501
|
-
|
|
387
|
+
```typescript
|
|
388
|
+
const playwrightProxy: {
|
|
389
|
+
before(
|
|
390
|
+
page: Page,
|
|
391
|
+
testInfo: TestInfo,
|
|
392
|
+
mode: 'record' | 'replay' | 'transparent',
|
|
393
|
+
options?: { url?: string | RegExp; timeout?: number }
|
|
394
|
+
): Promise<void>;
|
|
502
395
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
4. Commit updated `.mock.json` file
|
|
396
|
+
teardown(): Promise<void>;
|
|
397
|
+
};
|
|
398
|
+
```
|
|
507
399
|
|
|
508
|
-
|
|
400
|
+
### `setProxyMode`
|
|
509
401
|
|
|
510
|
-
|
|
402
|
+
```typescript
|
|
403
|
+
function setProxyMode(
|
|
404
|
+
mode: 'record' | 'replay' | 'transparent',
|
|
405
|
+
id?: string,
|
|
406
|
+
timeout?: number
|
|
407
|
+
): Promise<void>;
|
|
408
|
+
```
|
|
511
409
|
|
|
512
|
-
|
|
513
|
-
**Client-side recordings** (via HAR): HTTP Archive files with `.har` extension
|
|
410
|
+
### Next.js helpers (`test-proxy-recorder/nextjs`)
|
|
514
411
|
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
412
|
+
```typescript
|
|
413
|
+
function setNextProxyHeaders(request: NextRequest, response: NextResponse): void;
|
|
414
|
+
function getRecordingId(headers: NextRequest | Headers): string | null;
|
|
415
|
+
function createHeadersWithRecordingId(
|
|
416
|
+
headers: NextRequest | Headers,
|
|
417
|
+
additional?: Record<string, string>
|
|
418
|
+
): Record<string, string>;
|
|
521
419
|
```
|
|
522
420
|
|
|
523
|
-
|
|
421
|
+
</details>
|
|
524
422
|
|
|
525
|
-
|
|
423
|
+
---
|
|
526
424
|
|
|
527
|
-
|
|
425
|
+
## Next.js 16
|
|
528
426
|
|
|
529
|
-
|
|
427
|
+
<details>
|
|
428
|
+
<summary>Show details</summary>
|
|
530
429
|
|
|
531
|
-
|
|
532
|
-
|
|
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`:
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
// proxy.ts (Next.js 16 middleware convention)
|
|
434
|
+
import { NextResponse } from 'next/server';
|
|
435
|
+
import type { NextRequest } from 'next/server';
|
|
436
|
+
import { setNextProxyHeaders } from 'test-proxy-recorder/nextjs';
|
|
437
|
+
|
|
438
|
+
export function proxy(request: NextRequest) {
|
|
439
|
+
const response = NextResponse.next();
|
|
440
|
+
setNextProxyHeaders(request, response);
|
|
441
|
+
return response;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
export const config = {
|
|
445
|
+
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
446
|
+
};
|
|
533
447
|
```
|
|
534
448
|
|
|
535
|
-
**
|
|
449
|
+
**package.json scripts** — start services from scripts, not from `playwright.config.ts`:
|
|
536
450
|
|
|
537
|
-
```
|
|
538
|
-
|
|
451
|
+
```json
|
|
452
|
+
{
|
|
453
|
+
"scripts": {
|
|
454
|
+
"mock": "node mock-backend/server.mjs",
|
|
455
|
+
"proxy": "test-proxy-recorder http://localhost:3002 -p 8100 -d ./e2e/recordings",
|
|
456
|
+
"start:all": "concurrently \"pnpm mock\" \"pnpm proxy\" \"pnpm build && next start --port 3000\""
|
|
457
|
+
}
|
|
458
|
+
}
|
|
539
459
|
```
|
|
540
460
|
|
|
541
|
-
|
|
461
|
+
</details>
|
|
542
462
|
|
|
543
|
-
|
|
544
|
-
- Check app is using proxy URL (`http://localhost:8100`)
|
|
545
|
-
- Verify write permissions on recordings directory
|
|
546
|
-
- Check proxy server logs for errors
|
|
463
|
+
---
|
|
547
464
|
|
|
548
|
-
|
|
465
|
+
## FAQ
|
|
549
466
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
- Verify recording file matches expected format
|
|
553
|
-
- Re-record if API responses changed
|
|
467
|
+
<details>
|
|
468
|
+
<summary><strong>My parallel replay tests sometimes hit the real backend — why?</strong></summary>
|
|
554
469
|
|
|
555
|
-
|
|
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.
|
|
556
471
|
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
472
|
+
```typescript
|
|
473
|
+
// ❌ breaks parallel replay — teardown() affects all sessions globally
|
|
474
|
+
test.afterAll(async () => {
|
|
475
|
+
await playwrightProxy.teardown();
|
|
476
|
+
});
|
|
477
|
+
```
|
|
561
478
|
|
|
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.
|
|
562
480
|
|
|
563
|
-
|
|
481
|
+
</details>
|
|
564
482
|
|
|
565
|
-
|
|
483
|
+
<details>
|
|
484
|
+
<summary><strong>Should I commit recordings to git?</strong></summary>
|
|
566
485
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
listen(port: number): http.Server;
|
|
572
|
-
}
|
|
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`:
|
|
487
|
+
|
|
488
|
+
```text
|
|
489
|
+
/e2e/recordings/** binary
|
|
573
490
|
```
|
|
574
491
|
|
|
575
|
-
|
|
492
|
+
</details>
|
|
576
493
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
import type { Page } from '@playwright/test';
|
|
580
|
-
|
|
581
|
-
// Client-side recording options
|
|
582
|
-
interface ClientSideRecordingOptions {
|
|
583
|
-
/**
|
|
584
|
-
* URL pattern for client-side requests to record/replay
|
|
585
|
-
* Uses Playwright's native format (string or RegExp)
|
|
586
|
-
* Example: /cognito-.*amazonaws\.com|\.stream-io-api\.com/
|
|
587
|
-
* Example: 'https://api.example.com/**'
|
|
588
|
-
*/
|
|
589
|
-
url?: string | RegExp;
|
|
590
|
-
}
|
|
494
|
+
<details>
|
|
495
|
+
<summary><strong>Does the proxy <code><target-url></code> matter for browser-only (HAR) recording?</strong></summary>
|
|
591
496
|
|
|
592
|
-
|
|
593
|
-
const playwrightProxy = {
|
|
594
|
-
// Set proxy mode before test and configure page with recording ID header
|
|
595
|
-
// Supports optional client-side recording for 3rd party APIs
|
|
596
|
-
async before(
|
|
597
|
-
page: Page,
|
|
598
|
-
testInfo: TestInfo,
|
|
599
|
-
mode: 'record' | 'replay' | 'transparent',
|
|
600
|
-
options?: number | (ClientSideRecordingOptions & { timeout?: number })
|
|
601
|
-
): Promise<void>;
|
|
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.
|
|
602
498
|
|
|
603
|
-
|
|
604
|
-
// Use in Playwright's globalTeardown configuration
|
|
605
|
-
async teardown(): Promise<void>;
|
|
606
|
-
};
|
|
499
|
+
</details>
|
|
607
500
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
mode: 'record' | 'replay' | 'transparent',
|
|
611
|
-
id?: string,
|
|
612
|
-
timeout?: number
|
|
613
|
-
): Promise<void>;
|
|
501
|
+
<details>
|
|
502
|
+
<summary><strong>Can I record against the Next.js dev server?</strong></summary>
|
|
614
503
|
|
|
615
|
-
|
|
616
|
-
const RECORDING_ID_HEADER: string; // 'x-test-rcrd-id'
|
|
617
|
-
```
|
|
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.
|
|
618
505
|
|
|
619
|
-
|
|
620
|
-
- `number` - Legacy format: timeout in milliseconds
|
|
621
|
-
- `ClientSideRecordingOptions & { timeout?: number }` - Object with optional client-side recording and timeout:
|
|
622
|
-
- `url?: string | RegExp` - URL pattern for client-side recording (uses Playwright's HAR format)
|
|
623
|
-
- `timeout?: number` - Auto-reset timeout in milliseconds
|
|
506
|
+
</details>
|
|
624
507
|
|
|
625
|
-
|
|
508
|
+
<details>
|
|
509
|
+
<summary><strong>How do I update a recording?</strong></summary>
|
|
626
510
|
|
|
627
|
-
|
|
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/`.
|
|
628
512
|
|
|
629
|
-
|
|
630
|
-
import {
|
|
631
|
-
setNextProxyHeaders,
|
|
632
|
-
getRecordingId,
|
|
633
|
-
createHeadersWithRecordingId,
|
|
634
|
-
RECORDING_ID_HEADER
|
|
635
|
-
} from 'test-proxy-recorder/nextjs';
|
|
636
|
-
import type { NextRequest, NextResponse } from 'next/server';
|
|
637
|
-
|
|
638
|
-
// Forward recording ID header in Next.js middleware
|
|
639
|
-
// Automatically skipped in production unless TEST_PROXY_RECORDER_ENABLED=true
|
|
640
|
-
function setNextProxyHeaders(
|
|
641
|
-
request: NextRequest,
|
|
642
|
-
response: NextResponse
|
|
643
|
-
): void;
|
|
644
|
-
|
|
645
|
-
// Get recording ID from request headers
|
|
646
|
-
function getRecordingId(
|
|
647
|
-
requestHeaders: NextRequest | Headers
|
|
648
|
-
): string | null;
|
|
649
|
-
|
|
650
|
-
// Create headers object with recording ID for fetch requests
|
|
651
|
-
function createHeadersWithRecordingId(
|
|
652
|
-
requestHeaders: NextRequest | Headers,
|
|
653
|
-
additionalHeaders?: Record<string, string>
|
|
654
|
-
): Record<string, string>;
|
|
655
|
-
```
|
|
513
|
+
</details>
|
|
656
514
|
|
|
657
|
-
|
|
515
|
+
---
|
|
658
516
|
|
|
659
|
-
|
|
517
|
+
## AI Agent Skills
|
|
660
518
|
|
|
661
|
-
|
|
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:
|
|
662
520
|
|
|
663
|
-
```
|
|
664
|
-
|
|
665
|
-
{
|
|
666
|
-
recordingsDir: string; // Path to recordings directory
|
|
667
|
-
mode: string; // Current mode: 'transparent' | 'record' | 'replay'
|
|
668
|
-
id?: string; // Active recording/replay session ID
|
|
669
|
-
}
|
|
521
|
+
```bash
|
|
522
|
+
npx @tanstack/intent@latest install
|
|
670
523
|
```
|
|
671
524
|
|
|
672
|
-
|
|
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.
|
|
673
526
|
|
|
674
|
-
|
|
675
|
-
// Request Body
|
|
676
|
-
{
|
|
677
|
-
mode: 'transparent' | 'record' | 'replay';
|
|
678
|
-
id?: string; // Recording ID (required for record/replay)
|
|
679
|
-
timeout?: number; // Auto-reset timeout in ms (default: 120000)
|
|
680
|
-
}
|
|
527
|
+
---
|
|
681
528
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
}
|
|
690
|
-
```
|
|
529
|
+
## Roadmap
|
|
530
|
+
|
|
531
|
+
First-class integrations on the way:
|
|
532
|
+
|
|
533
|
+
- **TanStack Start**
|
|
534
|
+
- **Remix**
|
|
535
|
+
- **Vite + SSR**
|
|
691
536
|
|
|
692
|
-
|
|
537
|
+
Need one sooner, or a different framework? [Open an issue](https://github.com/asmyshlyaev177/test-proxy-recorder/issues).
|
|
538
|
+
|
|
539
|
+
---
|
|
693
540
|
|
|
694
541
|
## Requirements
|
|
695
542
|
|
|
696
|
-
- Node.js >=
|
|
697
|
-
- @playwright/test >= 1.0.0 (
|
|
543
|
+
- Node.js >= 20.0.0
|
|
544
|
+
- @playwright/test >= 1.0.0 (peer dependency)
|
|
545
|
+
|
|
546
|
+
---
|
|
698
547
|
|
|
699
548
|
## Contributing
|
|
700
549
|
|
|
701
|
-
Contributions
|
|
550
|
+
Contributions welcome! Please submit a Pull Request.
|
|
551
|
+
|
|
552
|
+
---
|
|
702
553
|
|
|
703
554
|
## License
|
|
704
555
|
|