Skip to content

Commit 7d35869

Browse files
committed
chore: update tests
1 parent 7a95a55 commit 7d35869

24 files changed

+3397
-3881
lines changed

packages/typed-openapi/tests/configurable-status-codes.test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ it("should use custom success status codes", async () => {
4949
// Test with default success status codes (should include 200 and 201)
5050
const defaultGenerated = await prettify(generateFile(endpoints));
5151
expect(defaultGenerated).toContain("export type SuccessStatusCode =");
52-
expect(defaultGenerated).toContain("| 200");
53-
expect(defaultGenerated).toContain("| 201");
52+
expect(defaultGenerated).toContain("200, 201, 202");
5453

5554
// Test with custom success status codes (only 200)
5655
const customGenerated = await prettify(
@@ -61,8 +60,8 @@ it("should use custom success status codes", async () => {
6160
);
6261

6362
// Should only contain 200 in the StatusCode type
64-
expect(customGenerated).toContain("export type SuccessStatusCode = 200;");
65-
expect(customGenerated).not.toContain("| 201");
63+
expect(customGenerated).toContain("const successStatusCodes = [200] as const");
64+
expect(customGenerated).not.toContain("const successStatusCodes = [201] as const");
6665

6766
// The ApiResponse type should use the custom StatusCode
6867
expect(customGenerated).toContain("TStatusCode extends SuccessStatusCode");

packages/typed-openapi/tests/generator.test.ts

Lines changed: 309 additions & 371 deletions
Large diffs are not rendered by default.

packages/typed-openapi/tests/multiple-success-responses.test.ts

Lines changed: 81 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -183,91 +183,68 @@ describe("multiple success responses", () => {
183183
184184
export type Fetcher = (method: Method, url: string, parameters?: EndpointParameters | undefined) => Promise<Response>;
185185
186-
// Status code type for success responses
187-
export type SuccessStatusCode =
188-
| 200
189-
| 201
190-
| 202
191-
| 203
192-
| 204
193-
| 205
194-
| 206
195-
| 207
196-
| 208
197-
| 226
198-
| 300
199-
| 301
200-
| 302
201-
| 303
202-
| 304
203-
| 305
204-
| 306
205-
| 307
206-
| 308;
186+
export const successStatusCodes = [
187+
200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 306, 307, 308,
188+
] as const;
189+
export type SuccessStatusCode = (typeof successStatusCodes)[number];
190+
191+
export const errorStatusCodes = [
192+
400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 421, 422, 423, 424,
193+
425, 426, 428, 429, 431, 451, 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511,
194+
] as const;
195+
export type ErrorStatusCode = (typeof errorStatusCodes)[number];
207196
208197
// Error handling types
198+
/** @see https://developer.mozilla.org/en-US/docs/Web/API/Response */
199+
interface SuccessResponse<TSuccess, TStatusCode> extends Omit<Response, "ok" | "status" | "json"> {
200+
ok: true;
201+
status: TStatusCode;
202+
data: TSuccess;
203+
/** [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Response/json) */
204+
json: () => Promise<TSuccess>;
205+
}
206+
207+
/** @see https://developer.mozilla.org/en-US/docs/Web/API/Response */
208+
interface ErrorResponse<TData, TStatusCode> extends Omit<Response, "ok" | "status" | "json"> {
209+
ok: false;
210+
status: TStatusCode;
211+
data: TData;
212+
/** [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Response/json) */
213+
json: () => Promise<TData>;
214+
}
215+
209216
export type TypedApiResponse<
210217
TSuccess,
211218
TAllResponses extends Record<string | number, unknown> = {},
212219
> = keyof TAllResponses extends never
213-
? Omit<Response, "ok" | "status" | "json"> & {
214-
ok: true;
215-
status: number;
216-
data: TSuccess;
217-
json: () => Promise<TSuccess>;
218-
}
220+
? SuccessResponse<TSuccess, number>
219221
: {
220222
[K in keyof TAllResponses]: K extends string
221223
? K extends \`\${infer TStatusCode extends number}\`
222224
? TStatusCode extends SuccessStatusCode
223-
? Omit<Response, "ok" | "status" | "json"> & {
224-
ok: true;
225-
status: TStatusCode;
226-
data: TSuccess;
227-
json: () => Promise<TSuccess>;
228-
}
229-
: Omit<Response, "ok" | "status" | "json"> & {
230-
ok: false;
231-
status: TStatusCode;
232-
data: TAllResponses[K];
233-
json: () => Promise<TAllResponses[K]>;
234-
}
225+
? SuccessResponse<TSuccess, TStatusCode>
226+
: ErrorResponse<TAllResponses[K], TStatusCode>
235227
: never
236228
: K extends number
237229
? K extends SuccessStatusCode
238-
? Omit<Response, "ok" | "status" | "json"> & {
239-
ok: true;
240-
status: K;
241-
data: TSuccess;
242-
json: () => Promise<TSuccess>;
243-
}
244-
: Omit<Response, "ok" | "status" | "json"> & {
245-
ok: false;
246-
status: K;
247-
data: TAllResponses[K];
248-
json: () => Promise<TAllResponses[K]>;
249-
}
230+
? SuccessResponse<TSuccess, K>
231+
: ErrorResponse<TAllResponses[K], K>
250232
: never;
251233
}[keyof TAllResponses];
252234
253235
export type SafeApiResponse<TEndpoint> = TEndpoint extends { response: infer TSuccess; responses: infer TResponses }
254236
? TResponses extends Record<string, unknown>
255237
? TypedApiResponse<TSuccess, TResponses>
256-
: Omit<Response, "ok" | "status" | "json"> & {
257-
ok: true;
258-
status: number;
259-
data: TSuccess;
260-
json: () => Promise<TSuccess>;
261-
}
238+
: SuccessResponse<TSuccess, number>
262239
: TEndpoint extends { response: infer TSuccess }
263-
? Omit<Response, "ok" | "status" | "json"> & {
264-
ok: true;
265-
status: number;
266-
data: TSuccess;
267-
json: () => Promise<TSuccess>;
268-
}
240+
? SuccessResponse<TSuccess, number>
269241
: never;
270242
243+
export type InferResponseByStatus<TEndpoint, TStatusCode> = Extract<
244+
SafeApiResponse<TEndpoint>,
245+
{ status: TStatusCode }
246+
>;
247+
271248
type RequiredKeys<T> = {
272249
[P in keyof T]-?: undefined extends T[P] ? never : P;
273250
}[keyof T];
@@ -276,9 +253,23 @@ describe("multiple success responses", () => {
276253
277254
// </ApiClientTypes>
278255
256+
// <TypedResponseError>
257+
export class TypedResponseError extends Error {
258+
response: ErrorResponse<unknown, ErrorStatusCode>;
259+
status: number;
260+
constructor(response: ErrorResponse<unknown, ErrorStatusCode>) {
261+
super(\`HTTP \${response.status}: \${response.statusText}\`);
262+
this.name = "TypedResponseError";
263+
this.response = response;
264+
this.status = response.status;
265+
}
266+
}
267+
// </TypedResponseError>
279268
// <ApiClient>
280269
export class ApiClient {
281270
baseUrl: string = "";
271+
successStatusCodes = successStatusCodes;
272+
errorStatusCodes = errorStatusCodes;
282273
283274
constructor(public fetcher: Fetcher) {}
284275
@@ -298,12 +289,12 @@ describe("multiple success responses", () => {
298289
// <ApiClient.post>
299290
post<Path extends keyof PostEndpoints, TEndpoint extends PostEndpoints[Path]>(
300291
path: Path,
301-
...params: MaybeOptionalArg<TEndpoint["parameters"] & { withResponse?: false }>
292+
...params: MaybeOptionalArg<TEndpoint["parameters"] & { withResponse?: false; throwOnStatusError?: boolean }>
302293
): Promise<TEndpoint["response"]>;
303294
304295
post<Path extends keyof PostEndpoints, TEndpoint extends PostEndpoints[Path]>(
305296
path: Path,
306-
...params: MaybeOptionalArg<TEndpoint["parameters"] & { withResponse: true }>
297+
...params: MaybeOptionalArg<TEndpoint["parameters"] & { withResponse: true; throwOnStatusError?: boolean }>
307298
): Promise<SafeApiResponse<TEndpoint>>;
308299
309300
post<Path extends keyof PostEndpoints, TEndpoint extends PostEndpoints[Path]>(
@@ -312,31 +303,27 @@ describe("multiple success responses", () => {
312303
): Promise<any> {
313304
const requestParams = params[0];
314305
const withResponse = requestParams?.withResponse;
306+
const { withResponse: _, throwOnStatusError = withResponse ? false : true, ...fetchParams } = requestParams || {};
307+
308+
const promise = this.fetcher(
309+
"post",
310+
this.baseUrl + path,
311+
Object.keys(fetchParams).length ? requestParams : undefined,
312+
).then(async (response) => {
313+
const data = await this.parseResponse(response);
314+
const typedResponse = Object.assign(response, {
315+
data: data,
316+
json: () => Promise.resolve(data),
317+
}) as SafeApiResponse<TEndpoint>;
318+
319+
if (throwOnStatusError && errorStatusCodes.includes(response.status as never)) {
320+
throw new TypedResponseError(typedResponse as never);
321+
}
315322
316-
// Remove withResponse from params before passing to fetcher
317-
const { withResponse: _, ...fetchParams } = requestParams || {};
318-
319-
if (withResponse) {
320-
return this.fetcher("post", this.baseUrl + path, Object.keys(fetchParams).length ? fetchParams : undefined).then(
321-
async (response) => {
322-
// Parse the response data
323-
const data = await this.parseResponse(response);
324-
325-
// Override properties while keeping the original Response object
326-
const typedResponse = Object.assign(response, {
327-
ok: response.ok,
328-
status: response.status,
329-
data: data,
330-
json: () => Promise.resolve(data),
331-
});
332-
return typedResponse;
333-
},
334-
);
335-
} else {
336-
return this.fetcher("post", this.baseUrl + path, requestParams).then((response) =>
337-
this.parseResponse(response),
338-
) as Promise<TEndpoint["response"]>;
339-
}
323+
return withResponse ? typedResponse : data;
324+
});
325+
326+
return promise as Promise<TEndpoint["response"]>;
340327
}
341328
// </ApiClient.post>
342329
@@ -352,13 +339,10 @@ describe("multiple success responses", () => {
352339
method: TMethod,
353340
path: TPath,
354341
...params: MaybeOptionalArg<TEndpoint extends { parameters: infer Params } ? Params : never>
355-
): Promise<
356-
Omit<Response, "json"> & {
357-
/** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/json) */
358-
json: () => Promise<TEndpoint extends { response: infer Res } ? Res : never>;
359-
}
360-
> {
361-
return this.fetcher(method, this.baseUrl + (path as string), params[0] as EndpointParameters);
342+
): Promise<SafeApiResponse<TEndpoint>> {
343+
return this.fetcher(method, this.baseUrl + (path as string), params[0] as EndpointParameters) as Promise<
344+
SafeApiResponse<TEndpoint>
345+
>;
362346
}
363347
// </ApiClient.request>
364348
}
@@ -392,7 +376,7 @@ describe("multiple success responses", () => {
392376
}
393377
*/
394378
395-
// </ApiClient
379+
// </ApiClient>
396380
"
397381
`);
398382
});

0 commit comments

Comments
 (0)