Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/chilly-banks-act.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@redocly/cli": patch
---

Fixed a status code mismatch that occurred when using the `--har-output` option in the `respect` command.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { createHarLog } from '../../../../commands/respect/har-logs/har-logs.js';
import { withHar } from '../../../../commands/respect/har-logs/with-har.js';

describe('withHar', () => {
it('should preserve the original response status', async () => {
const har = createHarLog({ version: '1.0.0' });
const dispatcher = { on: vi.fn() };
const originalResponse = new Response(JSON.stringify({ created: true }), {
status: 201,
statusText: 'Created',
headers: { 'content-type': 'application/json' },
});
const baseFetch = vi.fn(async () => {
return originalResponse;
});

const fetch = withHar(baseFetch as any, { har });
const response = await fetch('https://example.com/resources', {
method: 'POST',
dispatcher,
});

expect(response).toBe(originalResponse);
expect(response.status).toBe(201);
expect(response.statusText).toBe('Created');
expect(await response.json()).toEqual({ created: true });
expect(har.log.entries[0].response.status).toBe(201);
});

it('should return a bodyless response for no-content statuses', async () => {
const har = createHarLog({ version: '1.0.0' });
const dispatcher = { on: vi.fn() };
const originalResponse = new Response(null, {
status: 204,
statusText: 'No Content',
});
const baseFetch = vi.fn(async () => {
return originalResponse;
});

const fetch = withHar(baseFetch as any, { har });
const response = await fetch('https://example.com/resources', {
method: 'POST',
dispatcher,
});

expect(response).toBe(originalResponse);
expect(response.status).toBe(204);
expect(response.statusText).toBe('No Content');
expect(await response.text()).toBe('');
expect(har.log.entries[0].response.status).toBe(204);
});
});
21 changes: 7 additions & 14 deletions packages/cli/src/commands/respect/har-logs/with-har.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,15 @@ export const withHar: WithHar = function <T extends typeof fetch>(
// Make the request
const response = await baseFetch(input, options);

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

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

// Get the response body and update received time
const text = await response.text();
const text = response.body === null ? '' : await responseTextClone.text();
entry._timestamps.received = process.hrtime();

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

if (harEntry._compressed) {
const rawBody = await responseClone.arrayBuffer();
const rawBody = await responseBufferClone.arrayBuffer();
harEntry.response.content.size = rawBody.byteLength;
} else {
harEntry.response.content.size = text ? Buffer.byteLength(text) : -1;
Expand Down Expand Up @@ -211,15 +212,7 @@ export const withHar: WithHar = function <T extends typeof fetch>(
parent.pageref = entry.pageref;
});

const Response =
defaults.Response || baseFetch.Response || global.Response || response.constructor;
const responseCopy = new Response(text, {
status: response.statusCode,
statusText: response.statusText || '',
headers: response.headers,
url: response.url,
});
responseCopy.harEntry = entry;
response.harEntry = entry;

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

return responseCopy;
return response;
} as T;
};
Loading