gs-port / node_modules /@reduxjs /toolkit /src /query /tests /apiProvider.test.tsx
Scribbler310's picture
feat: enhance dashboard
c2b7eb3 verified
import { configureStore } from '@reduxjs/toolkit'
import {
ApiProvider,
buildCreateApi,
coreModule,
createApi,
reactHooksModule,
} from '@reduxjs/toolkit/query/react'
import { fireEvent, render, waitFor } from '@testing-library/react'
import { delay } from 'msw'
import * as React from 'react'
import type { ReactReduxContextValue } from 'react-redux'
import {
Provider,
createDispatchHook,
createSelectorHook,
createStoreHook,
} from 'react-redux'
const api = createApi({
baseQuery: async (arg: any) => {
await delay(150)
return { data: arg?.body ? arg.body : null }
},
endpoints: (build) => ({
getUser: build.query<any, number>({
query: (arg) => arg,
}),
updateUser: build.mutation<any, { name: string }>({
query: (update) => ({ body: update }),
}),
}),
})
afterEach(() => {
vi.resetAllMocks()
})
describe('ApiProvider', () => {
test('ApiProvider allows a user to make queries without a traditional Redux setup', async () => {
function User() {
const [value, setValue] = React.useState(0)
const { isFetching } = api.endpoints.getUser.useQuery(1, {
skip: value < 1,
})
return (
<div>
<div data-testid="isFetching">{String(isFetching)}</div>
<button onClick={() => setValue((val) => val + 1)}>
Increment value
</button>
</div>
)
}
const { getByText, getByTestId } = render(
<ApiProvider api={api}>
<User />
</ApiProvider>,
)
await waitFor(() =>
expect(getByTestId('isFetching').textContent).toBe('false'),
)
fireEvent.click(getByText('Increment value'))
await waitFor(() =>
expect(getByTestId('isFetching').textContent).toBe('true'),
)
await waitFor(() =>
expect(getByTestId('isFetching').textContent).toBe('false'),
)
fireEvent.click(getByText('Increment value'))
// Being that nothing has changed in the args, this should never fire.
expect(getByTestId('isFetching').textContent).toBe('false')
})
test('ApiProvider throws if nested inside a Redux context', () => {
// Intentionally swallow the "unhandled error" message
vi.spyOn(console, 'error').mockImplementation(() => {})
expect(() =>
render(
<Provider store={configureStore({ reducer: () => null })}>
<ApiProvider api={api}>child</ApiProvider>
</Provider>,
),
).toThrowErrorMatchingInlineSnapshot(
`[Error: Existing Redux context detected. If you already have a store set up, please use the traditional Redux setup.]`,
)
})
test('ApiProvider allows a custom context', async () => {
const customContext = React.createContext<ReactReduxContextValue | null>(
null,
)
const createApiWithCustomContext = buildCreateApi(
coreModule(),
reactHooksModule({
hooks: {
useStore: createStoreHook(customContext),
useSelector: createSelectorHook(customContext),
useDispatch: createDispatchHook(customContext),
},
}),
)
const customApi = createApiWithCustomContext({
baseQuery: async (arg: any) => {
await delay(150)
return { data: arg?.body ? arg.body : null }
},
endpoints: (build) => ({
getUser: build.query<any, number>({
query: (arg) => arg,
}),
updateUser: build.mutation<any, { name: string }>({
query: (update) => ({ body: update }),
}),
}),
})
function User() {
const [value, setValue] = React.useState(0)
const { isFetching } = customApi.endpoints.getUser.useQuery(1, {
skip: value < 1,
})
return (
<div>
<div data-testid="isFetching">{String(isFetching)}</div>
<button onClick={() => setValue((val) => val + 1)}>
Increment value
</button>
</div>
)
}
const { getByText, getByTestId } = render(
<ApiProvider api={customApi} context={customContext}>
<User />
</ApiProvider>,
)
await waitFor(() =>
expect(getByTestId('isFetching').textContent).toBe('false'),
)
fireEvent.click(getByText('Increment value'))
await waitFor(() =>
expect(getByTestId('isFetching').textContent).toBe('true'),
)
await waitFor(() =>
expect(getByTestId('isFetching').textContent).toBe('false'),
)
fireEvent.click(getByText('Increment value'))
// Being that nothing has changed in the args, this should never fire.
expect(getByTestId('isFetching').textContent).toBe('false')
// won't throw if nested, because context is different
expect(() =>
render(
<Provider store={configureStore({ reducer: () => null })}>
<ApiProvider api={customApi} context={customContext}>
child
</ApiProvider>
</Provider>,
),
).not.toThrow()
})
})