@@ -3,6 +3,8 @@ import 'isomorphic-fetch'
3
3
import { beforeEach , describe , expect , it , vi } from 'vitest'
4
4
import { FetcherOptions , RequestPayload , fetcher } from './index'
5
5
6
+ const RANDOM_STRING = String ( Math . random ( ) )
7
+
6
8
describe ( 'fetcher' , ( ) => {
7
9
beforeEach ( ( ) => {
8
10
fetchMock . reset ( )
@@ -15,7 +17,7 @@ describe('fetcher', () => {
15
17
16
18
describe ( 'config options' , ( ) => {
17
19
describe ( 'base' , ( ) => {
18
- it ( " defaults to ''" , ( ) => {
20
+ it ( ` defaults to ''` , ( ) => {
19
21
expect ( fetcher ( ) . base ) . toBe ( '' )
20
22
} )
21
23
@@ -50,9 +52,69 @@ describe('fetcher', () => {
50
52
expect ( custom_fetch ) . toBeCalledWith ( '/foo' , {
51
53
method : 'GET' ,
52
54
body : undefined ,
53
- headers : { 'content-type' : 'application/json' } ,
55
+ headers : { } ,
56
+ } )
57
+ } )
58
+ } )
59
+
60
+ describe ( 'transformRequest' , ( ) => {
61
+ it ( 'can modify the request before sending' , async ( ) => {
62
+ fetchMock . get ( '/' , { status : 200 , body : 'Success' } )
63
+
64
+ const transformRequest = vi . fn ( r => {
65
+ r . url = '/'
66
+ return r
54
67
} )
68
+ const response = await fetcher ( { transformRequest } ) . get ( '/foo' )
69
+
70
+ expect ( transformRequest ) . toHaveBeenCalled ( )
71
+ expect ( response ) . toBe ( 'Success' )
72
+ } )
73
+
74
+ it ( 'can take an async function' , async ( ) => {
75
+ fetchMock . get ( '/' , { status : 200 , body : 'Success' } )
76
+
77
+ const transformRequest = async ( r ) => {
78
+ r . url = await '/'
79
+ return r
80
+ }
81
+
82
+ const response = await fetcher ( { transformRequest } ) . get ( '/foo' )
83
+
84
+ expect ( response ) . toBe ( 'Success' )
85
+ } )
86
+ } )
87
+ } )
88
+
89
+ describe ( 'error handling' , ( ) => {
90
+ it ( 'without response body' , async ( ) => {
91
+ fetchMock . get ( '/' , { status : 404 } )
92
+ const response : any = await fetcher ( ) . get ( '/' ) . catch ( e => e )
93
+
94
+ expect ( response . status ) . toBe ( 404 )
95
+ expect ( response . message ) . toBe ( 'Not Found' )
96
+ } )
97
+
98
+ it ( 'with text response body' , async ( ) => {
99
+ fetchMock . get ( '/' , { status : 404 , body : RANDOM_STRING } )
100
+ const response : any = await fetcher ( ) . get ( '/' ) . catch ( e => e )
101
+
102
+ expect ( response . status ) . toBe ( 404 )
103
+ expect ( response . message ) . toBe ( RANDOM_STRING )
104
+ } )
105
+
106
+ it ( 'with JSON response body' , async ( ) => {
107
+ fetchMock . get ( '/' , {
108
+ status : 404 ,
109
+ body : { error : 'Not Found' , details : RANDOM_STRING } ,
110
+ headers : { 'content-type' : 'application/json' } ,
55
111
} )
112
+ const catchError = vi . fn ( e => e )
113
+ const response : any = await fetcher ( ) . get ( '/' ) . catch ( catchError )
114
+
115
+ expect ( response . status ) . toBe ( 404 )
116
+ expect ( response . details ) . toBe ( RANDOM_STRING )
117
+ expect ( response . error ) . toBe ( 'Not Found' )
56
118
} )
57
119
} )
58
120
@@ -174,7 +236,6 @@ describe('fetcher', () => {
174
236
status : 500 ,
175
237
expected : { error : 'Internal Server Error' } ,
176
238
} ,
177
-
178
239
// global headers
179
240
'can set a header via global options as well as per-route overrides' : {
180
241
url : '/foo' ,
@@ -217,17 +278,17 @@ describe('fetcher', () => {
217
278
expected : { url : base + '/?message=hello+world' } ,
218
279
} ,
219
280
'combines query params from the URL and the payload (object)' : {
220
- payload : { foo : 10 } ,
281
+ url : '/somewhere?foo=10' ,
282
+ payload : { foo : 12 , bar : 'baz' } ,
221
283
options : {
222
284
base,
223
285
transformRequest ( req ) {
224
- const url = new URL ( req . url )
225
- url . searchParams . set ( 'message' , 'hello world' )
226
- req . url = url . toString ( )
286
+ console . log ( 'base' , base )
287
+ console . log ( 'REQUEST' , req . url )
227
288
return req
228
289
} ,
229
290
} ,
230
- expected : { url : base + '/?foo=10&message=hello+world ' } ,
291
+ expected : { url : base + '/somewhere ?foo=10&foo=12&bar=baz ' } ,
231
292
} ,
232
293
'combines query params from the URL and the payload (URLSearchParams)' : {
233
294
payload : new URLSearchParams ( [
@@ -304,6 +365,11 @@ describe('fetcher', () => {
304
365
if ( expected . error && status ) {
305
366
fetchMock . mock ( full_url , status )
306
367
await expect ( fetcher ( options ) [ method ] ( url , payload , init ) ) . rejects . toThrow ( expected . error )
368
+
369
+ if ( expected . response ) {
370
+ const getError = vi . fn ( ( { response, ...err } ) => ( { ...err } ) )
371
+ await expect ( getError ) . toHaveReturnedWith ( expected . response )
372
+ }
307
373
return
308
374
}
309
375
@@ -374,11 +440,16 @@ function create_mock_url({
374
440
// query params in the URL. To do this, we need to evaluate the payload
375
441
// and add it to the URL.
376
442
if ( method === 'get' && payload && typeof payload === 'object' && ! options ?. transformRequest ) {
377
- const url = new URL ( mock_url )
378
- url . search = (
379
- payload instanceof URLSearchParams ? payload : params_from_object ( payload )
380
- ) . toString ( )
381
- mock_url = url . toString ( )
443
+ try {
444
+ const url = new URL ( mock_url )
445
+ url . search = (
446
+ payload instanceof URLSearchParams ? payload : params_from_object ( payload )
447
+ ) . toString ( )
448
+ mock_url = url . toString ( )
449
+ } catch ( err ) {
450
+ console . error ( `Could not create url from ${ mock_url } .` )
451
+ }
382
452
}
453
+
383
454
return mock_url
384
455
}
0 commit comments