Build NapCat Artifacts / Windows Loader Test (push) Canceled after 0s
Build NapCat Artifacts / Type Check & Test (push) Canceled after 0s
Build NapCat Artifacts / Build NapCat.Framework (push) Canceled after 0s
Build NapCat Artifacts / Build NapCat.Shell (push) Canceled after 0s
110 lines
3.4 KiB
Plaintext
110 lines
3.4 KiB
Plaintext
import { createApi, QueryStatus } from '@reduxjs/toolkit/query'
|
|
import { delay } from 'msw'
|
|
import { actionsReducer, setupApiStore } from '../../tests/utils/helpers'
|
|
|
|
// We need to be able to control when which query resolves to simulate race
|
|
// conditions properly, that's the purpose of this factory.
|
|
const createPromiseFactory = () => {
|
|
const resolveQueue: (() => void)[] = []
|
|
const createPromise = () =>
|
|
new Promise<void>((resolve) => {
|
|
resolveQueue.push(resolve)
|
|
})
|
|
const resolveOldest = () => {
|
|
resolveQueue.shift()?.()
|
|
}
|
|
return { createPromise, resolveOldest }
|
|
}
|
|
|
|
const getEatenBananaPromises = createPromiseFactory()
|
|
const eatBananaPromises = createPromiseFactory()
|
|
|
|
let eatenBananas = 0
|
|
const api = createApi({
|
|
invalidationBehavior: 'delayed',
|
|
baseQuery: () => undefined as any,
|
|
tagTypes: ['Banana'],
|
|
endpoints: (build) => ({
|
|
// Eat a banana.
|
|
eatBanana: build.mutation<unknown, void>({
|
|
queryFn: async () => {
|
|
await eatBananaPromises.createPromise()
|
|
eatenBananas += 1
|
|
return { data: null, meta: {} }
|
|
},
|
|
invalidatesTags: ['Banana'],
|
|
}),
|
|
|
|
// Get the number of eaten bananas.
|
|
getEatenBananas: build.query<number, void>({
|
|
queryFn: async (arg, arg1, arg2, arg3) => {
|
|
const result = eatenBananas
|
|
await getEatenBananaPromises.createPromise()
|
|
return { data: result }
|
|
},
|
|
providesTags: ['Banana'],
|
|
}),
|
|
}),
|
|
})
|
|
const { getEatenBananas, eatBanana } = api.endpoints
|
|
|
|
const storeRef = setupApiStore(api, {
|
|
...actionsReducer,
|
|
})
|
|
|
|
it('invalidates a query after a corresponding mutation', async () => {
|
|
eatenBananas = 0
|
|
|
|
const query = storeRef.store.dispatch(getEatenBananas.initiate())
|
|
const getQueryState = () =>
|
|
storeRef.store.getState().api.queries[query.queryCacheKey]
|
|
getEatenBananaPromises.resolveOldest()
|
|
await delay(2)
|
|
|
|
expect(getQueryState()?.data).toBe(0)
|
|
expect(getQueryState()?.status).toBe(QueryStatus.fulfilled)
|
|
|
|
const mutation = storeRef.store.dispatch(eatBanana.initiate())
|
|
const getMutationState = () =>
|
|
storeRef.store.getState().api.mutations[mutation.requestId]
|
|
eatBananaPromises.resolveOldest()
|
|
await delay(2)
|
|
|
|
expect(getMutationState()?.status).toBe(QueryStatus.fulfilled)
|
|
expect(getQueryState()?.data).toBe(0)
|
|
expect(getQueryState()?.status).toBe(QueryStatus.pending)
|
|
|
|
getEatenBananaPromises.resolveOldest()
|
|
await delay(2)
|
|
|
|
expect(getQueryState()?.data).toBe(1)
|
|
expect(getQueryState()?.status).toBe(QueryStatus.fulfilled)
|
|
})
|
|
|
|
it('invalidates a query whose corresponding mutation finished while the query was in flight', async () => {
|
|
eatenBananas = 0
|
|
|
|
const query = storeRef.store.dispatch(getEatenBananas.initiate())
|
|
const getQueryState = () =>
|
|
storeRef.store.getState().api.queries[query.queryCacheKey]
|
|
|
|
const mutation = storeRef.store.dispatch(eatBanana.initiate())
|
|
const getMutationState = () =>
|
|
storeRef.store.getState().api.mutations[mutation.requestId]
|
|
eatBananaPromises.resolveOldest()
|
|
await delay(2)
|
|
expect(getMutationState()?.status).toBe(QueryStatus.fulfilled)
|
|
|
|
getEatenBananaPromises.resolveOldest()
|
|
await delay(2)
|
|
expect(getQueryState()?.data).toBe(0)
|
|
expect(getQueryState()?.status).toBe(QueryStatus.pending)
|
|
|
|
// should already be refetching
|
|
getEatenBananaPromises.resolveOldest()
|
|
await delay(2)
|
|
|
|
expect(getQueryState()?.status).toBe(QueryStatus.fulfilled)
|
|
expect(getQueryState()?.data).toBe(1)
|
|
})
|