@plowtech/rescript-fetch 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +5 -0
- package/package.json +38 -0
- package/rescript.json +35 -0
- package/src/Fetch.res +561 -0
- package/src/Fetch.res.js +420 -0
- package/src/Fetch.resi +337 -0
- package/tests/FetchTest.res +155 -0
- package/tests/FetchTest.res.js +162 -0
- package/tests/utils/Assert.res +20 -0
- package/tests/utils/Assert.res.js +25 -0
- package/tests/utils/ReactTest.res +47 -0
- package/tests/utils/ReactTest.res.js +41 -0
package/src/Fetch.resi
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
type body
|
|
2
|
+
type bodyInit
|
|
3
|
+
type headers
|
|
4
|
+
type headersInit
|
|
5
|
+
type response
|
|
6
|
+
type request
|
|
7
|
+
type requestInit
|
|
8
|
+
|
|
9
|
+
// external
|
|
10
|
+
type arrayBuffer /* TypedArray */
|
|
11
|
+
type blob /* FileAPI */
|
|
12
|
+
type bufferSource /* Web IDL, either an arrayBuffer or arrayBufferView */
|
|
13
|
+
type formData /* XMLHttpRequest */
|
|
14
|
+
type readableStream /* Streams */
|
|
15
|
+
type urlSearchParams /* URL */
|
|
16
|
+
type abortController
|
|
17
|
+
type signal
|
|
18
|
+
|
|
19
|
+
type requestMethod =
|
|
20
|
+
| Get
|
|
21
|
+
| Head
|
|
22
|
+
| Post
|
|
23
|
+
| Put
|
|
24
|
+
| Delete
|
|
25
|
+
| Connect
|
|
26
|
+
| Options
|
|
27
|
+
| Trace
|
|
28
|
+
| Patch
|
|
29
|
+
| Other(string)
|
|
30
|
+
|
|
31
|
+
module AbortController: {
|
|
32
|
+
/* Experimental API */
|
|
33
|
+
type t = abortController
|
|
34
|
+
|
|
35
|
+
/* Experimental API */
|
|
36
|
+
@get
|
|
37
|
+
external signal: t => signal = "signal"
|
|
38
|
+
|
|
39
|
+
/* Experimental API */
|
|
40
|
+
@send
|
|
41
|
+
external abort: t => unit = "abort"
|
|
42
|
+
|
|
43
|
+
/* Experimental API */
|
|
44
|
+
@new
|
|
45
|
+
external make: unit => t = "AbortController"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type referrerPolicy =
|
|
49
|
+
| None
|
|
50
|
+
| NoReferrer
|
|
51
|
+
| NoReferrerWhenDowngrade
|
|
52
|
+
| SameOrigin
|
|
53
|
+
| Origin
|
|
54
|
+
| StrictOrigin
|
|
55
|
+
| OriginWhenCrossOrigin
|
|
56
|
+
| StrictOriginWhenCrossOrigin
|
|
57
|
+
| UnsafeUrl
|
|
58
|
+
|
|
59
|
+
type requestType =
|
|
60
|
+
| None /* default? unknown? just empty string in spec */
|
|
61
|
+
| Audio
|
|
62
|
+
| Font
|
|
63
|
+
| Image
|
|
64
|
+
| Script
|
|
65
|
+
| Style
|
|
66
|
+
| Track
|
|
67
|
+
| Video
|
|
68
|
+
|
|
69
|
+
type requestDestination =
|
|
70
|
+
| None /* default? unknown? just empty string in spec */
|
|
71
|
+
| Document
|
|
72
|
+
| Embed
|
|
73
|
+
| Font
|
|
74
|
+
| Image
|
|
75
|
+
| Manifest
|
|
76
|
+
| Media
|
|
77
|
+
| Object
|
|
78
|
+
| Report
|
|
79
|
+
| Script
|
|
80
|
+
| ServiceWorker
|
|
81
|
+
| SharedWorker
|
|
82
|
+
| Style
|
|
83
|
+
| Worker
|
|
84
|
+
| Xslt
|
|
85
|
+
|
|
86
|
+
type requestMode =
|
|
87
|
+
| Navigate
|
|
88
|
+
| SameOrigin
|
|
89
|
+
| NoCORS
|
|
90
|
+
| CORS
|
|
91
|
+
|
|
92
|
+
type requestCredentials =
|
|
93
|
+
| Omit
|
|
94
|
+
| SameOrigin
|
|
95
|
+
| Include
|
|
96
|
+
|
|
97
|
+
type requestCache =
|
|
98
|
+
| Default
|
|
99
|
+
| NoStore
|
|
100
|
+
| Reload
|
|
101
|
+
| NoCache
|
|
102
|
+
| ForceCache
|
|
103
|
+
| OnlyIfCached
|
|
104
|
+
|
|
105
|
+
type requestRedirect =
|
|
106
|
+
| Follow
|
|
107
|
+
| Error
|
|
108
|
+
| Manual
|
|
109
|
+
|
|
110
|
+
module HeadersInit: {
|
|
111
|
+
type t = headersInit
|
|
112
|
+
|
|
113
|
+
external make: Js.t<{..}> => t = "%identity"
|
|
114
|
+
external makeWithDict: Js.Dict.t<string> => t = "%identity"
|
|
115
|
+
external makeWithArray: array<(string, string)> => t = "%identity"
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
module Headers: {
|
|
119
|
+
type t = headers
|
|
120
|
+
|
|
121
|
+
@new
|
|
122
|
+
external make: t = "Headers"
|
|
123
|
+
|
|
124
|
+
@new
|
|
125
|
+
external makeWithInit: headersInit => t = "Headers"
|
|
126
|
+
|
|
127
|
+
@send
|
|
128
|
+
external append: (t, string, string) => unit = "append"
|
|
129
|
+
|
|
130
|
+
@send
|
|
131
|
+
external delete: (t, string) => unit = "delete"
|
|
132
|
+
|
|
133
|
+
@send @return(nullable)
|
|
134
|
+
external get: (t, string) => option<string> = "get"
|
|
135
|
+
|
|
136
|
+
@send
|
|
137
|
+
external has: (t, string) => bool = "has"
|
|
138
|
+
|
|
139
|
+
@send
|
|
140
|
+
external set: (t, string, string) => unit = "set"
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module BodyInit: {
|
|
144
|
+
type t = bodyInit
|
|
145
|
+
|
|
146
|
+
external make: string => t = "%identity"
|
|
147
|
+
external makeWithBlob: blob => t = "%identity"
|
|
148
|
+
external makeWithBufferSource: bufferSource => t = "%identity"
|
|
149
|
+
external makeWithFormData: formData => t = "%identity"
|
|
150
|
+
external makeWithUrlSearchParams: urlSearchParams => t = "%identity"
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module Body: {
|
|
154
|
+
type t = body
|
|
155
|
+
|
|
156
|
+
@get
|
|
157
|
+
external body: t => readableStream = "body"
|
|
158
|
+
|
|
159
|
+
@get
|
|
160
|
+
external bodyUsed: t => bool = "bodyUsed"
|
|
161
|
+
|
|
162
|
+
@send
|
|
163
|
+
external arrayBuffer: t => Js.Promise.t<arrayBuffer> = "arrayBuffer"
|
|
164
|
+
|
|
165
|
+
@send
|
|
166
|
+
external blob: t => Js.Promise.t<blob> = "blob"
|
|
167
|
+
|
|
168
|
+
@send
|
|
169
|
+
external formData: t => Js.Promise.t<formData> = "formData"
|
|
170
|
+
|
|
171
|
+
@send
|
|
172
|
+
external json: t => Js.Promise.t<Js.Json.t> = "json"
|
|
173
|
+
|
|
174
|
+
@send
|
|
175
|
+
external text: t => Js.Promise.t<string> = "text"
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
module RequestInit: {
|
|
179
|
+
type t = requestInit
|
|
180
|
+
|
|
181
|
+
let make: (
|
|
182
|
+
~method_: requestMethod=?,
|
|
183
|
+
~headers: headersInit=?,
|
|
184
|
+
~body: bodyInit=?,
|
|
185
|
+
~referrer: string=?,
|
|
186
|
+
~referrerPolicy: referrerPolicy=?,
|
|
187
|
+
~mode: requestMode=?,
|
|
188
|
+
~credentials: requestCredentials=?,
|
|
189
|
+
~cache: requestCache=?,
|
|
190
|
+
~redirect: requestRedirect=?,
|
|
191
|
+
~integrity: string=?,
|
|
192
|
+
~keepalive: bool=?,
|
|
193
|
+
~signal: signal=?,
|
|
194
|
+
unit,
|
|
195
|
+
) => t
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
module Request: {
|
|
199
|
+
type t = request
|
|
200
|
+
|
|
201
|
+
@new
|
|
202
|
+
external make: string => t = "Request"
|
|
203
|
+
@new
|
|
204
|
+
external makeWithInit: (string, requestInit) => t = "Request"
|
|
205
|
+
@new
|
|
206
|
+
external makeWithRequest: t => t = "Request"
|
|
207
|
+
@new
|
|
208
|
+
external makeWithRequestInit: (t, requestInit) => t = "Request"
|
|
209
|
+
|
|
210
|
+
let method_: t => requestMethod
|
|
211
|
+
|
|
212
|
+
@get
|
|
213
|
+
external url: t => string = "url"
|
|
214
|
+
|
|
215
|
+
@get
|
|
216
|
+
external headers: t => headers = "headers"
|
|
217
|
+
|
|
218
|
+
let type_: t => requestType
|
|
219
|
+
|
|
220
|
+
let destination: t => requestDestination
|
|
221
|
+
|
|
222
|
+
@get
|
|
223
|
+
external referrer: t => string = "referrer"
|
|
224
|
+
|
|
225
|
+
let referrerPolicy: t => referrerPolicy
|
|
226
|
+
|
|
227
|
+
let mode: t => requestMode
|
|
228
|
+
|
|
229
|
+
let credentials: t => requestCredentials
|
|
230
|
+
|
|
231
|
+
let cache: t => requestCache
|
|
232
|
+
|
|
233
|
+
let redirect: t => requestRedirect
|
|
234
|
+
|
|
235
|
+
@get
|
|
236
|
+
external integrity: t => string = "integrity"
|
|
237
|
+
|
|
238
|
+
@get
|
|
239
|
+
external keepalive: t => bool = "keepalive"
|
|
240
|
+
|
|
241
|
+
@get
|
|
242
|
+
external signal: t => signal = "signal"
|
|
243
|
+
|
|
244
|
+
/* Body Impl */
|
|
245
|
+
@get
|
|
246
|
+
external body: t => readableStream = "body"
|
|
247
|
+
|
|
248
|
+
@get
|
|
249
|
+
external bodyUsed: t => bool = "bodyUsed"
|
|
250
|
+
|
|
251
|
+
@send
|
|
252
|
+
external arrayBuffer: t => Js.Promise.t<arrayBuffer> = "arrayBuffer"
|
|
253
|
+
|
|
254
|
+
@send
|
|
255
|
+
external blob: t => Js.Promise.t<blob> = "blob"
|
|
256
|
+
|
|
257
|
+
@send
|
|
258
|
+
external formData: t => Js.Promise.t<formData> = "formData"
|
|
259
|
+
|
|
260
|
+
@send
|
|
261
|
+
external json: t => Js.Promise.t<Js.Json.t> = "json"
|
|
262
|
+
|
|
263
|
+
@send
|
|
264
|
+
external text: t => Js.Promise.t<string> = "text"
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
module Response: {
|
|
268
|
+
type t = response
|
|
269
|
+
|
|
270
|
+
@val
|
|
271
|
+
external error: unit => t = "error"
|
|
272
|
+
|
|
273
|
+
@val
|
|
274
|
+
external redirect: string => t = "redirect"
|
|
275
|
+
|
|
276
|
+
@val
|
|
277
|
+
external redirectWithStatus: (string, int) => t = "redirect"
|
|
278
|
+
|
|
279
|
+
@get
|
|
280
|
+
external headers: t => headers = "headers"
|
|
281
|
+
|
|
282
|
+
@get
|
|
283
|
+
external ok: t => bool = "ok"
|
|
284
|
+
|
|
285
|
+
@get
|
|
286
|
+
external redirected: t => bool = "redirected"
|
|
287
|
+
|
|
288
|
+
@get
|
|
289
|
+
external status: t => int = "status"
|
|
290
|
+
|
|
291
|
+
@get
|
|
292
|
+
external statusText: t => string = "statusText"
|
|
293
|
+
|
|
294
|
+
@get
|
|
295
|
+
external _type: t => string = "_type"
|
|
296
|
+
|
|
297
|
+
@get
|
|
298
|
+
external url: t => string = "url"
|
|
299
|
+
|
|
300
|
+
@send
|
|
301
|
+
external clone: t => t = "clone"
|
|
302
|
+
|
|
303
|
+
/* Body.Impl */
|
|
304
|
+
|
|
305
|
+
@get
|
|
306
|
+
external body: t => readableStream = "body"
|
|
307
|
+
|
|
308
|
+
@get
|
|
309
|
+
external bodyUsed: t => bool = "bodyUsed"
|
|
310
|
+
|
|
311
|
+
@send
|
|
312
|
+
external arrayBuffer: t => Js.Promise.t<arrayBuffer> = "arrayBuffer"
|
|
313
|
+
|
|
314
|
+
@send
|
|
315
|
+
external blob: t => Js.Promise.t<blob> = "blob"
|
|
316
|
+
|
|
317
|
+
@send
|
|
318
|
+
external formData: t => Js.Promise.t<formData> = "formData"
|
|
319
|
+
|
|
320
|
+
@send
|
|
321
|
+
external json: t => Js.Promise.t<Js.Json.t> = "json"
|
|
322
|
+
|
|
323
|
+
@send
|
|
324
|
+
external text: t => Js.Promise.t<string> = "text"
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
@val
|
|
328
|
+
external fetch: string => Js.Promise.t<response> = "fetch"
|
|
329
|
+
|
|
330
|
+
@val
|
|
331
|
+
external fetchWithInit: (string, requestInit) => Js.Promise.t<response> = "fetch"
|
|
332
|
+
|
|
333
|
+
@val
|
|
334
|
+
external fetchWithRequest: request => Js.Promise.t<response> = "fetch"
|
|
335
|
+
|
|
336
|
+
@val
|
|
337
|
+
external fetchWithRequestInit: (request, requestInit) => Js.Promise.t<response> = "fetch"
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
open ReactTest
|
|
2
|
+
|
|
3
|
+
let placeholderText = `{"userId":1,"id":1,"title":"delectus aut autem","completed":false}`
|
|
4
|
+
let postPlaceholderText = `{"title":"foo","body":"bar","userId":1,"id":101}`
|
|
5
|
+
|
|
6
|
+
module Hooks = {
|
|
7
|
+
let useFetch = () => {
|
|
8
|
+
let (state, setState) = React.useState(() => None)
|
|
9
|
+
|
|
10
|
+
React.useEffect0(() => {
|
|
11
|
+
let promise = async () => {
|
|
12
|
+
let response = await Fetch.fetch("https://jsonplaceholder.typicode.com/todos/1")
|
|
13
|
+
let body = await response->Fetch.Response.json
|
|
14
|
+
|
|
15
|
+
setState(_ => Some(body))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
promise()->Promise.thenResolve(_ => ())->ignore
|
|
19
|
+
|
|
20
|
+
None
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
state
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let useFetchWithInit = () => {
|
|
27
|
+
let (state, setState) = React.useState(() => None)
|
|
28
|
+
|
|
29
|
+
React.useEffect0(() => {
|
|
30
|
+
let promise = async () => {
|
|
31
|
+
let response = await Fetch.fetchWithInit(
|
|
32
|
+
"https://jsonplaceholder.typicode.com/todos/1",
|
|
33
|
+
Fetch.RequestInit.make(~method_=Get, ()),
|
|
34
|
+
)
|
|
35
|
+
let body = await response->Fetch.Response.json
|
|
36
|
+
|
|
37
|
+
setState(_ => Some(body))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
promise()->Promise.thenResolve(_ => ())->ignore
|
|
41
|
+
|
|
42
|
+
None
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
state
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let usePostFetchWithInit = () => {
|
|
49
|
+
let postBody = {
|
|
50
|
+
"title": "foo",
|
|
51
|
+
"body": "bar",
|
|
52
|
+
"userId": 1,
|
|
53
|
+
}
|
|
54
|
+
let (state, setState) = React.useState(() => None)
|
|
55
|
+
|
|
56
|
+
React.useEffect0(() => {
|
|
57
|
+
let promise = async () => {
|
|
58
|
+
let body = Fetch.BodyInit.make(JSON.stringifyAny(postBody)->Option.getOr(""))
|
|
59
|
+
let headers = Fetch.HeadersInit.makeWithArray([
|
|
60
|
+
("Accept", "application/json"),
|
|
61
|
+
("Content-Type", "application/json"),
|
|
62
|
+
])
|
|
63
|
+
let response = await Fetch.fetchWithInit(
|
|
64
|
+
"https://jsonplaceholder.typicode.com/posts",
|
|
65
|
+
Fetch.RequestInit.make(~method_=Post, ~headers, ~body, ()),
|
|
66
|
+
)
|
|
67
|
+
let body = await response->Fetch.Response.json
|
|
68
|
+
|
|
69
|
+
setState(_ => Some(body))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
promise()->Promise.thenResolve(_ => ())->ignore
|
|
73
|
+
|
|
74
|
+
None
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
state
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module Home = {
|
|
82
|
+
@react.component
|
|
83
|
+
let make = (~fetchHok: unit => option<JSON.t>) => {
|
|
84
|
+
let jsonPlaceholder = fetchHok()
|
|
85
|
+
|
|
86
|
+
<div id="placeholder">
|
|
87
|
+
{React.string(jsonPlaceholder->Option.mapOr("Loading...", JSON.stringify(_)))}
|
|
88
|
+
</div>
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@get external textContent: Dom.element => string = "textContent"
|
|
93
|
+
|
|
94
|
+
testAsyncWithReact("fetch", (root, done) => {
|
|
95
|
+
let promise = async () => {
|
|
96
|
+
let _ = await act(async () => {
|
|
97
|
+
root->ReactDOM.Client.Root.render(<Home fetchHok=Hooks.useFetch />)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
let _ = await screen->findByText(placeholderText)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
promise()
|
|
104
|
+
->Promise.thenResolve(_ => {
|
|
105
|
+
Assert.elementContains(
|
|
106
|
+
~message="has result",
|
|
107
|
+
ReactDOM.querySelector("#placeholder"),
|
|
108
|
+
placeholderText,
|
|
109
|
+
)
|
|
110
|
+
done()
|
|
111
|
+
})
|
|
112
|
+
->ignore
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
testAsyncWithReact("fetchWithInit", (root, done) => {
|
|
116
|
+
let promise = async () => {
|
|
117
|
+
let _ = await act(async () => {
|
|
118
|
+
root->ReactDOM.Client.Root.render(<Home fetchHok=Hooks.useFetchWithInit />)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
let _ = await screen->findByText(placeholderText)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
promise()
|
|
125
|
+
->Promise.thenResolve(_ => {
|
|
126
|
+
Assert.elementContains(
|
|
127
|
+
~message="has result",
|
|
128
|
+
ReactDOM.querySelector("#placeholder"),
|
|
129
|
+
placeholderText,
|
|
130
|
+
)
|
|
131
|
+
done()
|
|
132
|
+
})
|
|
133
|
+
->ignore
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
testAsyncWithReact("postFetchWithInit", (root, done) => {
|
|
137
|
+
let promise = async () => {
|
|
138
|
+
let _ = await act(async () => {
|
|
139
|
+
root->ReactDOM.Client.Root.render(<Home fetchHok=Hooks.usePostFetchWithInit />)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
let _ = await screen->findByText(postPlaceholderText)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
promise()
|
|
146
|
+
->Promise.thenResolve(_ => {
|
|
147
|
+
Assert.elementContains(
|
|
148
|
+
~message="has result",
|
|
149
|
+
ReactDOM.querySelector("#placeholder"),
|
|
150
|
+
postPlaceholderText,
|
|
151
|
+
)
|
|
152
|
+
done()
|
|
153
|
+
})
|
|
154
|
+
->ignore
|
|
155
|
+
})
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var Fetch = require("../src/Fetch.res.js");
|
|
5
|
+
var React = require("react");
|
|
6
|
+
var Assert = require("./utils/Assert.res.js");
|
|
7
|
+
var ReactTest = require("./utils/ReactTest.res.js");
|
|
8
|
+
var Caml_option = require("rescript/lib/js/caml_option.js");
|
|
9
|
+
var Core__Option = require("@rescript/core/src/Core__Option.res.js");
|
|
10
|
+
var JsxRuntime = require("react/jsx-runtime");
|
|
11
|
+
var React$1 = require("@testing-library/react");
|
|
12
|
+
|
|
13
|
+
var placeholderText = "{\"userId\":1,\"id\":1,\"title\":\"delectus aut autem\",\"completed\":false}";
|
|
14
|
+
|
|
15
|
+
var postPlaceholderText = "{\"title\":\"foo\",\"body\":\"bar\",\"userId\":1,\"id\":101}";
|
|
16
|
+
|
|
17
|
+
function useFetch() {
|
|
18
|
+
var match = React.useState(function () {
|
|
19
|
+
|
|
20
|
+
});
|
|
21
|
+
var setState = match[1];
|
|
22
|
+
React.useEffect((function () {
|
|
23
|
+
var promise = async function () {
|
|
24
|
+
var response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
|
|
25
|
+
var body = await response.json();
|
|
26
|
+
return setState(function (param) {
|
|
27
|
+
return body;
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
promise().then(function () {
|
|
31
|
+
|
|
32
|
+
});
|
|
33
|
+
}), []);
|
|
34
|
+
return match[0];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function useFetchWithInit() {
|
|
38
|
+
var match = React.useState(function () {
|
|
39
|
+
|
|
40
|
+
});
|
|
41
|
+
var setState = match[1];
|
|
42
|
+
React.useEffect((function () {
|
|
43
|
+
var promise = async function () {
|
|
44
|
+
var response = await fetch("https://jsonplaceholder.typicode.com/todos/1", Fetch.RequestInit.make("Get", undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined));
|
|
45
|
+
var body = await response.json();
|
|
46
|
+
return setState(function (param) {
|
|
47
|
+
return body;
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
promise().then(function () {
|
|
51
|
+
|
|
52
|
+
});
|
|
53
|
+
}), []);
|
|
54
|
+
return match[0];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function usePostFetchWithInit() {
|
|
58
|
+
var postBody = {
|
|
59
|
+
title: "foo",
|
|
60
|
+
body: "bar",
|
|
61
|
+
userId: 1
|
|
62
|
+
};
|
|
63
|
+
var match = React.useState(function () {
|
|
64
|
+
|
|
65
|
+
});
|
|
66
|
+
var setState = match[1];
|
|
67
|
+
React.useEffect((function () {
|
|
68
|
+
var promise = async function () {
|
|
69
|
+
var body = Core__Option.getOr(JSON.stringify(postBody), "");
|
|
70
|
+
var headers = [
|
|
71
|
+
[
|
|
72
|
+
"Accept",
|
|
73
|
+
"application/json"
|
|
74
|
+
],
|
|
75
|
+
[
|
|
76
|
+
"Content-Type",
|
|
77
|
+
"application/json"
|
|
78
|
+
]
|
|
79
|
+
];
|
|
80
|
+
var response = await fetch("https://jsonplaceholder.typicode.com/posts", Fetch.RequestInit.make("Post", Caml_option.some(headers), Caml_option.some(body), undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined));
|
|
81
|
+
var body$1 = await response.json();
|
|
82
|
+
return setState(function (param) {
|
|
83
|
+
return body$1;
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
promise().then(function () {
|
|
87
|
+
|
|
88
|
+
});
|
|
89
|
+
}), []);
|
|
90
|
+
return match[0];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
var Hooks = {
|
|
94
|
+
useFetch: useFetch,
|
|
95
|
+
useFetchWithInit: useFetchWithInit,
|
|
96
|
+
usePostFetchWithInit: usePostFetchWithInit
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
function FetchTest$Home(props) {
|
|
100
|
+
var jsonPlaceholder = props.fetchHok();
|
|
101
|
+
return JsxRuntime.jsx("div", {
|
|
102
|
+
children: Core__Option.mapOr(jsonPlaceholder, "Loading...", (function (__x) {
|
|
103
|
+
return JSON.stringify(__x);
|
|
104
|
+
})),
|
|
105
|
+
id: "placeholder"
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
var Home = {
|
|
110
|
+
make: FetchTest$Home
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
ReactTest.testAsyncWithReact("fetch", undefined, (function (root, done) {
|
|
114
|
+
var promise = async function () {
|
|
115
|
+
await React$1.act(async function () {
|
|
116
|
+
root.render(JsxRuntime.jsx(FetchTest$Home, {
|
|
117
|
+
fetchHok: useFetch
|
|
118
|
+
}));
|
|
119
|
+
});
|
|
120
|
+
await React$1.screen.findByText(placeholderText);
|
|
121
|
+
};
|
|
122
|
+
promise().then(function () {
|
|
123
|
+
Assert.elementContains("has result", Caml_option.nullable_to_opt(document.querySelector("#placeholder")), placeholderText);
|
|
124
|
+
done(undefined, undefined);
|
|
125
|
+
});
|
|
126
|
+
}));
|
|
127
|
+
|
|
128
|
+
ReactTest.testAsyncWithReact("fetchWithInit", undefined, (function (root, done) {
|
|
129
|
+
var promise = async function () {
|
|
130
|
+
await React$1.act(async function () {
|
|
131
|
+
root.render(JsxRuntime.jsx(FetchTest$Home, {
|
|
132
|
+
fetchHok: useFetchWithInit
|
|
133
|
+
}));
|
|
134
|
+
});
|
|
135
|
+
await React$1.screen.findByText(placeholderText);
|
|
136
|
+
};
|
|
137
|
+
promise().then(function () {
|
|
138
|
+
Assert.elementContains("has result", Caml_option.nullable_to_opt(document.querySelector("#placeholder")), placeholderText);
|
|
139
|
+
done(undefined, undefined);
|
|
140
|
+
});
|
|
141
|
+
}));
|
|
142
|
+
|
|
143
|
+
ReactTest.testAsyncWithReact("postFetchWithInit", undefined, (function (root, done) {
|
|
144
|
+
var promise = async function () {
|
|
145
|
+
await React$1.act(async function () {
|
|
146
|
+
root.render(JsxRuntime.jsx(FetchTest$Home, {
|
|
147
|
+
fetchHok: usePostFetchWithInit
|
|
148
|
+
}));
|
|
149
|
+
});
|
|
150
|
+
await React$1.screen.findByText(postPlaceholderText);
|
|
151
|
+
};
|
|
152
|
+
promise().then(function () {
|
|
153
|
+
Assert.elementContains("has result", Caml_option.nullable_to_opt(document.querySelector("#placeholder")), postPlaceholderText);
|
|
154
|
+
done(undefined, undefined);
|
|
155
|
+
});
|
|
156
|
+
}));
|
|
157
|
+
|
|
158
|
+
exports.placeholderText = placeholderText;
|
|
159
|
+
exports.postPlaceholderText = postPlaceholderText;
|
|
160
|
+
exports.Hooks = Hooks;
|
|
161
|
+
exports.Home = Home;
|
|
162
|
+
/* Not a pure module */
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
open Test
|
|
2
|
+
|
|
3
|
+
@get external textContent: Dom.element => string = "textContent"
|
|
4
|
+
|
|
5
|
+
let isSome = (~message: string, value: option<'a>) =>
|
|
6
|
+
switch value {
|
|
7
|
+
| Some(_) => pass(~message, ())
|
|
8
|
+
| None => fail(~message="Expected Some, got None", ())
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let elementContains = (~message=?, element: option<Dom.element>, substring: string) =>
|
|
12
|
+
assertion(
|
|
13
|
+
~message?,
|
|
14
|
+
~operator="elementContains",
|
|
15
|
+
(textContent, substring) => {
|
|
16
|
+
textContent->String.includes(substring)
|
|
17
|
+
},
|
|
18
|
+
element->Option.mapOr("Not Found", element => element->textContent),
|
|
19
|
+
substring,
|
|
20
|
+
)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var Test = require("rescript-test/src/Test.res.js");
|
|
5
|
+
var Core__Option = require("@rescript/core/src/Core__Option.res.js");
|
|
6
|
+
|
|
7
|
+
function isSome(message, value) {
|
|
8
|
+
if (value !== undefined) {
|
|
9
|
+
return Test.pass(message, undefined);
|
|
10
|
+
} else {
|
|
11
|
+
return Test.fail("Expected Some, got None", undefined);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function elementContains(message, element, substring) {
|
|
16
|
+
Test.assertion(message, "elementContains", (function (textContent, substring) {
|
|
17
|
+
return textContent.includes(substring);
|
|
18
|
+
}), Core__Option.mapOr(element, "Not Found", (function (element) {
|
|
19
|
+
return element.textContent;
|
|
20
|
+
})), substring);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
exports.isSome = isSome;
|
|
24
|
+
exports.elementContains = elementContains;
|
|
25
|
+
/* Test Not a pure module */
|