test-proxy-recorder 0.1.5 → 0.1.7
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 -207
- package/dist/index.cjs +205 -62
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.mjs +205 -62
- package/dist/proxy.js +205 -62
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -9,328 +9,455 @@ HTTP proxy server for recording and replaying network requests in testing. Works
|
|
|
9
9
|
|
|
10
10
|
## Features
|
|
11
11
|
|
|
12
|
-
- **Fast CI/CD Tests**: Record API responses once with real backend, replay them on CI/CD
|
|
13
|
-
- **Fast
|
|
14
|
-
- **Server Side Rendering**: Can record SSR requests from JS frameworks like
|
|
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
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
|
|
16
17
|
|
|
17
|
-
##
|
|
18
|
+
## Table of Contents
|
|
19
|
+
|
|
20
|
+
- [How It Works](#how-it-works)
|
|
21
|
+
- [Complete Setup Guide](#complete-setup-guide)
|
|
22
|
+
- [CLI Usage](#cli-usage)
|
|
23
|
+
- [Playwright Integration](#playwright-integration)
|
|
24
|
+
- [Control Endpoint](#control-endpoint)
|
|
25
|
+
- [Typical Workflow](#typical-workflow)
|
|
26
|
+
- [Recording Format](#recording-format)
|
|
27
|
+
- [Troubleshooting](#troubleshooting)
|
|
28
|
+
- [API Reference](#api-reference)
|
|
29
|
+
|
|
30
|
+
## How It Works
|
|
31
|
+
|
|
32
|
+
The proxy server runs continuously and can switch between three modes per test:
|
|
33
|
+
|
|
34
|
+
### 1. Transparent Mode (Default)
|
|
35
|
+
|
|
36
|
+
Passes requests through to the backend without recording or replaying.
|
|
37
|
+
|
|
38
|
+
### 2. Record Mode
|
|
39
|
+
|
|
40
|
+
Captures all HTTP requests/responses and WebSocket messages to disk. Each test gets its own recording file based on the test name.
|
|
41
|
+
|
|
42
|
+
### 3. Replay Mode
|
|
43
|
+
|
|
44
|
+
Replays previously recorded responses from disk instead of hitting the real API. Perfect for fast, deterministic tests.
|
|
45
|
+
|
|
46
|
+
## Complete Setup Guide
|
|
47
|
+
|
|
48
|
+
### Step 1: Install Package
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install --save-dev test-proxy-recorder
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Step 2: Add NPM Scripts
|
|
55
|
+
|
|
56
|
+
Add to `package.json`:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"scripts": {
|
|
61
|
+
"proxy": "test-proxy-recorder http://localhost:8000 --port 8100 --recordings-dir ./e2e/recordings"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**RECOMMENDED**: Use `concurrently` to run proxy and app together:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm install --save-dev concurrently
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"scripts": {
|
|
75
|
+
"proxy": "test-proxy-recorder http://localhost:8000 --port 8100 --recordings-dir ./e2e/recordings",
|
|
76
|
+
"dev:proxy": "concurrently -n \"proxy,app\" -c \"blue,green\" \"npm run proxy\" \"INTERNAL_API_URL=http://localhost:8100 npm run dev\""
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Step 3: Configure Git for Recordings
|
|
82
|
+
|
|
83
|
+
**CRITICAL**: Recordings must be committed to git for CI/CD replay.
|
|
84
|
+
|
|
85
|
+
Create or update your `.gitattributes` file:
|
|
86
|
+
|
|
87
|
+
```gitattributes
|
|
88
|
+
/e2e/recordings/** binary
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
This marks recording files as binary, which causes long mock files to be collapsed/folded in Pull Request diffs for better readability.
|
|
92
|
+
|
|
93
|
+
**DO NOT** add `e2e/recordings` to `.gitignore`. Recordings need to be versioned in git for CI/CD to use them.
|
|
94
|
+
|
|
95
|
+
**Note**: The recordings directory will be created automatically when you first record a test - no need to create it manually.
|
|
96
|
+
|
|
97
|
+
### Step 4: Create Playwright Global Teardown (Recommended)
|
|
98
|
+
|
|
99
|
+
Create `e2e/global-teardown.ts`:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { setProxyMode } from 'test-proxy-recorder';
|
|
103
|
+
|
|
104
|
+
async function globalTeardown() {
|
|
105
|
+
await setProxyMode('transparent');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export default globalTeardown;
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Update `playwright.config.ts`:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { defineConfig } from '@playwright/test';
|
|
115
|
+
|
|
116
|
+
export default defineConfig({
|
|
117
|
+
testDir: './e2e',
|
|
118
|
+
globalTeardown: './e2e/global-teardown.ts',
|
|
119
|
+
// ... rest of config
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Step 5: Create Example Test
|
|
124
|
+
|
|
125
|
+
Create `e2e/example.spec.ts`:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { test, expect } from '@playwright/test';
|
|
129
|
+
import { playwrightProxy } from 'test-proxy-recorder';
|
|
130
|
+
|
|
131
|
+
test('example test with proxy', async ({ page }, testInfo) => {
|
|
132
|
+
// Set proxy mode: 'record' to capture, 'replay' to use recordings
|
|
133
|
+
await playwrightProxy.before(testInfo, 'replay');
|
|
134
|
+
|
|
135
|
+
await page.goto('/');
|
|
136
|
+
await expect(page.getByText('Welcome')).toBeVisible();
|
|
137
|
+
|
|
138
|
+
// Always cleanup after test
|
|
139
|
+
await playwrightProxy.after(testInfo);
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Step 6: Run Tests
|
|
144
|
+
|
|
145
|
+
**First run (record mode)**:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
await playwrightProxy.before(testInfo, 'record');
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Subsequent runs (replay mode)**:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
await playwrightProxy.before(testInfo, 'replay');
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## CLI Usage
|
|
158
|
+
|
|
159
|
+
### Basic Command
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
test-proxy-recorder <target-url> [options]
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### CLI Options
|
|
166
|
+
|
|
167
|
+
- `<target-url>` - Backend API URL (positional argument, required)
|
|
168
|
+
- `--port, -p <number>` - Port to listen on (default: 8080)
|
|
169
|
+
- `--recordings-dir, -r <path>` - Directory to store recordings (default: ./recordings)
|
|
170
|
+
- `--help, -h` - Show help
|
|
171
|
+
|
|
172
|
+
### Examples
|
|
18
173
|
|
|
19
174
|
```bash
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
#
|
|
24
|
-
|
|
175
|
+
# Basic usage
|
|
176
|
+
test-proxy-recorder http://localhost:8000
|
|
177
|
+
|
|
178
|
+
# Custom port and recordings directory
|
|
179
|
+
test-proxy-recorder http://localhost:8000 --port 8100 --recordings-dir ./mocks
|
|
180
|
+
|
|
181
|
+
# Multiple targets (experimental)
|
|
182
|
+
test-proxy-recorder http://localhost:8000 http://localhost:9000 --port 8100
|
|
25
183
|
```
|
|
26
184
|
|
|
27
|
-
##
|
|
185
|
+
## Playwright Integration
|
|
28
186
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
187
|
+
### Basic Test Structure
|
|
188
|
+
|
|
189
|
+
Every test using the proxy should follow this pattern:
|
|
32
190
|
|
|
33
191
|
```typescript
|
|
34
192
|
import { test } from '@playwright/test';
|
|
35
193
|
import { playwrightProxy } from 'test-proxy-recorder';
|
|
36
194
|
|
|
37
|
-
test('
|
|
38
|
-
// Set
|
|
195
|
+
test('test name', async ({ page }, testInfo) => {
|
|
196
|
+
// 1. Set mode BEFORE test actions
|
|
197
|
+
await playwrightProxy.before(testInfo, 'replay');
|
|
198
|
+
|
|
199
|
+
// 2. Test code
|
|
200
|
+
await page.goto('/page');
|
|
201
|
+
|
|
202
|
+
// 3. Reset mode AFTER test completes
|
|
203
|
+
await playwrightProxy.after(testInfo);
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Recording vs Replay
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
// Recording mode - captures API responses
|
|
211
|
+
test('create user', async ({ page }, testInfo) => {
|
|
39
212
|
await playwrightProxy.before(testInfo, 'record');
|
|
40
213
|
|
|
41
|
-
|
|
42
|
-
await page.
|
|
43
|
-
|
|
214
|
+
await page.goto('/users/new');
|
|
215
|
+
await page.fill('[name="username"]', 'testuser');
|
|
216
|
+
await page.click('button[type="submit"]');
|
|
44
217
|
|
|
45
|
-
// Save mock and return to transparent mode
|
|
46
218
|
await playwrightProxy.after(testInfo);
|
|
47
219
|
});
|
|
48
220
|
|
|
49
|
-
|
|
50
|
-
|
|
221
|
+
// Replay mode - uses recorded responses
|
|
222
|
+
test('create user', async ({ page }, testInfo) => {
|
|
51
223
|
await playwrightProxy.before(testInfo, 'replay');
|
|
52
224
|
|
|
53
|
-
await page.goto('/
|
|
54
|
-
|
|
225
|
+
await page.goto('/users/new');
|
|
226
|
+
await page.fill('[name="username"]', 'testuser');
|
|
227
|
+
await page.click('button[type="submit"]');
|
|
55
228
|
|
|
56
229
|
await playwrightProxy.after(testInfo);
|
|
57
230
|
});
|
|
58
231
|
```
|
|
59
232
|
|
|
60
|
-
|
|
233
|
+
### Test Naming
|
|
61
234
|
|
|
62
|
-
|
|
235
|
+
Recording files are auto-generated from test names:
|
|
63
236
|
|
|
64
|
-
|
|
237
|
+
- Test: `"create a user"`
|
|
238
|
+
- File: `create-a-user.mock.json`
|
|
65
239
|
|
|
66
|
-
|
|
240
|
+
**Important**: Keep test names stable for replay to work correctly.
|
|
67
241
|
|
|
68
|
-
###
|
|
242
|
+
### Global Teardown (Recommended)
|
|
69
243
|
|
|
70
|
-
|
|
244
|
+
Create `e2e/global-teardown.ts`:
|
|
71
245
|
|
|
72
|
-
|
|
246
|
+
```typescript
|
|
247
|
+
import { setProxyMode } from 'test-proxy-recorder';
|
|
73
248
|
|
|
74
|
-
|
|
249
|
+
async function globalTeardown() {
|
|
250
|
+
await setProxyMode('transparent');
|
|
251
|
+
}
|
|
75
252
|
|
|
76
|
-
|
|
253
|
+
export default globalTeardown;
|
|
254
|
+
```
|
|
77
255
|
|
|
78
|
-
|
|
256
|
+
Update `playwright.config.ts`:
|
|
79
257
|
|
|
80
258
|
```typescript
|
|
81
|
-
|
|
82
|
-
await playwrightProxy.before(testInfo, 'recording');
|
|
83
|
-
// ... test code ...
|
|
84
|
-
await playwrightProxy.after(testInfo);
|
|
259
|
+
import { defineConfig } from '@playwright/test';
|
|
85
260
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
261
|
+
export default defineConfig({
|
|
262
|
+
testDir: './e2e',
|
|
263
|
+
globalTeardown: './e2e/global-teardown.ts',
|
|
264
|
+
// ... rest of config
|
|
265
|
+
});
|
|
90
266
|
```
|
|
91
267
|
|
|
92
|
-
|
|
268
|
+
## Control Endpoint
|
|
93
269
|
|
|
94
|
-
|
|
270
|
+
The proxy exposes a control endpoint at `/__control` for programmatic mode switching.
|
|
271
|
+
|
|
272
|
+
### Via HTTP
|
|
95
273
|
|
|
96
274
|
```bash
|
|
97
275
|
# Switch to record mode
|
|
98
276
|
curl -X POST http://localhost:8100/__control \
|
|
99
277
|
-H "Content-Type: application/json" \
|
|
100
|
-
-d '{"mode": "record", "id": "my-
|
|
278
|
+
-d '{"mode": "record", "id": "my-test-1", "timeout": 30000}'
|
|
101
279
|
|
|
102
280
|
# Switch to replay mode
|
|
103
281
|
curl -X POST http://localhost:8100/__control \
|
|
104
282
|
-H "Content-Type: application/json" \
|
|
105
|
-
-d '{"mode": "replay", "id": "my-
|
|
283
|
+
-d '{"mode": "replay", "id": "my-test-1"}'
|
|
106
284
|
|
|
107
285
|
# Switch to transparent mode
|
|
108
286
|
curl -X POST http://localhost:8100/__control \
|
|
109
287
|
-H "Content-Type: application/json" \
|
|
110
|
-
-d '{"mode": "transparent"
|
|
288
|
+
-d '{"mode": "transparent"}'
|
|
111
289
|
```
|
|
112
290
|
|
|
113
|
-
|
|
291
|
+
### Via JavaScript
|
|
114
292
|
|
|
115
293
|
```javascript
|
|
116
|
-
// Switch to record mode
|
|
117
294
|
await fetch('http://localhost:8100/__control', {
|
|
118
295
|
method: 'POST',
|
|
119
|
-
headers: {
|
|
120
|
-
'Content-Type': 'application/json',
|
|
121
|
-
},
|
|
296
|
+
headers: { 'Content-Type': 'application/json' },
|
|
122
297
|
body: JSON.stringify({
|
|
123
298
|
mode: 'record',
|
|
124
|
-
id: 'my-
|
|
125
|
-
timeout: 30000
|
|
126
|
-
})
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
// Switch to replay mode
|
|
130
|
-
await fetch('http://localhost:8100/__control', {
|
|
131
|
-
method: 'POST',
|
|
132
|
-
headers: {
|
|
133
|
-
'Content-Type': 'application/json',
|
|
134
|
-
},
|
|
135
|
-
body: JSON.stringify({
|
|
136
|
-
mode: 'replay',
|
|
137
|
-
id: 'my-testfile-1'
|
|
138
|
-
})
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// Switch to transparent mode
|
|
142
|
-
await fetch('http://localhost:8100/__control', {
|
|
143
|
-
method: 'POST',
|
|
144
|
-
headers: {
|
|
145
|
-
'Content-Type': 'application/json',
|
|
146
|
-
},
|
|
147
|
-
body: JSON.stringify({
|
|
148
|
-
mode: 'transparent',
|
|
299
|
+
id: 'my-test-1',
|
|
300
|
+
timeout: 30000 // Optional: auto-reset after 30s
|
|
149
301
|
})
|
|
150
302
|
});
|
|
151
303
|
```
|
|
152
304
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
# Start proxy server
|
|
157
|
-
test-proxy-recorder --port 8100 --target http://localhost:8000 --recordings ./recordings
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### CLI Options
|
|
161
|
-
|
|
162
|
-
- `--port, -p`: Port to listen on (default: 8080)
|
|
163
|
-
- `--target, -t`: Backend target URL (can add multiple targets)
|
|
164
|
-
- `--recordings, -r`: Directory to store recordings (default: ./recordings)
|
|
165
|
-
|
|
166
|
-
## API
|
|
167
|
-
|
|
168
|
-
### ProxyServer
|
|
169
|
-
|
|
170
|
-
```typescript
|
|
171
|
-
class ProxyServer {
|
|
172
|
-
constructor(targets: string[], recordingsDir: string);
|
|
173
|
-
|
|
174
|
-
async init(): Promise<void>;
|
|
175
|
-
listen(port: number): http.Server;
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### Control Endpoint
|
|
180
|
-
|
|
181
|
-
Send POST requests to `/__control` with JSON body:
|
|
305
|
+
### Control Request Interface
|
|
182
306
|
|
|
183
307
|
```typescript
|
|
184
308
|
interface ControlRequest {
|
|
185
309
|
mode: 'transparent' | 'record' | 'replay';
|
|
186
|
-
id?: string; //
|
|
187
|
-
timeout?: number; // Auto-
|
|
310
|
+
id?: string; // Recording ID, required for record/replay
|
|
311
|
+
timeout?: number; // Auto-reset timeout in ms (default: 120000)
|
|
188
312
|
}
|
|
189
313
|
```
|
|
190
314
|
|
|
191
|
-
|
|
315
|
+
## Typical Workflow
|
|
192
316
|
|
|
193
|
-
|
|
194
|
-
import { playwrightProxy, setProxyMode } from 'test-proxy-recorder';
|
|
317
|
+
### Initial Recording
|
|
195
318
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
319
|
+
1. Start backend API: `npm run api`
|
|
320
|
+
2. Start proxy and app: `npm run dev:proxy`
|
|
321
|
+
3. Set test to `'record'` mode
|
|
322
|
+
4. Run test: Recordings saved to `./e2e/recordings/` (directory created automatically)
|
|
323
|
+
5. Commit `.mock.json` files to git
|
|
324
|
+
6. Change mode to `'replay'`
|
|
200
325
|
|
|
201
|
-
|
|
202
|
-
async after(testInfo: PlaywrightTestInfo): Promise<void>;
|
|
203
|
-
};
|
|
204
|
-
```
|
|
326
|
+
### Running with Replay
|
|
205
327
|
|
|
206
|
-
|
|
328
|
+
1. Start proxy and app: `npm run dev:proxy` (no backend needed!)
|
|
329
|
+
2. Set test to `'replay'` mode
|
|
330
|
+
3. Run test: Uses recorded responses
|
|
331
|
+
4. Tests run fast without backend
|
|
207
332
|
|
|
208
|
-
|
|
333
|
+
### Updating Recordings
|
|
209
334
|
|
|
210
|
-
|
|
335
|
+
1. Start backend API
|
|
336
|
+
2. Set test to `'record'` mode
|
|
337
|
+
3. Run test: Overwrites existing recording
|
|
338
|
+
4. Commit updated `.mock.json` file
|
|
211
339
|
|
|
212
|
-
|
|
340
|
+
## Recording Format
|
|
213
341
|
|
|
214
|
-
|
|
215
|
-
import { setProxyMode } from 'test-proxy-recorder';
|
|
342
|
+
Recordings are stored as JSON files with `.mock.json` extension:
|
|
216
343
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
344
|
+
```text
|
|
345
|
+
e2e/recordings/
|
|
346
|
+
├── create-a-user.mock.json
|
|
347
|
+
├── fetch-users-list.mock.json
|
|
348
|
+
└── delete-user.mock.json
|
|
222
349
|
```
|
|
223
350
|
|
|
224
|
-
|
|
351
|
+
## Troubleshooting
|
|
225
352
|
|
|
226
|
-
|
|
353
|
+
### Proxy not responding
|
|
227
354
|
|
|
228
|
-
|
|
229
|
-
import { test } from '@playwright/test';
|
|
230
|
-
import { playwrightProxy } from 'test-proxy-recorder';
|
|
355
|
+
**Check if proxy is running**:
|
|
231
356
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
* This will run after every test across all test files.
|
|
235
|
-
*/
|
|
236
|
-
test.afterEach(async ({}, testInfo) => {
|
|
237
|
-
try {
|
|
238
|
-
await playwrightProxy.after(testInfo);
|
|
239
|
-
} catch (error) {
|
|
240
|
-
console.error('Error during proxy cleanup:', error);
|
|
241
|
-
// Don't throw - we want cleanup to continue even if this fails
|
|
242
|
-
}
|
|
243
|
-
});
|
|
357
|
+
```bash
|
|
358
|
+
curl http://localhost:8100/__control
|
|
244
359
|
```
|
|
245
360
|
|
|
246
|
-
|
|
361
|
+
**Check port availability**:
|
|
247
362
|
|
|
248
|
-
|
|
363
|
+
```bash
|
|
364
|
+
lsof -i :8100
|
|
365
|
+
```
|
|
249
366
|
|
|
250
|
-
|
|
251
|
-
import { defineConfig } from '@playwright/test';
|
|
367
|
+
### No recordings saved
|
|
252
368
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
});
|
|
258
|
-
```
|
|
369
|
+
- Verify proxy mode is `'record'`
|
|
370
|
+
- Check app is using proxy URL (`http://localhost:8100`)
|
|
371
|
+
- Verify write permissions on recordings directory
|
|
372
|
+
- Check proxy server logs for errors
|
|
259
373
|
|
|
260
|
-
|
|
374
|
+
### Test fails in replay mode
|
|
261
375
|
|
|
262
|
-
|
|
376
|
+
- Ensure recording exists for this test
|
|
377
|
+
- Check test name hasn't changed
|
|
378
|
+
- Verify recording file matches expected format
|
|
379
|
+
- Re-record if API responses changed
|
|
263
380
|
|
|
264
|
-
|
|
265
|
-
// In your e2e/basePage.ts or similar base test file
|
|
266
|
-
import { test as base } from '@playwright/test';
|
|
381
|
+
### Recordings not matching requests
|
|
267
382
|
|
|
268
|
-
|
|
269
|
-
|
|
383
|
+
- Request URLs must match exactly
|
|
384
|
+
- Headers may affect matching (configurable)
|
|
385
|
+
- Query parameters must be in same order
|
|
386
|
+
- Re-record to capture current API behavior
|
|
270
387
|
|
|
271
|
-
export const test = base.extend({
|
|
272
|
-
// your fixtures
|
|
273
|
-
});
|
|
274
|
-
```
|
|
275
388
|
|
|
276
|
-
##
|
|
389
|
+
## API Reference
|
|
277
390
|
|
|
278
|
-
|
|
391
|
+
### ProxyServer Class
|
|
279
392
|
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
393
|
+
```typescript
|
|
394
|
+
class ProxyServer {
|
|
395
|
+
constructor(targets: string[], recordingsDir: string);
|
|
396
|
+
async init(): Promise<void>;
|
|
397
|
+
listen(port: number): http.Server;
|
|
398
|
+
}
|
|
285
399
|
```
|
|
286
400
|
|
|
287
|
-
|
|
401
|
+
### Playwright Integration
|
|
288
402
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
- Unique keys for request matching during replay
|
|
403
|
+
```typescript
|
|
404
|
+
import { playwrightProxy, setProxyMode } from 'test-proxy-recorder';
|
|
292
405
|
|
|
293
|
-
|
|
406
|
+
// Main helper for Playwright tests
|
|
407
|
+
const playwrightProxy = {
|
|
408
|
+
// Set proxy mode before test
|
|
409
|
+
async before(
|
|
410
|
+
testInfo: TestInfo,
|
|
411
|
+
mode: 'record' | 'replay' | 'transparent',
|
|
412
|
+
timeout?: number
|
|
413
|
+
): Promise<void>;
|
|
294
414
|
|
|
295
|
-
|
|
415
|
+
// Reset to transparent mode after test
|
|
416
|
+
async after(testInfo: TestInfo): Promise<void>;
|
|
417
|
+
};
|
|
296
418
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
419
|
+
// Direct mode control
|
|
420
|
+
async function setProxyMode(
|
|
421
|
+
mode: 'record' | 'replay' | 'transparent',
|
|
422
|
+
id?: string,
|
|
423
|
+
timeout?: number
|
|
424
|
+
): Promise<void>;
|
|
425
|
+
```
|
|
300
426
|
|
|
301
|
-
|
|
427
|
+
### Control Endpoint
|
|
428
|
+
|
|
429
|
+
**Endpoint**: `POST http://localhost:8100/__control`
|
|
302
430
|
|
|
303
|
-
|
|
431
|
+
**Request Body**:
|
|
304
432
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
```
|
|
433
|
+
```typescript
|
|
434
|
+
{
|
|
435
|
+
mode: 'transparent' | 'record' | 'replay';
|
|
436
|
+
id?: string; // Recording ID (required for record/replay)
|
|
437
|
+
timeout?: number; // Auto-reset timeout in ms (default: 120000)
|
|
438
|
+
}
|
|
439
|
+
```
|
|
313
440
|
|
|
314
|
-
|
|
441
|
+
**Response**:
|
|
315
442
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
443
|
+
```typescript
|
|
444
|
+
{
|
|
445
|
+
success: boolean;
|
|
446
|
+
mode: string;
|
|
447
|
+
id: string | null;
|
|
448
|
+
timeout: number;
|
|
449
|
+
}
|
|
450
|
+
```
|
|
324
451
|
|
|
325
452
|
## Requirements
|
|
326
453
|
|
|
327
454
|
- Node.js >= 22.0.0
|
|
328
|
-
- @playwright/test >= 1.0.0
|
|
329
|
-
|
|
330
|
-
## License
|
|
331
|
-
|
|
332
|
-
MIT
|
|
455
|
+
- @playwright/test >= 1.0.0 (for Playwright integration)
|
|
333
456
|
|
|
334
457
|
## Contributing
|
|
335
458
|
|
|
336
459
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
460
|
+
|
|
461
|
+
## License
|
|
462
|
+
|
|
463
|
+
MIT
|