I have my Custom Hook, it uses useAppDispatch and Slice from ReduxToolkit:
import { useAppDispatch } from "../../app/redux";
import { registrationFormSlice } from "../../entities/registration";
import { getStringToTheTemplate } from "./utils";
export interface IgetFields {
label: string;
valueKey: string;
setValue: any;
disabled?: boolean;
}
export const useFields = () => {
const dispatch = useAppDispatch();
const { setLastName } = registrationFormSlice.actions;
const getFields = (): IgetFields[][] => {
return [
[
{
label: "lastName",
valueKey: "lastName",
setValue: (value: string) =>
dispatch(
setLastName(getStringToTheTemplate(value))
),
},
],
];
};
return getFields;
};
I'm trying to write tests for it:
import { useAppDispatch } from "../../app/redux";
import { registrationFormSlice } from "../../entities/registration";
import { useFields } from "../ForgetPassword/data";
describe("useFields hook", () => {
let setLastNameSpy: jest.SpyInstance;
let dispatchMock: jest.Mock;
let useAppDispatchMock: jest.SpyInstance;
beforeEach(() => {
setLastNameSpy = jest.spyOn(registrationFormSlice.actions, "setLastName");
dispatchMock = jest.fn();
useAppDispatchMock = jest.spyOn(useAppDispatch, "useAppDispatch");
useAppDispatchMock.mockReturnValue(dispatchMock);
});
afterEach(() => {
setLastNameSpy.mockReset();
dispatchMock.mockReset();
useAppDispatchMock.mockReset();
});
it("should call setLastName action with transformed value", () => {
const getFields = useFields();
const lastNameField = getFields()[0][0];
lastNameField.setValue("Test");
expect(setLastNameSpy).toHaveBeenCalledTimes(1);
expect(setLastNameSpy).toHaveBeenCalledWith("Test");
expect(dispatchMock).toHaveBeenCalledTimes(1);
});
it("should return correct fields array", () => {
const getFields = useFields();
const expectedFields = [
[
{
label: "lastName",
valueKey: "lastName",
setValue: expect.any(Function),
},
],
];
expect(getFields()).toEqual(expectedFields);
});
});
And I get errors:
Code useAppDispatch:
import { AppDispatch, RootState } from "../entities/store";
import { useDispatch } from "react-redux";
export const useAppDispatch = () => useDispatch<AppDispatch>();
Code type AppDispatch:
import { combineReducers, configureStore } from "@reduxjs/toolkit";
import { userSlice } from "./user";
import { registrationFormSlice } from "./registration";
const rootReducer = combineReducers({
user: userSlice.reducer,
registrationForm: registrationFormSlice.reducer,
});
export const setupStore = () => {
return configureStore({
reducer: rootReducer,
});
};
export type RootState = ReturnType<typeof rootReducer>;
export type AppStore = ReturnType<typeof setupStore>;
export type AppDispatch = AppStore["dispatch"];
Help solve the errors, please
I tried to find the answer to the problem on the Internet, but all the information I found was about JS and therefore was of little use to me
A comment from Lin Du helped solve my question. My mistake was that I used jest.spyOn() incorrectly:
useAppDispatchMock = jest.spyOn(useAppDispatch, "useAppDispatch");
The fact is that in just.spyOn( ), the second argument should be the name of the property of the object, and I have an import of a separate specific function.
Also my test is trying to spy of the registrationFormSlice is superfluous and does unnecessary actions:
beforeEach(() => {
setLastNameSpy = jest.spyOn(registrationFormSlice.actions, "setLastName");
dispatchMock = jest.fn();
useAppDispatchMock = jest.spyOn(useAppDispatch, "useAppDispatch");
useAppDispatchMock.mockReturnValue(dispatchMock);
});
afterEach(() => {
setLastNameSpy.mockReset();
dispatchMock.mockReset();
useAppDispatchMock.mockReset();
});
For this reason, probably the best working test would be to check the result for structure and data types:
import { renderHook } from "@testing-library/react";
import { useFields } from "./data";
import * as useAppDispatch from "../../app/redux";
describe("useFields", () => {
const useDispatchMock = jest.spyOn(useAppDispatch, "useAppDispatch");
useDispatchMock.mockReturnValue(jest.fn());
const setup = () => {
const { result } = renderHook(() => useFields());
return result.current();
};
test("Must be an array of arrays", () => {
const getFields = setup();
expect(Array.isArray(getFields)).toBeTruthy();
expect(getFields.length).toBe(1);
expect(useDispatchMock).toBeCalled();
});
test("An array with index 0 must have certain properties and structure", () => {
const getFields = setup()[0];
expect(getFields.length).toBe(1);
expect(typeof getFields[0].label).toBe("string");
expect(getFields[0].valueKey).toBe("lastName");
expect(typeof getFields[0].setValue).toBe("function");
});
});