test-proxy-recorder 0.2.0 → 0.3.1
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 +134 -33
- package/dist/{index-nmNRt1WE.d.cts → index-CVuiglPk.d.cts} +6 -10
- package/dist/{index-nmNRt1WE.d.ts → index-CVuiglPk.d.ts} +6 -10
- package/dist/index.cjs +291 -258
- package/dist/index.d.cts +25 -8
- package/dist/index.d.ts +25 -8
- package/dist/index.mjs +288 -259
- package/dist/nextjs/index.cjs +43 -0
- package/dist/nextjs/index.d.cts +89 -0
- package/dist/nextjs/index.d.ts +89 -0
- package/dist/nextjs/index.mjs +38 -0
- package/dist/playwright/index.cjs +20 -11
- package/dist/playwright/index.d.cts +1 -1
- package/dist/playwright/index.d.ts +1 -1
- package/dist/playwright/index.mjs +20 -11
- package/dist/proxy.js +239 -246
- package/package.json +6 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/constants.ts
|
|
4
|
+
var RECORDING_ID_HEADER = "x-test-rcrd-id";
|
|
5
|
+
|
|
6
|
+
// src/nextjs/middleware.ts
|
|
7
|
+
function isRecorderEnabled() {
|
|
8
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
9
|
+
const isExplicitlyEnabled = process.env.TEST_PROXY_RECORDER_ENABLED === "true" || Number.parseInt(process.env.TEST_PROXY_RECORDER_ENABLED || "") === 1;
|
|
10
|
+
return !isProduction || isExplicitlyEnabled;
|
|
11
|
+
}
|
|
12
|
+
function setNextProxyHeaders(request, response) {
|
|
13
|
+
if (!isRecorderEnabled()) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const recordingId = request.headers.get(RECORDING_ID_HEADER);
|
|
17
|
+
if (recordingId) {
|
|
18
|
+
response.headers.set(RECORDING_ID_HEADER, recordingId);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function getRecordingId(requestHeaders) {
|
|
22
|
+
if (requestHeaders instanceof Headers) {
|
|
23
|
+
return requestHeaders.get(RECORDING_ID_HEADER);
|
|
24
|
+
}
|
|
25
|
+
return requestHeaders.headers.get(RECORDING_ID_HEADER);
|
|
26
|
+
}
|
|
27
|
+
function createHeadersWithRecordingId(requestHeaders, additionalHeaders = {}) {
|
|
28
|
+
if (!isRecorderEnabled()) {
|
|
29
|
+
return additionalHeaders;
|
|
30
|
+
}
|
|
31
|
+
const recordingId = getRecordingId(requestHeaders);
|
|
32
|
+
return {
|
|
33
|
+
...additionalHeaders,
|
|
34
|
+
...recordingId && { [RECORDING_ID_HEADER]: recordingId }
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
exports.RECORDING_ID_HEADER = RECORDING_ID_HEADER;
|
|
39
|
+
exports.createHeadersWithRecordingId = createHeadersWithRecordingId;
|
|
40
|
+
exports.getRecordingId = getRecordingId;
|
|
41
|
+
exports.setNextProxyHeaders = setNextProxyHeaders;
|
|
42
|
+
//# sourceMappingURL=index.cjs.map
|
|
43
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
declare const RECORDING_ID_HEADER = "x-test-rcrd-id";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal type for Next.js Request - compatible with next/server's NextRequest
|
|
5
|
+
* We define this locally to avoid requiring Next.js as a dependency
|
|
6
|
+
*/
|
|
7
|
+
interface NextJSRequest {
|
|
8
|
+
headers: Headers;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Minimal type for Next.js Response - compatible with next/server's NextResponse
|
|
12
|
+
* We define this locally to avoid requiring Next.js as a dependency
|
|
13
|
+
*/
|
|
14
|
+
interface NextJSResponse {
|
|
15
|
+
headers: Headers;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Next.js middleware helper for forwarding test proxy recording headers
|
|
19
|
+
* Automatically forwards the recording ID header from incoming requests to the proxy
|
|
20
|
+
* Only runs in non-production environments or when TEST_PROXY_RECORDER_ENABLED is set
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // middleware.ts
|
|
24
|
+
* import { NextResponse } from 'next/server';
|
|
25
|
+
* import type { NextRequest } from 'next/server';
|
|
26
|
+
* import { setNextProxyHeaders } from 'test-proxy-recorder/nextjs';
|
|
27
|
+
*
|
|
28
|
+
* export function middleware(request: NextRequest) {
|
|
29
|
+
* const response = NextResponse.next();
|
|
30
|
+
* // Only forwards headers in test/dev environments
|
|
31
|
+
* setNextProxyHeaders(request, response);
|
|
32
|
+
* return response;
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* @param request - Next.js request object (NextRequest from next/server)
|
|
36
|
+
* @param response - Next.js response object (NextResponse from next/server)
|
|
37
|
+
*/
|
|
38
|
+
declare function setNextProxyHeaders(request: NextJSRequest, response: NextJSResponse): void;
|
|
39
|
+
/**
|
|
40
|
+
* Get the recording ID from the request if present
|
|
41
|
+
* Useful for manually adding the header to fetch requests in Next.js
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* // In your API route or server component
|
|
45
|
+
* import { getRecordingId } from 'test-proxy-recorder/nextjs';
|
|
46
|
+
* import { headers } from 'next/headers';
|
|
47
|
+
*
|
|
48
|
+
* export async function GET() {
|
|
49
|
+
* const recordingId = getRecordingId(headers());
|
|
50
|
+
*
|
|
51
|
+
* const response = await fetch('http://localhost:8100/api/data', {
|
|
52
|
+
* headers: {
|
|
53
|
+
* ...(recordingId && { 'x-test-rcrd-id': recordingId })
|
|
54
|
+
* }
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* return Response.json(await response.json());
|
|
58
|
+
* }
|
|
59
|
+
*
|
|
60
|
+
* @param requestHeaders - Next.js headers object or NextRequest from next/server
|
|
61
|
+
* @returns The recording ID if present, null otherwise
|
|
62
|
+
*/
|
|
63
|
+
declare function getRecordingId(requestHeaders: NextJSRequest | Headers): string | null;
|
|
64
|
+
/**
|
|
65
|
+
* Create headers object with recording ID for fetch requests
|
|
66
|
+
* Use this helper when making fetch requests in Next.js to forward the recording ID
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* // In your API route or server component
|
|
70
|
+
* import { createHeadersWithRecordingId } from 'test-proxy-recorder/nextjs';
|
|
71
|
+
* import { headers } from 'next/headers';
|
|
72
|
+
*
|
|
73
|
+
* export async function GET() {
|
|
74
|
+
* const response = await fetch('http://localhost:8100/api/data', {
|
|
75
|
+
* headers: createHeadersWithRecordingId(headers(), {
|
|
76
|
+
* 'Content-Type': 'application/json',
|
|
77
|
+
* })
|
|
78
|
+
* });
|
|
79
|
+
*
|
|
80
|
+
* return Response.json(await response.json());
|
|
81
|
+
* }
|
|
82
|
+
*
|
|
83
|
+
* @param requestHeaders - Next.js headers object or NextRequest from next/server
|
|
84
|
+
* @param additionalHeaders - Optional additional headers to include
|
|
85
|
+
* @returns Headers object with recording ID if present
|
|
86
|
+
*/
|
|
87
|
+
declare function createHeadersWithRecordingId(requestHeaders: NextJSRequest | Headers, additionalHeaders?: Record<string, string>): Record<string, string>;
|
|
88
|
+
|
|
89
|
+
export { type NextJSRequest, type NextJSResponse, RECORDING_ID_HEADER, createHeadersWithRecordingId, getRecordingId, setNextProxyHeaders };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
declare const RECORDING_ID_HEADER = "x-test-rcrd-id";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Minimal type for Next.js Request - compatible with next/server's NextRequest
|
|
5
|
+
* We define this locally to avoid requiring Next.js as a dependency
|
|
6
|
+
*/
|
|
7
|
+
interface NextJSRequest {
|
|
8
|
+
headers: Headers;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Minimal type for Next.js Response - compatible with next/server's NextResponse
|
|
12
|
+
* We define this locally to avoid requiring Next.js as a dependency
|
|
13
|
+
*/
|
|
14
|
+
interface NextJSResponse {
|
|
15
|
+
headers: Headers;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Next.js middleware helper for forwarding test proxy recording headers
|
|
19
|
+
* Automatically forwards the recording ID header from incoming requests to the proxy
|
|
20
|
+
* Only runs in non-production environments or when TEST_PROXY_RECORDER_ENABLED is set
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // middleware.ts
|
|
24
|
+
* import { NextResponse } from 'next/server';
|
|
25
|
+
* import type { NextRequest } from 'next/server';
|
|
26
|
+
* import { setNextProxyHeaders } from 'test-proxy-recorder/nextjs';
|
|
27
|
+
*
|
|
28
|
+
* export function middleware(request: NextRequest) {
|
|
29
|
+
* const response = NextResponse.next();
|
|
30
|
+
* // Only forwards headers in test/dev environments
|
|
31
|
+
* setNextProxyHeaders(request, response);
|
|
32
|
+
* return response;
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* @param request - Next.js request object (NextRequest from next/server)
|
|
36
|
+
* @param response - Next.js response object (NextResponse from next/server)
|
|
37
|
+
*/
|
|
38
|
+
declare function setNextProxyHeaders(request: NextJSRequest, response: NextJSResponse): void;
|
|
39
|
+
/**
|
|
40
|
+
* Get the recording ID from the request if present
|
|
41
|
+
* Useful for manually adding the header to fetch requests in Next.js
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* // In your API route or server component
|
|
45
|
+
* import { getRecordingId } from 'test-proxy-recorder/nextjs';
|
|
46
|
+
* import { headers } from 'next/headers';
|
|
47
|
+
*
|
|
48
|
+
* export async function GET() {
|
|
49
|
+
* const recordingId = getRecordingId(headers());
|
|
50
|
+
*
|
|
51
|
+
* const response = await fetch('http://localhost:8100/api/data', {
|
|
52
|
+
* headers: {
|
|
53
|
+
* ...(recordingId && { 'x-test-rcrd-id': recordingId })
|
|
54
|
+
* }
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* return Response.json(await response.json());
|
|
58
|
+
* }
|
|
59
|
+
*
|
|
60
|
+
* @param requestHeaders - Next.js headers object or NextRequest from next/server
|
|
61
|
+
* @returns The recording ID if present, null otherwise
|
|
62
|
+
*/
|
|
63
|
+
declare function getRecordingId(requestHeaders: NextJSRequest | Headers): string | null;
|
|
64
|
+
/**
|
|
65
|
+
* Create headers object with recording ID for fetch requests
|
|
66
|
+
* Use this helper when making fetch requests in Next.js to forward the recording ID
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* // In your API route or server component
|
|
70
|
+
* import { createHeadersWithRecordingId } from 'test-proxy-recorder/nextjs';
|
|
71
|
+
* import { headers } from 'next/headers';
|
|
72
|
+
*
|
|
73
|
+
* export async function GET() {
|
|
74
|
+
* const response = await fetch('http://localhost:8100/api/data', {
|
|
75
|
+
* headers: createHeadersWithRecordingId(headers(), {
|
|
76
|
+
* 'Content-Type': 'application/json',
|
|
77
|
+
* })
|
|
78
|
+
* });
|
|
79
|
+
*
|
|
80
|
+
* return Response.json(await response.json());
|
|
81
|
+
* }
|
|
82
|
+
*
|
|
83
|
+
* @param requestHeaders - Next.js headers object or NextRequest from next/server
|
|
84
|
+
* @param additionalHeaders - Optional additional headers to include
|
|
85
|
+
* @returns Headers object with recording ID if present
|
|
86
|
+
*/
|
|
87
|
+
declare function createHeadersWithRecordingId(requestHeaders: NextJSRequest | Headers, additionalHeaders?: Record<string, string>): Record<string, string>;
|
|
88
|
+
|
|
89
|
+
export { type NextJSRequest, type NextJSResponse, RECORDING_ID_HEADER, createHeadersWithRecordingId, getRecordingId, setNextProxyHeaders };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// src/constants.ts
|
|
2
|
+
var RECORDING_ID_HEADER = "x-test-rcrd-id";
|
|
3
|
+
|
|
4
|
+
// src/nextjs/middleware.ts
|
|
5
|
+
function isRecorderEnabled() {
|
|
6
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
7
|
+
const isExplicitlyEnabled = process.env.TEST_PROXY_RECORDER_ENABLED === "true" || Number.parseInt(process.env.TEST_PROXY_RECORDER_ENABLED || "") === 1;
|
|
8
|
+
return !isProduction || isExplicitlyEnabled;
|
|
9
|
+
}
|
|
10
|
+
function setNextProxyHeaders(request, response) {
|
|
11
|
+
if (!isRecorderEnabled()) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const recordingId = request.headers.get(RECORDING_ID_HEADER);
|
|
15
|
+
if (recordingId) {
|
|
16
|
+
response.headers.set(RECORDING_ID_HEADER, recordingId);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function getRecordingId(requestHeaders) {
|
|
20
|
+
if (requestHeaders instanceof Headers) {
|
|
21
|
+
return requestHeaders.get(RECORDING_ID_HEADER);
|
|
22
|
+
}
|
|
23
|
+
return requestHeaders.headers.get(RECORDING_ID_HEADER);
|
|
24
|
+
}
|
|
25
|
+
function createHeadersWithRecordingId(requestHeaders, additionalHeaders = {}) {
|
|
26
|
+
if (!isRecorderEnabled()) {
|
|
27
|
+
return additionalHeaders;
|
|
28
|
+
}
|
|
29
|
+
const recordingId = getRecordingId(requestHeaders);
|
|
30
|
+
return {
|
|
31
|
+
...additionalHeaders,
|
|
32
|
+
...recordingId && { [RECORDING_ID_HEADER]: recordingId }
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { RECORDING_ID_HEADER, createHeadersWithRecordingId, getRecordingId, setNextProxyHeaders };
|
|
37
|
+
//# sourceMappingURL=index.mjs.map
|
|
38
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/constants.ts
|
|
4
|
+
var RECORDING_ID_HEADER = "x-test-rcrd-id";
|
|
5
|
+
|
|
3
6
|
// src/types.ts
|
|
4
7
|
var Modes = {
|
|
5
8
|
transparent: "transparent",
|
|
@@ -86,23 +89,29 @@ async function stopProxy(testInfo) {
|
|
|
86
89
|
}
|
|
87
90
|
var playwrightProxy = {
|
|
88
91
|
/**
|
|
89
|
-
* Setup before test - sets the proxy mode
|
|
92
|
+
* Setup before test - sets the proxy mode and configures page with custom header
|
|
93
|
+
* Automatically sets up page.on('close') handler for cleanup
|
|
94
|
+
* @param page - Playwright page object
|
|
90
95
|
* @param testInfo - Playwright test info object
|
|
91
96
|
* @param mode - The proxy mode to use for this test
|
|
92
97
|
* @param timeout - Optional timeout in milliseconds
|
|
93
98
|
*/
|
|
94
|
-
async before(testInfo, mode, timeout) {
|
|
99
|
+
async before(page, testInfo, mode, timeout) {
|
|
95
100
|
const sessionId = generateSessionId(testInfo);
|
|
101
|
+
await page.setExtraHTTPHeaders({
|
|
102
|
+
[RECORDING_ID_HEADER]: sessionId
|
|
103
|
+
});
|
|
96
104
|
await setProxyMode(mode, sessionId, timeout);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
105
|
+
page.on("close", async () => {
|
|
106
|
+
try {
|
|
107
|
+
await setProxyMode(Modes.replay, sessionId);
|
|
108
|
+
console.log(
|
|
109
|
+
`[Cleanup] Switched to replay mode for session: ${sessionId}`
|
|
110
|
+
);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error("[Cleanup] Error during page close cleanup:", error);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
106
115
|
},
|
|
107
116
|
/**
|
|
108
117
|
* Global teardown - switches proxy to transparent mode
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import '@playwright/test';
|
|
2
|
-
export { P as PlaywrightTestInfo, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from '../index-
|
|
2
|
+
export { P as PlaywrightTestInfo, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from '../index-CVuiglPk.cjs';
|
|
3
3
|
import 'node:http';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import '@playwright/test';
|
|
2
|
-
export { P as PlaywrightTestInfo, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from '../index-
|
|
2
|
+
export { P as PlaywrightTestInfo, g as generateSessionId, p as playwrightProxy, s as setProxyMode, b as startRecording, c as startReplay, d as stopProxy } from '../index-CVuiglPk.js';
|
|
3
3
|
import 'node:http';
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// src/constants.ts
|
|
2
|
+
var RECORDING_ID_HEADER = "x-test-rcrd-id";
|
|
3
|
+
|
|
1
4
|
// src/types.ts
|
|
2
5
|
var Modes = {
|
|
3
6
|
transparent: "transparent",
|
|
@@ -84,23 +87,29 @@ async function stopProxy(testInfo) {
|
|
|
84
87
|
}
|
|
85
88
|
var playwrightProxy = {
|
|
86
89
|
/**
|
|
87
|
-
* Setup before test - sets the proxy mode
|
|
90
|
+
* Setup before test - sets the proxy mode and configures page with custom header
|
|
91
|
+
* Automatically sets up page.on('close') handler for cleanup
|
|
92
|
+
* @param page - Playwright page object
|
|
88
93
|
* @param testInfo - Playwright test info object
|
|
89
94
|
* @param mode - The proxy mode to use for this test
|
|
90
95
|
* @param timeout - Optional timeout in milliseconds
|
|
91
96
|
*/
|
|
92
|
-
async before(testInfo, mode, timeout) {
|
|
97
|
+
async before(page, testInfo, mode, timeout) {
|
|
93
98
|
const sessionId = generateSessionId(testInfo);
|
|
99
|
+
await page.setExtraHTTPHeaders({
|
|
100
|
+
[RECORDING_ID_HEADER]: sessionId
|
|
101
|
+
});
|
|
94
102
|
await setProxyMode(mode, sessionId, timeout);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
page.on("close", async () => {
|
|
104
|
+
try {
|
|
105
|
+
await setProxyMode(Modes.replay, sessionId);
|
|
106
|
+
console.log(
|
|
107
|
+
`[Cleanup] Switched to replay mode for session: ${sessionId}`
|
|
108
|
+
);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error("[Cleanup] Error during page close cleanup:", error);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
104
113
|
},
|
|
105
114
|
/**
|
|
106
115
|
* Global teardown - switches proxy to transparent mode
|