Skip to content

Commit e628ed6

Browse files
authored
Merge pull request #2702 from Bezmehrabi/bugfix/provided-tags
2 parents 4f55c3a + c4c3477 commit e628ed6

File tree

2 files changed

+96
-42
lines changed

2 files changed

+96
-42
lines changed

packages/toolkit/src/query/core/buildSlice.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,17 @@ export function buildSlice({
314314
)
315315
const { queryCacheKey } = action.meta.arg
316316

317+
for (const tagTypeSubscriptions of Object.values(draft)) {
318+
for (const idSubscriptions of Object.values(
319+
tagTypeSubscriptions
320+
)) {
321+
const foundAt = idSubscriptions.indexOf(queryCacheKey)
322+
if (foundAt !== -1) {
323+
idSubscriptions.splice(foundAt, 1)
324+
}
325+
}
326+
}
327+
317328
for (const { type, id } of providedTags) {
318329
const subscribedQueries = ((draft[type] ??= {})[
319330
id || '__internal_without_id'

packages/toolkit/src/query/tests/buildSlice.test.ts

Lines changed: 85 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,22 @@ import { createSlice } from '@reduxjs/toolkit'
22
import { createApi } from '@reduxjs/toolkit/query'
33
import { setupApiStore } from './helpers'
44

5+
let shouldApiResponseSuccess = true
6+
7+
function delay(ms: number) {
8+
return new Promise((resolve) => setTimeout(resolve, ms))
9+
}
10+
511
const baseQuery = (args?: any) => ({ data: args })
612
const api = createApi({
713
baseQuery,
14+
tagTypes: ['SUCCEED', 'FAILED'],
815
endpoints: (build) => ({
9-
getUser: build.query<unknown, number>({
16+
getUser: build.query<{ url: string; success: boolean }, number>({
1017
query(id) {
11-
return { url: `user/${id}` }
18+
return { url: `user/${id}`, success: shouldApiResponseSuccess }
1219
},
20+
providesTags: (result) => (result?.success ? ['SUCCEED'] : ['FAILED']),
1321
}),
1422
}),
1523
})
@@ -29,51 +37,86 @@ const authSlice = createSlice({
2937

3038
const storeRef = setupApiStore(api, { auth: authSlice.reducer })
3139

32-
it('only resets the api state when resetApiState is dispatched', async () => {
33-
storeRef.store.dispatch({ type: 'unrelated' }) // trigger "registered middleware" into place
34-
const initialState = storeRef.store.getState()
35-
36-
await storeRef.store.dispatch(
37-
getUser.initiate(1, { subscriptionOptions: { pollingInterval: 10 } })
38-
)
39-
40-
expect(storeRef.store.getState()).toEqual({
41-
api: {
42-
config: {
43-
focused: true,
44-
keepUnusedDataFor: 60,
45-
middlewareRegistered: true,
46-
online: true,
47-
reducerPath: 'api',
48-
refetchOnFocus: false,
49-
refetchOnMountOrArgChange: false,
50-
refetchOnReconnect: false,
51-
},
52-
mutations: {},
53-
provided: {},
54-
queries: {
55-
'getUser(1)': {
56-
data: {
57-
url: 'user/1',
40+
describe('buildSlice', () => {
41+
beforeEach(() => {
42+
shouldApiResponseSuccess = true
43+
})
44+
45+
it('only resets the api state when resetApiState is dispatched', async () => {
46+
storeRef.store.dispatch({ type: 'unrelated' }) // trigger "registered middleware" into place
47+
const initialState = storeRef.store.getState()
48+
49+
await storeRef.store.dispatch(
50+
getUser.initiate(1, { subscriptionOptions: { pollingInterval: 10 } })
51+
)
52+
53+
expect(storeRef.store.getState()).toEqual({
54+
api: {
55+
config: {
56+
focused: true,
57+
keepUnusedDataFor: 60,
58+
middlewareRegistered: true,
59+
online: true,
60+
reducerPath: 'api',
61+
refetchOnFocus: false,
62+
refetchOnMountOrArgChange: false,
63+
refetchOnReconnect: false,
64+
},
65+
mutations: {},
66+
provided: {
67+
SUCCEED: {
68+
__internal_without_id: ['getUser(1)'],
69+
},
70+
},
71+
queries: {
72+
'getUser(1)': {
73+
data: {
74+
url: 'user/1',
75+
success: true,
76+
},
77+
endpointName: 'getUser',
78+
fulfilledTimeStamp: expect.any(Number),
79+
originalArgs: 1,
80+
requestId: expect.any(String),
81+
startedTimeStamp: expect.any(Number),
82+
status: 'fulfilled',
5883
},
59-
endpointName: 'getUser',
60-
fulfilledTimeStamp: expect.any(Number),
61-
originalArgs: 1,
62-
requestId: expect.any(String),
63-
startedTimeStamp: expect.any(Number),
64-
status: 'fulfilled',
84+
},
85+
subscriptions: {
86+
'getUser(1)': expect.any(Object),
6587
},
6688
},
67-
subscriptions: {
68-
'getUser(1)': expect.any(Object),
89+
auth: {
90+
token: '1234',
6991
},
70-
},
71-
auth: {
72-
token: '1234',
73-
},
92+
})
93+
94+
storeRef.store.dispatch(api.util.resetApiState())
95+
96+
expect(storeRef.store.getState()).toEqual(initialState)
7497
})
7598

76-
storeRef.store.dispatch(api.util.resetApiState())
99+
it('replaces previous tags with new provided tags', async () => {
100+
await storeRef.store.dispatch(getUser.initiate(1))
77101

78-
expect(storeRef.store.getState()).toEqual(initialState)
102+
expect(
103+
api.util.selectInvalidatedBy(storeRef.store.getState(), ['SUCCEED'])
104+
).toHaveLength(1)
105+
expect(
106+
api.util.selectInvalidatedBy(storeRef.store.getState(), ['FAILED'])
107+
).toHaveLength(0)
108+
109+
shouldApiResponseSuccess = false
110+
111+
storeRef.store.dispatch(getUser.initiate(1)).refetch()
112+
113+
await delay(10)
114+
115+
expect(
116+
api.util.selectInvalidatedBy(storeRef.store.getState(), ['SUCCEED'])
117+
).toHaveLength(0)
118+
expect(
119+
api.util.selectInvalidatedBy(storeRef.store.getState(), ['FAILED'])
120+
).toHaveLength(1)
121+
})
79122
})

0 commit comments

Comments
 (0)