Skip to content

Commit 2deb9d5

Browse files
fix: mismatch in respect status code when har-output option used (#2803)
1 parent ea362a2 commit 2deb9d5

3 files changed

Lines changed: 65 additions & 14 deletions

File tree

.changeset/chilly-banks-act.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@redocly/cli": patch
3+
---
4+
5+
Fixed a status code mismatch that occurred when using the `--har-output` option in the `respect` command.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { createHarLog } from '../../../../commands/respect/har-logs/har-logs.js';
2+
import { withHar } from '../../../../commands/respect/har-logs/with-har.js';
3+
4+
describe('withHar', () => {
5+
it('should preserve the original response status', async () => {
6+
const har = createHarLog({ version: '1.0.0' });
7+
const dispatcher = { on: vi.fn() };
8+
const originalResponse = new Response(JSON.stringify({ created: true }), {
9+
status: 201,
10+
statusText: 'Created',
11+
headers: { 'content-type': 'application/json' },
12+
});
13+
const baseFetch = vi.fn(async () => {
14+
return originalResponse;
15+
});
16+
17+
const fetch = withHar(baseFetch as any, { har });
18+
const response = await fetch('https://example.com/resources', {
19+
method: 'POST',
20+
dispatcher,
21+
});
22+
23+
expect(response).toBe(originalResponse);
24+
expect(response.status).toBe(201);
25+
expect(response.statusText).toBe('Created');
26+
expect(await response.json()).toEqual({ created: true });
27+
expect(har.log.entries[0].response.status).toBe(201);
28+
});
29+
30+
it('should return a bodyless response for no-content statuses', async () => {
31+
const har = createHarLog({ version: '1.0.0' });
32+
const dispatcher = { on: vi.fn() };
33+
const originalResponse = new Response(null, {
34+
status: 204,
35+
statusText: 'No Content',
36+
});
37+
const baseFetch = vi.fn(async () => {
38+
return originalResponse;
39+
});
40+
41+
const fetch = withHar(baseFetch as any, { har });
42+
const response = await fetch('https://example.com/resources', {
43+
method: 'POST',
44+
dispatcher,
45+
});
46+
47+
expect(response).toBe(originalResponse);
48+
expect(response.status).toBe(204);
49+
expect(response.statusText).toBe('No Content');
50+
expect(await response.text()).toBe('');
51+
expect(har.log.entries[0].response.status).toBe(204);
52+
});
53+
});

packages/cli/src/commands/respect/har-logs/with-har.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,15 @@ export const withHar: WithHar = function <T extends typeof fetch>(
110110
// Make the request
111111
const response = await baseFetch(input, options);
112112

113-
// Need to clone response to get both text and arrayBuffer
114-
const responseClone = response.clone();
113+
// Read from clones so HAR logging does not consume or reconstruct the real response.
114+
const responseTextClone = response.clone();
115+
const responseBufferClone = response.clone();
115116

116117
// Update firstByte time when we get the response
117118
entry._timestamps.firstByte = process.hrtime();
118119

119120
// Get the response body and update received time
120-
const text = await response.text();
121+
const text = response.body === null ? '' : await responseTextClone.text();
121122
entry._timestamps.received = process.hrtime();
122123

123124
const harEntry = harEntryMap.get(requestId);
@@ -149,7 +150,7 @@ export const withHar: WithHar = function <T extends typeof fetch>(
149150
}
150151

151152
if (harEntry._compressed) {
152-
const rawBody = await responseClone.arrayBuffer();
153+
const rawBody = await responseBufferClone.arrayBuffer();
153154
harEntry.response.content.size = rawBody.byteLength;
154155
} else {
155156
harEntry.response.content.size = text ? Buffer.byteLength(text) : -1;
@@ -211,15 +212,7 @@ export const withHar: WithHar = function <T extends typeof fetch>(
211212
parent.pageref = entry.pageref;
212213
});
213214

214-
const Response =
215-
defaults.Response || baseFetch.Response || global.Response || response.constructor;
216-
const responseCopy = new Response(text, {
217-
status: response.statusCode,
218-
statusText: response.statusText || '',
219-
headers: response.headers,
220-
url: response.url,
221-
});
222-
responseCopy.harEntry = entry;
215+
response.harEntry = entry;
223216

224217
if (Array.isArray(har?.log?.entries)) {
225218
har.log.entries.push(...parents, entry);
@@ -232,6 +225,6 @@ export const withHar: WithHar = function <T extends typeof fetch>(
232225
onHarEntry(entry);
233226
}
234227

235-
return responseCopy;
228+
return response;
236229
} as T;
237230
};

0 commit comments

Comments
 (0)