@@ -5,7 +5,13 @@ import {
55 hookWaitFor ,
66 setupApiStore ,
77} 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'
915import { delay } from 'msw'
1016
1117interface Post {
@@ -14,6 +20,11 @@ interface Post {
1420 contents : string
1521}
1622
23+ interface FolderT {
24+ id : number
25+ children : FolderT [ ]
26+ }
27+
1728const baseQuery = vi . fn ( )
1829beforeEach ( ( ) => baseQuery . mockReset ( ) )
1930
@@ -28,7 +39,7 @@ const api = createApi({
2839 . catch ( ( e : any ) => ( { error : e } ) )
2940 return { data : result , meta : 'meta' }
3041 } ,
31- tagTypes : [ 'Post' ] ,
42+ tagTypes : [ 'Post' , 'Folder' ] ,
3243 endpoints : ( build ) => ( {
3344 getPosts : build . query < Post [ ] , void > ( {
3445 query : ( ) => '/posts' ,
@@ -80,6 +91,30 @@ const api = createApi({
8091 } ,
8192 keepUnusedDataFor : 0.01 ,
8293 } ) ,
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+ } ) ,
83118 } ) ,
84119} )
85120
@@ -434,6 +469,56 @@ describe('upsertQueryEntries', () => {
434469 undefined ,
435470 )
436471 } )
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+ } )
437522} )
438523
439524describe ( 'full integration' , ( ) => {
0 commit comments