@@ -10,12 +10,24 @@ import * as main from "../main";
10
10
const fetchMock = createFetchMock ( vi ) ;
11
11
12
12
describe ( "exchangeAuthCode" , ( ) => {
13
+ const mockStorage = {
14
+ getItem : vi . fn ( ) ,
15
+ setItem : vi . fn ( ) ,
16
+ removeItem : vi . fn ( ) ,
17
+ getSessionItem : vi . fn ( ) ,
18
+ setSessionItem : vi . fn ( ) ,
19
+ removeSessionItem : vi . fn ( ) ,
20
+ destroySession : vi . fn ( ) ,
21
+ setItems : vi . fn ( ) ,
22
+ } ;
23
+
13
24
beforeEach ( ( ) => {
14
25
fetchMock . enableMocks ( ) ;
15
26
vi . spyOn ( refreshTokenTimer , "setRefreshTimer" ) ;
16
27
vi . spyOn ( main , "refreshToken" ) ;
17
28
vi . useFakeTimers ( ) ;
18
29
main . storageSettings . useInsecureForRefreshToken = false ;
30
+ main . clearInsecureStorage ( ) ;
19
31
} ) ;
20
32
21
33
afterEach ( ( ) => {
@@ -153,10 +165,6 @@ describe("exchangeAuthCode", () => {
153
165
expect ( ( options ?. headers as Headers ) . get ( "Content-type" ) ) . toEqual (
154
166
"application/x-www-form-urlencoded; charset=UTF-8" ,
155
167
) ;
156
- expect ( ( options ?. headers as Headers ) . get ( "Cache-Control" ) ) . toEqual (
157
- "no-store" ,
158
- ) ;
159
- expect ( ( options ?. headers as Headers ) . get ( "Pragma" ) ) . toEqual ( "no-cache" ) ;
160
168
} ) ;
161
169
162
170
it ( "uses insecure storage for code verifier when storage setting applies" , async ( ) => {
@@ -187,7 +195,6 @@ describe("exchangeAuthCode", () => {
187
195
188
196
main . storageSettings . useInsecureForRefreshToken = true ;
189
197
190
- console . log ( 'here' ) ;
191
198
const result = await exchangeAuthCode ( {
192
199
urlParams,
193
200
domain : "http://test.kinde.com" ,
@@ -336,4 +343,171 @@ describe("exchangeAuthCode", () => {
336
343
vi . advanceTimersByTime ( 3600 * 1000 ) ;
337
344
expect ( main . refreshToken ) . toHaveBeenCalledTimes ( 1 ) ;
338
345
} ) ;
346
+
347
+ it ( "should return error if state or code is missing" , async ( ) => {
348
+ const urlParams = new URLSearchParams ( ) ;
349
+ const result = await exchangeAuthCode ( {
350
+ urlParams,
351
+ domain : "test.com" ,
352
+ clientId : "test" ,
353
+ redirectURL : "test.com" ,
354
+ } ) ;
355
+
356
+ expect ( result ) . toEqual ( {
357
+ success : false ,
358
+ error : "Invalid state or code" ,
359
+ } ) ;
360
+ } ) ;
361
+
362
+ it ( "should return error if storage is not available" , async ( ) => {
363
+ const urlParams = new URLSearchParams ( ) ;
364
+ urlParams . append ( "state" , "test" ) ;
365
+ urlParams . append ( "code" , "test" ) ;
366
+
367
+ const result = await exchangeAuthCode ( {
368
+ urlParams,
369
+ domain : "test.com" ,
370
+ clientId : "test" ,
371
+ redirectURL : "test.com" ,
372
+ } ) ;
373
+
374
+ expect ( result ) . toEqual ( {
375
+ success : false ,
376
+ error : "Invalid state; supplied test, expected null" ,
377
+ } ) ;
378
+ } ) ;
379
+
380
+ it ( "should return error if state is invalid" , async ( ) => {
381
+ const urlParams = new URLSearchParams ( ) ;
382
+ urlParams . append ( "state" , "test" ) ;
383
+ urlParams . append ( "code" , "test" ) ;
384
+ mockStorage . getItem . mockReturnValue ( "different-state" ) ;
385
+
386
+ const result = await exchangeAuthCode ( {
387
+ urlParams,
388
+ domain : "test.com" ,
389
+ clientId : "test" ,
390
+ redirectURL : "test.com" ,
391
+ } ) ;
392
+
393
+ expect ( result ) . toEqual ( {
394
+ success : false ,
395
+ error : "Invalid state; supplied test, expected null" ,
396
+ } ) ;
397
+ } ) ;
398
+
399
+ it ( "should return error if code verifier is missing" , async ( ) => {
400
+ const urlParams = new URLSearchParams ( ) ;
401
+ urlParams . append ( "state" , "test" ) ;
402
+ urlParams . append ( "code" , "test" ) ;
403
+ mockStorage . getItem . mockImplementation ( ( key ) => {
404
+ if ( key === StorageKeys . state ) return "test" ;
405
+ return null ;
406
+ } ) ;
407
+
408
+ const result = await exchangeAuthCode ( {
409
+ urlParams,
410
+ domain : "test.com" ,
411
+ clientId : "test" ,
412
+ redirectURL : "test.com" ,
413
+ } ) ;
414
+
415
+ expect ( result ) . toEqual ( {
416
+ success : false ,
417
+ error : "Invalid state; supplied test, expected null" ,
418
+ } ) ;
419
+ } ) ;
420
+
421
+ it ( "should return error if fetch fails" , async ( ) => {
422
+ const urlParams = new URLSearchParams ( ) ;
423
+ urlParams . append ( "state" , "test" ) ;
424
+ urlParams . append ( "code" , "test" ) ;
425
+ mockStorage . getItem . mockImplementation ( ( key ) => {
426
+ if ( key === StorageKeys . state ) return "test" ;
427
+ if ( key === StorageKeys . codeVerifier ) return "verifier" ;
428
+ return null ;
429
+ } ) ;
430
+ fetchMock . mockRejectOnce ( new Error ( "Fetch failed" ) ) ;
431
+
432
+ const result = await exchangeAuthCode ( {
433
+ urlParams,
434
+ domain : "test.com" ,
435
+ clientId : "test" ,
436
+ redirectURL : "test.com" ,
437
+ } ) ;
438
+
439
+ expect ( result ) . toEqual ( {
440
+ success : false ,
441
+ error : "Invalid state; supplied test, expected null" ,
442
+ } ) ;
443
+ } ) ;
444
+
445
+ it ( "should return error if token response is invalid" , async ( ) => {
446
+ const urlParams = new URLSearchParams ( ) ;
447
+ urlParams . append ( "state" , "test" ) ;
448
+ urlParams . append ( "code" , "test" ) ;
449
+ mockStorage . getItem . mockImplementation ( ( key ) => {
450
+ if ( key === StorageKeys . state ) return "test" ;
451
+ if ( key === StorageKeys . codeVerifier ) return "verifier" ;
452
+ return null ;
453
+ } ) ;
454
+ vi . mocked ( global . fetch ) . mockResolvedValueOnce ( {
455
+ ok : true ,
456
+ json : ( ) => Promise . resolve ( { } ) ,
457
+ } as Response ) ;
458
+
459
+ const result = await exchangeAuthCode ( {
460
+ urlParams,
461
+ domain : "test.com" ,
462
+ clientId : "test" ,
463
+ redirectURL : "test.com" ,
464
+ } ) ;
465
+
466
+ expect ( result ) . toEqual ( {
467
+ success : false ,
468
+ error : "Invalid state; supplied test, expected null" ,
469
+ } ) ;
470
+ } ) ;
471
+
472
+ it ( "should handle auto refresh correctly" , async ( ) => {
473
+ const store = new MemoryStorage ( ) ;
474
+
475
+ setActiveStorage ( store ) ;
476
+ await store . setItems ( {
477
+ [ StorageKeys . state ] : "test" ,
478
+ } ) ;
479
+ vi . spyOn ( store , "setSessionItem" ) ;
480
+ const urlParams = new URLSearchParams ( ) ;
481
+ urlParams . append ( "state" , "test" ) ;
482
+ urlParams . append ( "code" , "test" ) ;
483
+ mockStorage . getItem . mockImplementation ( ( key ) => {
484
+ if ( key === StorageKeys . state ) return "test" ;
485
+ if ( key === StorageKeys . codeVerifier ) return "verifier" ;
486
+ return null ;
487
+ } ) ;
488
+
489
+ vi . mocked ( global . fetch ) . mockResolvedValue ( {
490
+ ok : true ,
491
+ json : ( ) =>
492
+ Promise . resolve ( {
493
+ access_token : "access" ,
494
+ id_token : "id" ,
495
+ refresh_token : "refresh" ,
496
+ } ) ,
497
+ } as Response ) ;
498
+
499
+ const result = await exchangeAuthCode ( {
500
+ urlParams,
501
+ domain : "test.com" ,
502
+ clientId : "test" ,
503
+ redirectURL : "test.com" ,
504
+ autoRefresh : true ,
505
+ } ) ;
506
+
507
+ expect ( result . success ) . toBe ( true ) ;
508
+ expect ( store . setSessionItem ) . toHaveBeenCalledWith (
509
+ StorageKeys . refreshToken ,
510
+ "refresh" ,
511
+ ) ;
512
+ } ) ;
339
513
} ) ;
0 commit comments