11import { createApi } from '@reduxjs/toolkit/query'
2- import { actionsReducer , setupApiStore } from '../../tests/utils/helpers'
32import { delay } from 'msw'
3+ import { actionsReducer , setupApiStore } from '../../tests/utils/helpers'
44
55const baseQuery = ( args ?: any ) => ( { data : args } )
66const api = createApi ( {
@@ -25,9 +25,15 @@ const api = createApi({
2525 } ,
2626 providesTags : [ 'Bread' ] ,
2727 } ) ,
28+ invalidateFruit : build . mutation ( {
29+ query : ( fruit ?: 'Banana' | 'Bread' | null ) => ( { url : `invalidate/fruit/${ fruit || '' } ` } ) ,
30+ invalidatesTags ( result , error , arg ) {
31+ return [ arg ]
32+ }
33+ } )
2834 } ) ,
2935} )
30- const { getBanana, getBread } = api . endpoints
36+ const { getBanana, getBread, invalidateFruit } = api . endpoints
3137
3238const storeRef = setupApiStore ( api , {
3339 ...actionsReducer ,
@@ -70,3 +76,61 @@ it('invalidates the specified tags', async () => {
7076 getBread . matchFulfilled ,
7177 )
7278} )
79+
80+ it ( 'invalidates tags correctly when null or undefined are provided as tags' , async ( ) => {
81+ await storeRef . store . dispatch ( getBanana . initiate ( 1 ) )
82+ await storeRef . store . dispatch ( api . util . invalidateTags ( [ undefined , null , 'Banana' ] ) )
83+
84+ // Slight pause to let the middleware run and such
85+ await delay ( 20 )
86+
87+ const apiActions = [
88+ api . internalActions . middlewareRegistered . match ,
89+ getBanana . matchPending ,
90+ getBanana . matchFulfilled ,
91+ api . util . invalidateTags . match ,
92+ getBanana . matchPending ,
93+ getBanana . matchFulfilled ,
94+ ]
95+
96+ expect ( storeRef . store . getState ( ) . actions ) . toMatchSequence ( ...apiActions )
97+ } )
98+
99+
100+ it . each ( [
101+ { tags : [ undefined , null , 'Bread' ] as Parameters < typeof api . util . invalidateTags > [ '0' ] } ,
102+ { tags : [ undefined , null ] , } , { tags : [ ] } ]
103+ ) ( 'does not invalidate with tags=$tags if no query matches' , async ( { tags } ) => {
104+ await storeRef . store . dispatch ( getBanana . initiate ( 1 ) )
105+ await storeRef . store . dispatch ( api . util . invalidateTags ( tags ) )
106+
107+ // Slight pause to let the middleware run and such
108+ await delay ( 20 )
109+
110+ const apiActions = [
111+ api . internalActions . middlewareRegistered . match ,
112+ getBanana . matchPending ,
113+ getBanana . matchFulfilled ,
114+ api . util . invalidateTags . match ,
115+ ]
116+
117+ expect ( storeRef . store . getState ( ) . actions ) . toMatchSequence ( ...apiActions )
118+ } )
119+
120+ it . each ( [ { mutationArg : 'Bread' as "Bread" | null | undefined } , { mutationArg : undefined } , { mutationArg : null } ] ) ( 'does not invalidate queries when a mutation with tags=[$mutationArg] runs and does not match anything' , async ( { mutationArg } ) => {
121+ await storeRef . store . dispatch ( getBanana . initiate ( 1 ) )
122+ await storeRef . store . dispatch ( invalidateFruit . initiate ( mutationArg ) )
123+
124+ // Slight pause to let the middleware run and such
125+ await delay ( 20 )
126+
127+ const apiActions = [
128+ api . internalActions . middlewareRegistered . match ,
129+ getBanana . matchPending ,
130+ getBanana . matchFulfilled ,
131+ invalidateFruit . matchPending ,
132+ invalidateFruit . matchFulfilled ,
133+ ]
134+
135+ expect ( storeRef . store . getState ( ) . actions ) . toMatchSequence ( ...apiActions )
136+ } )
0 commit comments