Rules for writing unit tests in React with Vitest
You are a senior frontend developer and an expert in React, TypeScript, and modern web development.
vi.clearAllMocks();
vi
this is a declared globally alreadyas never
to convert to object to something that Typescript will just ignore. DO NOT user as any
.it.each
unit test.When creating mocks for a Provider Context it is unpractical to use a vi.spyOn
. Instead use the following 2 methods (each method has his own conditions in when to use them)
vi.mock
Use vi.mock
if the provider context value will be static for multiple tests.
Use the following coding example to create the mock: Example: you have the following Provider Context inside a custom hook:
const {
form: { instance },
currentStepState: { onFinish, onFinishFailed },
} = use(NewOrderPageProviderContext);
To mock this properly use vi.mock
and vi.hoisted
.
Use vi.hoisted
if you want to use variables inside vi.mock
objects like the following:
const mocks = vi.hoisted(() => ({
validateFieldsMock: vi.fn(),
onFinishMock: vi.fn(),
onFinishFailedMock: vi.fn(),
}));
vi.mock(
"@/features/orders/new-order-page/providers/contexts/new-order-page-provider-context",
() => ({
__esModule: true,
default: createContext({
form: {
instance: {
validateFields: mocks.validateFieldsMock,
},
},
currentStepState: {
onFinish: mocks.onFinishMock,
onFinishFailed: mocks.onFinishFailedMock,
},
}),
})
);
The import path needs to correspond with the import path used inside the custom hook.
Use a wrapper if the value of the provider context needs to be different inside a test.
Use the following code example for reference: Example: you have the following Provider Context inside a custom hook:
const {
form: { instance },
currentStepState: { onFinish, onFinishFailed },
} = use(NewOrderPageProviderContext);
To mock this Provider Context:
const mockValue = {
validateFieldsMock: vi.fn(),
onFinishMock: vi.fn(),
onFinishFailedMock: vi.fn(),
} as never;
const wrapper = ({ children }: { children: React.ReactNode }) => (
<NewOrderPageProviderContext.Provider value={mockValue}>
{children}
</NewOrderPageProviderContext.Provider>
);
const { result } = renderHook(() => useCustomHook(), { wrapper });
If react-i18next
is present inside the React project for internationalization. We should mock this package inside unit test to prevent errors. The following util script should be created inside /tests/utils/mock-translation.ts
:
const translationMock = (): void => {
vi.mock("react-i18next", () => ({
useTranslation: (): { t: (str: string) => string } => ({
t: (str: string) => str,
}),
}));
};
export default translationMock;