@@ -5,7 +5,13 @@ import {
5
5
hookWaitFor ,
6
6
setupApiStore ,
7
7
} from '../../tests/utils/helpers'
8
- import { renderHook , act , waitFor } from '@testing-library/react'
8
+ import {
9
+ render ,
10
+ renderHook ,
11
+ act ,
12
+ waitFor ,
13
+ screen ,
14
+ } from '@testing-library/react'
9
15
import { delay } from 'msw'
10
16
11
17
interface Post {
@@ -14,6 +20,11 @@ interface Post {
14
20
contents : string
15
21
}
16
22
23
+ interface FolderT {
24
+ id : number
25
+ children : FolderT [ ]
26
+ }
27
+
17
28
const baseQuery = vi . fn ( )
18
29
beforeEach ( ( ) => baseQuery . mockReset ( ) )
19
30
@@ -28,7 +39,7 @@ const api = createApi({
28
39
. catch ( ( e : any ) => ( { error : e } ) )
29
40
return { data : result , meta : 'meta' }
30
41
} ,
31
- tagTypes : [ 'Post' ] ,
42
+ tagTypes : [ 'Post' , 'Folder' ] ,
32
43
endpoints : ( build ) => ( {
33
44
getPosts : build . query < Post [ ] , void > ( {
34
45
query : ( ) => '/posts' ,
@@ -80,6 +91,30 @@ const api = createApi({
80
91
} ,
81
92
keepUnusedDataFor : 0.01 ,
82
93
} ) ,
94
+ getFolder : build . query < FolderT , number > ( {
95
+ queryFn : async ( args ) => {
96
+ return {
97
+ data : {
98
+ id : args ,
99
+ // Folder contains children that are as well folders
100
+ children : [ { id : 2 , children : [ ] } ] ,
101
+ } ,
102
+ }
103
+ } ,
104
+ providesTags : ( result , err , args ) => [ { type : 'Folder' , id : args } ] ,
105
+ onQueryStarted : async ( args , queryApi ) => {
106
+ const { data } = await queryApi . queryFulfilled
107
+
108
+ // Upsert getFolder endpoint with children from response data
109
+ const upsertData = data . children . map ( ( child ) => ( {
110
+ arg : child . id ,
111
+ endpointName : 'getFolder' as const ,
112
+ value : child ,
113
+ } ) )
114
+
115
+ queryApi . dispatch ( api . util . upsertQueryEntries ( upsertData ) )
116
+ } ,
117
+ } ) ,
83
118
} ) ,
84
119
} )
85
120
@@ -434,6 +469,56 @@ describe('upsertQueryEntries', () => {
434
469
undefined ,
435
470
)
436
471
} )
472
+
473
+ test ( 'Handles repeated upserts and async lifecycles' , async ( ) => {
474
+ const StateForUpsertFolder = ( { folderId } : { folderId : number } ) => {
475
+ const { status } = api . useGetFolderQuery ( folderId )
476
+
477
+ return (
478
+ < >
479
+ < div >
480
+ Status getFolder with ID (
481
+ { folderId === 1 ? 'original request' : 'upserted' } ) { folderId } :{ ' ' }
482
+ < span data-testid = { `status-${ folderId } ` } > { status } </ span >
483
+ </ div >
484
+ </ >
485
+ )
486
+ }
487
+
488
+ const Folder = ( ) => {
489
+ const { data, isLoading, isError } = api . useGetFolderQuery ( 1 )
490
+
491
+ return (
492
+ < div >
493
+ < h1 > Folders</ h1 >
494
+
495
+ { isLoading && < div > Loading...</ div > }
496
+
497
+ { isError && < div > Error...</ div > }
498
+
499
+ < StateForUpsertFolder key = { `state-${ 1 } ` } folderId = { 1 } />
500
+ < StateForUpsertFolder key = { `state-${ 2 } ` } folderId = { 2 } />
501
+ </ div >
502
+ )
503
+ }
504
+
505
+ render ( < Folder /> , {
506
+ wrapper : storeRef . wrapper ,
507
+ } )
508
+
509
+ await waitFor ( ( ) => {
510
+ const { actions } = storeRef . store . getState ( )
511
+ // Inspection:
512
+ // - 2 inits
513
+ // - 2 pendings, 2 fulfilleds for the hook queries
514
+ // - 2 upserts
515
+ expect ( actions . length ) . toBe ( 8 )
516
+ expect (
517
+ actions . filter ( ( a ) => api . util . upsertQueryEntries . match ( a ) ) . length ,
518
+ ) . toBe ( 2 )
519
+ } )
520
+ expect ( screen . getByTestId ( 'status-2' ) . textContent ) . toBe ( 'fulfilled' )
521
+ } )
437
522
} )
438
523
439
524
describe ( 'full integration' , ( ) => {
0 commit comments