Unit testing React apps with TypeScript, Vite, Jest, Redux toolkit, and Axios
Efficient and reliable applications can do wonders for your business. Unit testing can be the key to building React applications that are both efficient and reliable. Testing individual components in isolation allows you to catch and fix bugs early, improve code quality, and accelerate your development process. This guide walks you through configuring unit tests for a React application using Jest, with TypeScript support and Vite as the build tool. We’ll also cover mocking Axios for API calls and testing Redux slices with @reduxjs/toolkit
Steps for setting up your development environment for unit testing
Ensure you have a Vite project already set up. Let’s dive into configuring Jest and writing tests for API calls and React components.
Step 1: Install the required dependencies
- Jest and TypeScript support: npm install — save-dev jest @types/jest ts-jest
- React testing utilities: npm install — save-dev @testing-library/react @testing-library/jest-dom @testing-library/user-event @types/testing-library__react @types/testing-library__user-event @jest/globals
- Mocking Axios: npm install — save-dev axios-mock-adapter axios
Step 2: Configure Jest with TypeScript Support
Create a jest.config.js file in the root directory to set up Jest:
export default {
testEnvironment: "jsdom",
transform: {
"^.+\\.tsx?$": "ts-jest",
},
moduleNameMapper: {
"\\.(css|less|sass|scss)$": "identity-obj-proxy",
"^.+\\.svg$": "jest-transformer-svg",
"^@/(.*)$": "<rootDir>/src/$1",
"^@components/(.*)$": "<rootDir>/src/components/$1",
},
setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
};
Create a jest.setup.ts file to handle any Jest environment setup:
import "@testing-library/jest-dom/extend-expect";
//setting to get value from local storage which are encrypted/decrypted using window.atob/window.btoa
(global as any).window = {
localStorage: {
getItem: jest.fn(),
setItem: jest.fn(),
clear: jest.fn(),
},
btoa: (str: string) => Buffer.from(str, 'binary').toString('base64'),
atob: (str: string) => Buffer.from(str, 'base64').toString('binary'),
location: {
href: '',
},
};
global.XMLHttpRequest = undefined;
Add a test script in package.json to run the tests:
"scripts": {
"test": "jest --coverage"
},
Step 3: Configure the Redux Store and Middleware
Create store.ts:
import { combineReducers, configureStore } from "@reduxjs/toolkit";
import counterSlice from "../components/login/LoginSlice";
const rootReducer = combineReducers({
counter: counterSlice.reducer,
})
export function setupStore(preloadedState?: Partial<any>) {
return configureStore({
reducer: rootReducer,
preloadedState,
});
}
export type RootStateType = ReturnType<typeof rootReducer>;
export type AppDispatchType = ReturnType<typeof setupStore>
export type AppDispatch = AppDispatchType['dispatch']
Create hooks.ts for typed hooks:
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import type { AppDispatch, RootStateType } from './store';
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootStateType> = useSelector;
Step 4: Configure Axios (read more..)