Fetch_test.res.mjs
1// Generated by ReScript, PLEASE EDIT WITH CARE
2
3import * as Fetch from "../src/ffi/Fetch.res.mjs";
4import * as Vitest from "vitest";
5import * as Core__JSON from "@rescript/core/lib/es6/src/Core__JSON.res.mjs";
6
7let mockFetchJson = (function(json, status, statusText) {
8 globalThis.fetch = vi.fn(() => Promise.resolve({
9 ok: status >= 200 && status < 300,
10 status: status,
11 statusText: statusText,
12 json: () => Promise.resolve(json)
13 }));
14 });
15
16let setupMockWithCapture = (function() {
17 const calls = [];
18 globalThis.fetch = vi.fn((url, init) => {
19 calls.push({url, init});
20 return Promise.resolve({
21 ok: true,
22 status: 200,
23 statusText: 'OK',
24 json: () => Promise.resolve(null)
25 });
26 });
27 return calls;
28 });
29
30let getContentType = (function(calls) {
31 const headers = calls[0].init.headers;
32 if (Array.isArray(headers)) {
33 const found = headers.find(h => h[0] === 'Content-Type');
34 return found ? found[1] : undefined;
35 }
36 return headers['Content-Type'];
37 });
38
39let getCredentials = (function(calls) {
40 return calls[0].init.credentials;
41 });
42
43Vitest.describe("Fetch", () => {
44 Vitest.test("GET request returns user-defined response variant", async t => {
45 let json = Object.fromEntries([[
46 "name",
47 "test"
48 ]]);
49 mockFetchJson(json, 200, "OK");
50 let result = await Fetch.send(Fetch.onResponse(Fetch.get("http://example.com/api"), json => {
51 let dict = Core__JSON.Decode.object(json);
52 if (dict === undefined) {
53 return {
54 NAME: "DecodeError",
55 VAL: "not an object"
56 };
57 }
58 let name = dict["name"];
59 if (name === undefined) {
60 return {
61 NAME: "DecodeError",
62 VAL: "name missing"
63 };
64 }
65 let s = Core__JSON.Decode.string(name);
66 if (s !== undefined) {
67 return {
68 NAME: "Success",
69 VAL: s
70 };
71 } else {
72 return {
73 NAME: "DecodeError",
74 VAL: "name not string"
75 };
76 }
77 }, (status, message) => ({
78 NAME: "APIError",
79 VAL: [
80 status,
81 message
82 ]
83 })));
84 t.expect(result).toEqual({
85 NAME: "Success",
86 VAL: "test"
87 });
88 });
89 Vitest.test("POST request sends body and auto-sets content-type", async t => {
90 let body = Object.fromEntries([[
91 "data",
92 "value"
93 ]]);
94 let responseJson = Object.fromEntries([[
95 "id",
96 123
97 ]]);
98 mockFetchJson(responseJson, 201, "Created");
99 let result = await Fetch.send(Fetch.onResponse(Fetch.setBody(Fetch.post("http://example.com/api"), body), json => {
100 let dict = Core__JSON.Decode.object(json);
101 if (dict === undefined) {
102 return {
103 NAME: "DecodeError",
104 VAL: "not an object"
105 };
106 }
107 let id = dict["id"];
108 if (id === undefined) {
109 return {
110 NAME: "DecodeError",
111 VAL: "id missing"
112 };
113 }
114 let f = Core__JSON.Decode.float(id);
115 if (f !== undefined) {
116 return {
117 NAME: "Created",
118 VAL: f | 0
119 };
120 } else {
121 return {
122 NAME: "DecodeError",
123 VAL: "id not number"
124 };
125 }
126 }, (status, message) => ({
127 NAME: "APIError",
128 VAL: [
129 status,
130 message
131 ]
132 })));
133 t.expect(result).toEqual({
134 NAME: "Created",
135 VAL: 123
136 });
137 });
138 Vitest.test("POST auto-sets content-type header", async t => {
139 let _calls = setupMockWithCapture();
140 await Fetch.send(Fetch.onResponse(Fetch.setBody(Fetch.post("http://example.com/api"), "test body"), _json => ({
141 NAME: "Success",
142 VAL: true
143 }), (_status, _message) => ({
144 NAME: "Success",
145 VAL: false
146 })));
147 let ct = getContentType(_calls);
148 t.expect(ct).toEqual("application/json");
149 });
150 Vitest.test("POST does not override custom content-type", async t => {
151 let _calls = setupMockWithCapture();
152 await Fetch.send(Fetch.onResponse(Fetch.setBody(Fetch.setHeader(Fetch.post("http://example.com/api"), "Content-Type", "text/plain"), "test body"), _json => ({
153 NAME: "Success",
154 VAL: true
155 }), (_status, _message) => ({
156 NAME: "Success",
157 VAL: false
158 })));
159 let ct = getContentType(_calls);
160 t.expect(ct).toEqual("text/plain");
161 });
162 Vitest.test("error response triggers onError", async t => {
163 let errorJson = Object.fromEntries([[
164 "error",
165 "not found"
166 ]]);
167 mockFetchJson(errorJson, 404, "Not Found");
168 let result = await Fetch.send(Fetch.onResponse(Fetch.get("http://example.com/api"), _json => ({
169 NAME: "Success",
170 VAL: 0
171 }), (status, message) => {
172 if (status === 404 && message === "not found") {
173 return "NotFound";
174 } else {
175 return "OtherError";
176 }
177 }));
178 t.expect(result).toEqual("NotFound");
179 });
180 Vitest.test("promise returns a rescript promise", async t => {
181 let json = Object.fromEntries([[
182 "value",
183 42
184 ]]);
185 mockFetchJson(json, 200, "OK");
186 let p = Fetch.promise(Fetch.onResponse(Fetch.get("http://example.com/api"), json => {
187 let dict = Core__JSON.Decode.object(json);
188 if (dict === undefined) {
189 return {
190 NAME: "DecodeError",
191 VAL: "not an object"
192 };
193 }
194 let v = dict["value"];
195 if (v === undefined) {
196 return {
197 NAME: "DecodeError",
198 VAL: "value missing"
199 };
200 }
201 let f = Core__JSON.Decode.float(v);
202 if (f !== undefined) {
203 return {
204 NAME: "Success",
205 VAL: f | 0
206 };
207 } else {
208 return {
209 NAME: "DecodeError",
210 VAL: "value not number"
211 };
212 }
213 }, (status, message) => ({
214 NAME: "APIError",
215 VAL: [
216 status,
217 message
218 ]
219 })));
220 let result = await p;
221 t.expect(result).toEqual({
222 NAME: "Success",
223 VAL: 42
224 });
225 });
226 Vitest.test("DELETE request works", async t => {
227 mockFetchJson(null, 204, "No Content");
228 let result = await Fetch.send(Fetch.onResponse(Fetch.$$delete("http://example.com/api/1"), _json => "Deleted", (_status, _message) => "Failed"));
229 t.expect(result).toEqual("Deleted");
230 });
231 Vitest.test("default credentials is same-origin", async t => {
232 let _calls = setupMockWithCapture();
233 await Fetch.send(Fetch.onResponse(Fetch.get("http://example.com/api"), _json => ({
234 NAME: "Success",
235 VAL: true
236 }), (_status, _message) => ({
237 NAME: "Success",
238 VAL: false
239 })));
240 let creds = getCredentials(_calls);
241 t.expect(creds).toEqual("same-origin");
242 });
243 Vitest.test("credentials omit sets omit", async t => {
244 let _calls = setupMockWithCapture();
245 await Fetch.send(Fetch.onResponse(Fetch.credentials(Fetch.get("http://example.com/api"), "omit"), _json => ({
246 NAME: "Success",
247 VAL: true
248 }), (_status, _message) => ({
249 NAME: "Success",
250 VAL: false
251 })));
252 let creds = getCredentials(_calls);
253 t.expect(creds).toEqual("omit");
254 });
255 Vitest.test("credentials include sets include", async t => {
256 let _calls = setupMockWithCapture();
257 await Fetch.send(Fetch.onResponse(Fetch.credentials(Fetch.post("http://example.com/api"), "include"), _json => ({
258 NAME: "Success",
259 VAL: true
260 }), (_status, _message) => ({
261 NAME: "Success",
262 VAL: false
263 })));
264 let creds = getCredentials(_calls);
265 t.expect(creds).toEqual("include");
266 });
267 Vitest.test("abort triggers onAbort handler", async t => {
268 let controller = new AbortController();
269 (((() => {
270 globalThis.fetch = vi.fn((url, init) => {
271 return new Promise((resolve, reject) => {
272 // Listen for abort
273 if (init.signal) {
274 init.signal.addEventListener('abort', () => {
275 reject(new DOMException('The operation was aborted', 'AbortError'));
276 });
277 }
278 // Never resolve - wait for abort
279 });
280 });
281 })()));
282 let p = Fetch.promise(Fetch.onResponse(Fetch.withAbortController(Fetch.get("http://example.com/api"), controller, () => "Aborted"), _json => ({
283 NAME: "Success",
284 VAL: true
285 }), (_status, _message) => "Error"));
286 await (new Promise(r => setTimeout(r, 10)));
287 controller.abort();
288 let result = await p;
289 t.expect(result).toEqual("Aborted");
290 });
291 Vitest.test("abort after completion is no-op", async t => {
292 let controller = new AbortController();
293 let json = Object.fromEntries([[
294 "data",
295 "value"
296 ]]);
297 mockFetchJson(json, 200, "OK");
298 let p = Fetch.promise(Fetch.onResponse(Fetch.withAbortController(Fetch.get("http://example.com/api"), controller, () => "Aborted"), _json => ({
299 NAME: "Success",
300 VAL: true
301 }), (_status, _message) => "Error"));
302 let result = await p;
303 controller.abort();
304 t.expect(result).toEqual({
305 NAME: "Success",
306 VAL: true
307 });
308 });
309 Vitest.test("request with abort controller completes normally", async t => {
310 let controller = new AbortController();
311 let json = Object.fromEntries([[
312 "name",
313 "test"
314 ]]);
315 mockFetchJson(json, 200, "OK");
316 let result = await Fetch.send(Fetch.onResponse(Fetch.withAbortController(Fetch.get("http://example.com/api"), controller, () => "Aborted"), json => {
317 let dict = Core__JSON.Decode.object(json);
318 if (dict === undefined) {
319 return {
320 NAME: "DecodeError",
321 VAL: "not object"
322 };
323 }
324 let name = dict["name"];
325 if (name === undefined) {
326 return {
327 NAME: "DecodeError",
328 VAL: "missing"
329 };
330 }
331 let s = Core__JSON.Decode.string(name);
332 if (s !== undefined) {
333 return {
334 NAME: "Success",
335 VAL: s
336 };
337 } else {
338 return {
339 NAME: "DecodeError",
340 VAL: "not string"
341 };
342 }
343 }, (_status, _message) => "Error"));
344 t.expect(result).toEqual({
345 NAME: "Success",
346 VAL: "test"
347 });
348 });
349});
350
351export {
352 mockFetchJson,
353 setupMockWithCapture,
354 getContentType,
355 getCredentials,
356}
357/* Not a pure module */