Skip to content

Commit b509b14

Browse files
authored
Merge pull request #331 from OpenAPI-Qraft/fix/resolve-response-fn
fix: ensure `resolveResponse` always resolves promises.
2 parents 609b32d + c796132 commit b509b14

File tree

3 files changed

+129
-6
lines changed

3 files changed

+129
-6
lines changed

.changeset/eight-coats-brake.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'@openapi-qraft/react': patch
3+
---
4+
5+
Ensure `resolveResponse` always **resolves** promises.
6+
7+
This change modifies the `resolveResponse` function to always return a resolved Promise
8+
rather than rejecting when no `responsePromise` is provided. This brings the function's
9+
behavior in line with the `requestFn` pattern, ensuring consistent error handling.
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { describe, expect, it } from 'vitest';
2+
import { resolveResponse } from '../responseUtils.js';
3+
4+
describe('resolveResponse', () => {
5+
it('should handle Error without promise', async () => {
6+
const testError = new Error('Test error');
7+
8+
const result = await resolveResponse<unknown, Error>(testError);
9+
10+
expect(result).toEqual({
11+
error: testError,
12+
response: undefined,
13+
data: undefined,
14+
});
15+
});
16+
17+
it('should handle Response without promise', async () => {
18+
const mockResponse = new Response(null);
19+
20+
// We use casting to bypass type checking, since we know that the function accepts Response
21+
// without a promise in the implementation, although types do not allow it directly.
22+
const result = await (resolveResponse as any)(mockResponse);
23+
24+
expect(result).toEqual({
25+
error: expect.any(Error),
26+
response: mockResponse,
27+
data: undefined,
28+
});
29+
expect((result.error as Error).message).toBe(
30+
'Unhandled response without promise to resolve'
31+
);
32+
});
33+
34+
it('should resolve promise with data and response', async () => {
35+
const mockResponse = new Response(null);
36+
const testData = { test: 'data' };
37+
const dataPromise = Promise.resolve(testData);
38+
39+
const result = await resolveResponse<typeof testData, Error>(
40+
mockResponse,
41+
dataPromise
42+
);
43+
44+
expect(result).toEqual({
45+
data: testData,
46+
response: mockResponse,
47+
error: undefined,
48+
});
49+
});
50+
51+
it('should handle rejected promise with error and response', async () => {
52+
const mockResponse = new Response(null);
53+
const testError = new Error('Test rejection');
54+
const dataPromise = Promise.reject(testError);
55+
56+
const result = await resolveResponse<unknown, Error>(
57+
mockResponse,
58+
dataPromise
59+
);
60+
61+
expect(result).toEqual({
62+
error: testError,
63+
response: mockResponse,
64+
data: undefined,
65+
});
66+
});
67+
68+
it('should handle custom error objects in rejected promise', async () => {
69+
const mockResponse = new Response(null);
70+
type CustomError = { code: string; message: string };
71+
const customError: CustomError = {
72+
code: 'CUSTOM_ERROR',
73+
message: 'Custom error object',
74+
};
75+
const dataPromise = Promise.reject(customError);
76+
77+
const result = await resolveResponse<unknown, CustomError>(
78+
mockResponse,
79+
dataPromise
80+
);
81+
82+
expect(result).toEqual({
83+
error: customError,
84+
response: mockResponse,
85+
data: undefined,
86+
});
87+
});
88+
89+
it('should preserve response object when promise resolves', async () => {
90+
const headers = new Headers();
91+
headers.append('Content-Type', 'application/json');
92+
const mockResponse = new Response('{"key":"value"}', { headers });
93+
const testData = { key: 'value' };
94+
const dataPromise = Promise.resolve(testData);
95+
96+
const result = await resolveResponse<typeof testData, Error>(
97+
mockResponse,
98+
dataPromise
99+
);
100+
101+
expect(result.response).toBe(mockResponse);
102+
expect(result.data).toEqual(testData);
103+
expect(result.error).toBeUndefined();
104+
});
105+
});

packages/react-client/src/lib/responseUtils.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,21 @@ export function resolveResponse<TData, TError>(
4949
responseToReturn: Response | Error,
5050
responsePromise?: Promise<TData>
5151
): Promise<RequestFnResponse<TData, TError>> {
52-
if (!responsePromise)
53-
return Promise.reject({
54-
error: responseToReturn,
55-
response: undefined,
56-
data: undefined,
57-
});
52+
if (!responsePromise) {
53+
if (responseToReturn instanceof Response) {
54+
return Promise.resolve({
55+
error: new Error('Unhandled response without promise to resolve'),
56+
response: responseToReturn,
57+
data: undefined,
58+
});
59+
} else {
60+
return Promise.resolve({
61+
error: responseToReturn,
62+
response: undefined,
63+
data: undefined,
64+
});
65+
}
66+
}
5867

5968
return responsePromise
6069
.then(

0 commit comments

Comments
 (0)