trying to run the first test with redux-toolkit rtk query and got error that api is undefined. What I did wrong?
● Test suite failed to run
TypeError: Cannot read property 'injectEndpoints' of undefined
33 | };
34 |
> 35 | export const authApi = api.injectEndpoints({
| ^
36 | endpoints: (build) => ({
37 | login: build.mutation<ILoginResponse, ILoginData>({
38 | query: ({ username, password, captchaToken }) => {
at Object.<anonymous> (src/api/auth.ts:35:28)
at Object.<anonymous> (src/features/auth/authSlice.ts:2:1)
at Object.<anonymous> (src/api/index.ts:10:1)
at Object.<anonymous> (src/mocks/handler.ts:3:1)
at Object.<anonymous> (src/mocks/server.ts:3:1)
at Object.<anonymous> (src/setupTests.ts:6:1)
at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)
at runJest (node_modules/@jest/core/build/runJest.js:404:19)
at _run10000 (node_modules/@jest/core/build/cli/index.js:320:7)
at runCLI (node_modules/@jest/core/build/cli/index.js:173:3)
This is my test:
it('should reset roleType on role change', () => {
renderWithProviders(
<Form
initialValues={{
role: 6,
roleType: 7,
companyId: 2,
}}
mutators={formMutators}
onSubmit={jest.fn()}
>
{({ form }) => (
<>
<RoleFields setValue={form.mutators.setValue} />
</>
)}
</Form>
);
});
There is nothing here yet just trying to render without errors.
And this is renderWithProviders function:
interface ExtendedRenderOptions extends Omit<RenderOptions, 'queries'> {
preloadedState?: PreloadedState<RootState>;
store?: AppStore;
}
export function renderWithProviders(
ui: React.ReactElement,
{
preloadedState = {},
// Automatically create a store instance if no store was passed in
store = setupStore(preloadedState),
...renderOptions
}: ExtendedRenderOptions = {}
) {
function Wrapper({ children }: PropsWithChildren<Record<string, unknown>>): JSX.Element {
return <Provider store={store}>{children}</Provider>;
}
// Return an object with the store and all of RTL's query functions
return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) };
}
setupTests:
import '@testing-library/jest-dom/extend-expect';
import { server } from './mocks/server';
import { api } from './api';
import { setupStore } from './app/store';
const store = setupStore();
// Establish API mocking before all tests.
beforeAll(() => {
server.listen();
});
// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.
afterEach(() => {
server.resetHandlers();
// This is the solution to clear RTK Query cache after each test
store.dispatch(api.util.resetApiState());
});
// Clean up after the tests are finished.
afterAll(() => server.close());
Store setup:
import { configureStore, ThunkAction, Action, combineReducers } from '@reduxjs/toolkit';
import type { PreloadedState } from '@reduxjs/toolkit';
import { api } from '../api';
import { authSlice } from '../features/auth/authSlice';
// Create the root reducer separately so we can extract the RootState type
const rootReducer = combineReducers({
[api.reducerPath]: api.reducer,
[authSlice.name]: authSlice.reducer,
});
export const setupStore = (preloadedState?: PreloadedState<RootState>) => {
return configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(api.middleware),
preloadedState,
});
};
Please help what here is wrong, have no idea....
UPD: Looks like the problem here:
import { logout } from '../features/auth/authSlice';
....
const baseQueryWithAuthCheck: BaseQueryFn<
string | FetchArgs,
unknown,
FetchBaseQueryError
> = async (args, api, extraOptions) => {
const result = await baseQuery(args, api, extraOptions);
if (result.error && result.error.status === 401) {
api.dispatch(logout());
}
return result;
};
export const api = createApi({
reducerPath: 'api',
baseQuery: baseQueryWithAuthCheck,
tagTypes: ALL_TAGS_TYPES,
endpoints: () => ({}),
});
I'm doing import logout action from authSlice, and that authSlice do import from api to build matchers for extraReducers
import { authApi } from '../../api/auth';
....
export const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
logout: (state) => {
state.token = null;
authStorage.clear();
},
},
extraReducers: (builder) => {
builder
.addMatcher(authApi.endpoints.login.matchPending, (state) => {
state.loading = 'pending';
})
....