Skip to content

Commit ec1f006

Browse files
committed
Better error handling
1 parent efc1744 commit ec1f006

File tree

3 files changed

+198
-100
lines changed

3 files changed

+198
-100
lines changed

.vscode/launch.json

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
"configurations": [
44
{
55
"request": "launch",
6-
"name": "Debug Tests",
6+
"name": "Debug All Tests",
77
"type": "node",
8-
"program": "${workspaceFolder}/src/FetchClient.test.ts",
98
"cwd": "${workspaceFolder}",
109
"env": {},
1110
"runtimeExecutable": "deno",
@@ -15,6 +14,23 @@
1514
"--allow-all"
1615
],
1716
"attachSimplePort": 9229
17+
},
18+
{
19+
"request": "launch",
20+
"name": "Debug Test",
21+
"type": "node",
22+
"program": "src/FetchClient.test.ts",
23+
"cwd": "${workspaceFolder}",
24+
"env": {},
25+
"runtimeExecutable": "deno",
26+
"runtimeArgs": [
27+
"test",
28+
"--inspect-wait",
29+
"--allow-all",
30+
"--filter",
31+
"handles 400 response with non-JSON text"
32+
],
33+
"attachSimplePort": 9229
1834
}
1935
]
20-
}
36+
}

src/FetchClient.test.ts

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
import { assert, assertEquals, assertFalse, assertRejects } from "@std/assert";
1+
import {
2+
assert,
3+
assertEquals,
4+
assertFalse,
5+
assertRejects,
6+
assertStringIncludes,
7+
} from "@std/assert";
28
import {
39
FetchClient,
410
type FetchClientContext,
11+
type FetchClientResponse,
512
getJSON,
613
ProblemDetails,
714
setBaseUrl,
@@ -900,6 +907,69 @@ Deno.test("can use kitchen sink function", async () => {
900907
assert(optionsCalled);
901908
});
902909

910+
Deno.test("handles 400 response with non-JSON text", async () => {
911+
const provider = new FetchClientProvider();
912+
const fakeFetch = (): Promise<Response> =>
913+
new Promise((resolve) => {
914+
resolve(
915+
new Response("Hello World", {
916+
status: 400,
917+
statusText: "Bad Request",
918+
}),
919+
);
920+
});
921+
922+
provider.fetch = fakeFetch;
923+
const client = provider.getFetchClient();
924+
925+
// Test that the client throws an error for 400 status by default
926+
try {
927+
await client.deleteJSON("https://dummyjson.com/http/400/Hello World", {
928+
headers: { "Accept": "text/plain" },
929+
});
930+
} catch (error) {
931+
assert(error instanceof Response);
932+
const response = error as FetchClientResponse<unknown>;
933+
assertEquals(response.status, 400);
934+
assertEquals(response.statusText, "Bad Request");
935+
assertFalse(response.ok);
936+
assertEquals(response.data, null);
937+
assert(response.problem);
938+
assert(response.problem.errors);
939+
assert(response.problem.title);
940+
assertStringIncludes(response.problem.title, "Unexpected status");
941+
assert(response.problem.errors.general);
942+
assertEquals(response.problem.errors.general.length, 1);
943+
assertStringIncludes(
944+
response.problem.errors.general[0],
945+
"Unexpected status",
946+
);
947+
}
948+
949+
// Test with expectedStatusCodes to handle 400 without throwing
950+
const response = await client.deleteJSON(
951+
"https://dummyjson.com/http/400/Hello World",
952+
{
953+
expectedStatusCodes: [400],
954+
},
955+
);
956+
957+
assertEquals(response.status, 400);
958+
assertEquals(response.statusText, "Bad Request");
959+
assertFalse(response.ok);
960+
assertEquals(response.data, null);
961+
assert(response.problem);
962+
assert(response.problem.errors);
963+
assert(response.problem.title);
964+
assertStringIncludes(response.problem.title, "Unable to deserialize");
965+
assert(response.problem.errors.general);
966+
assertEquals(response.problem.errors.general.length, 1);
967+
assertStringIncludes(
968+
response.problem.errors.general[0],
969+
"Unable to deserialize",
970+
);
971+
});
972+
903973
function delay(time: number): Promise<void> {
904974
return new Promise((resolve) => setTimeout(resolve, time));
905975
}

0 commit comments

Comments
 (0)