Redux toolkit, redux-mock-store, redux-thunk
I'm struggling to understand the reason why my store.dispatch(action) doesn't work whereas userSlice.reducer seems to be working in the context of unit testing.
I did read this Weird error testing a reducer (redux toolkit) but it didn't help to resolve the issue.
user.tsx
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { refreshAccessToken } from "../../api/auth";
import { getUserData, patchUserData } from "../../api/user";
import { UserDataResponse } from "../../types/user";
import { RootState } from "../store";
import { logoutUserReducer } from "./auth";
export interface User {
email?: string;
name?: string;
password?: string;
}
export interface InitialStateUser {
user: User | null;
userIsLoading: boolean;
userIsLoaded?: boolean;
}
const initialState: InitialStateUser = {
user: null,
userIsLoading: false,
};
export const getUserDataReducer = createAsyncThunk(
"getUserData",
async (_, { rejectWithValue }) => {
// some async code with FETCH API and getUserData()
}
}
);
export const userSlice = createSlice({
name: "user",
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(getUserDataReducer.fulfilled, (state, action) => {
state.user = action.payload.user;
state.userIsLoading = false;
state.userIsLoaded = true;
})
.addCase(getUserDataReducer.pending, (state) => {
state.userIsLoading = true;
state.userIsLoaded = false;
})
.addCase(getUserDataReducer.rejected, (state, action) => {
state.userIsLoading = false;
state.userIsLoaded = false;
})
},
});
export default userSlice.reducer;
user.test.tsx
import { AppDispatch, RootState } from "../store";
import configureMockStore, { MockStoreEnhanced } from "redux-mock-store";
import thunk from "redux-thunk";
import { initialIngredientsState } from "./ingredients.test";
import { initialOrderState } from "./order.test";
import userReducer, {
getUserDataReducer,
InitialStateUser,
userSlice,
} from "../slices/user";
import fetchMock from "fetch-mock";
import { BASE_URL } from "../../api";
import { getCookie } from "../../utils/cookieHandler";
const initialUserState: InitialStateUser = {
user: null,
userIsLoading: false,
};
const mockStoreInitialState = {
user: { ...initialUserState }
};
describe("user reducer", () => {
let store: MockStoreEnhanced<RootState>;
beforeEach(() => {
store = mockStore(mockStoreInitialState);
});
afterEach(() => {
fetchMock.restore();
});
// WORKS
it("should getUserData fullfilled", () => {
const newState = userSlice.reducer(initialUserState, {
type: "getUserData/fulfilled",
payload: {
user: { email: "[email protected]", name: "testU2dfd" },
},
});
expect(newState.user).toEqual({
email: "[email protected]",
name: "testU2dfd",
});
expect(newState.userIsLoaded).toBe(true);
});
// DOESN't WORK
it("should getUserData pending", async () => {
await store.dispatch(getUserDataReducer.pending(""));
const { userIsLoaded, userIsLoading } = store.getState().user;
console.log(store.getState());
expect(userIsLoaded).toBe(false);
expect(userIsLoading).toBe(true);
});
});
The redux state is simply not updated for the await store.dispatch(getUserDataReducer.pending(""));.
● user reducer › should getUserData pending
expect(received).toBe(expected) // Object.is equality
Expected: false
Received: undefined
Am I missing something here or misunderstood smth?
Ok that looks to be that it's not even intended to update the state according to https://github.com/reduxjs/redux-mock-store/issues/71 and from readme https://github.com/reduxjs/redux-mock-store
Please note that this library is designed to test the action-related logic, not the reducer-related one