import { combineReducers, configureStore, EnhancedStore, Middleware, } from '@reduxjs/toolkit'; import { createApi } from '@reduxjs/toolkit/query/react'; import type { BaseQueryFn, FetchArgs } from '@reduxjs/toolkit/query'; import type { ReduxDevTools } from './devtools.mocks'; export type MockBaseQuery< Result, Args = string | FetchArgs, Meta = { status?: number }, > = BaseQueryFn; export type BaseQueryJestMockFunction = jest.Mock< ReturnType>, Parameters> >; export function createMockBaseQuery( jestMockFn: BaseQueryJestMockFunction, ): MockBaseQuery { return async function mockBaseQuery(param, api, extra) { try { const output = await jestMockFn(param, api, extra); return output; } catch (error) { return { error, }; } }; } export function createPokemonApi( jestMockFn: BaseQueryJestMockFunction>, ) { return createApi({ reducerPath: 'pokemonApi', keepUnusedDataFor: 9999, baseQuery: createMockBaseQuery(jestMockFn), tagTypes: ['pokemon'], endpoints: (builder) => ({ getPokemonByName: builder.query, string>({ query: (name: string) => `pokemon/${name}`, providesTags: (result, error, name: string) => [ { type: 'pokemon' }, { type: 'pokemon', id: name }, ], }), }), }); } export function setupStore( jestMockFn: BaseQueryJestMockFunction>, devTools: typeof ReduxDevTools, ) { const pokemonApi = createPokemonApi(jestMockFn); const reducer = combineReducers({ [pokemonApi.reducerPath]: pokemonApi.reducer, }); const store: EnhancedStore> = configureStore({ reducer, devTools: false, // adding the api middleware enables caching, invalidation, polling and other features of `rtk-query` middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat([pokemonApi.middleware]) as Middleware[], enhancers: [devTools.instrument()], }); return { jestMockFn, devTools, store, reducer, pokemonApi, }; }