DEV Community

Cover image for How to write jest test cases for react component?
Vishesh Tiwari
Vishesh Tiwari

Posted on • Edited on

How to write jest test cases for react component?

Hi developers,

React developers love crafting components, but when it comes to code coverage, they often find themselves at a loss. This blog aims to change that! By the end, you’ll feel confident in writing test cases that minimize bugs.

I’ve shared some key points and techniques below to help you write React components that are easy to test.

  • Before writing any component, ask yourself: Is it testable? If the answer is no, it’s time to change your approach.

Solution: Embrace the TDD (Test-Driven Development) approach.

Image description

  • When mocking, follow the principle of abstraction by defining the implementation.

Instead of passing state and handlers as props, and to avoid mocking API calls, define the implementation by passing methods as props. This allows you to create mock responses effectively.

Major of the times ,when we write the component either we have to mock these -

  • Any of the package/file's methods or properties
  • Any hooks
  • Any type of network call

But magic only reside focus on imported package ,define to mock their function or property and then define implementation.

If it function return promise use mockResolve , if multiple function getting call the define called in stack using mockResolveOnce.

Lets see some of the approaches by using this we can write testable components.

Using MockAdapter -

First make sure you have installed this package - 'axios-mock-adapter' if not use command

yarn add axios-mock-adapter

Enter fullscreen mode Exit fullscreen mode

After that you can mock network like -


const fetchedData = {}

describe('searchData', () => {
  let mockAxios: MockAdapter;

  beforeEach(() => {
    mockAxios = new MockAdapter(axios);
  });

  afterEach(() => {
    mockAxios.reset();
    mockAxios.restore();
  });

  it('should fetch all brands', async () => {
    const keyWord: string = 'paint';
    let mockAxios: MockAdapter = new MockAdapter(axios);
    const data = [];

    const searchApi: string = `apiUrl?keyWord=${keyWord}`;

    mockAxios.onGet(searchApi).reply(200, JSON.stringify(fetchedData));

    const result = await searchData('paint');

    expect(result).toEqual(data);
    expect(mockAxios.history.get.length).toBe(1);
    expect(mockAxios.history.get[0].url).toBe(searchApi);
  });
});

Enter fullscreen mode Exit fullscreen mode

How to mock function from particular method ?

Suppose you have one file like getChangeHistory.ts -

const getChangeHistory = async (
  promotionId: string,
  fetchAll: boolean = false,
): Promise<ApiResponse> => {
  const baseUrl: string = `apiUrl`;
  const params: string = fetchAll ? 'fetch=ALL' : '';
  const changeHistoryApiUrl: string = `${baseUrl}?${params}`;
  const axiosInstance: AxiosInstance = getAxiosInstance('apiUrl');
  const response: AxiosResponse = await axiosInstance.get('changeHistoryApiUrl');
  return response.data;
};

Enter fullscreen mode Exit fullscreen mode

In above code we will try to mock getAxiosInstance method and provide our own implementation because this method is responsible for api call -

jest.mock('path of the file where getAxiosInstance is define', () => ({
  getAxiosInstance: jest.fn(),
}));

// example : '../../../../../src/lib/api/config'
Enter fullscreen mode Exit fullscreen mode

Now your test case will look like -


describe('getChangeHistory', () => {
  let mockedAxiosInstance: jest.Mocked<any>;
  const offerId: string = '1234567890';

  beforeEach(() => {
    mockedAxiosInstance = getAxiosInstance as jest.Mock;
  });

  it('should fetch offer history for offer', async () => {
    const offerHistory = {
      changeHistory: [

      ],
    };

    // defining implementation
    mockedAxiosInstance.mockReturnValue({
      get: jest.fn().mockResolvedValue({ data: fetchOfferHistory }),
    });

    const result = await getChangeHistory(id);

//checking assertion / interactions
    expect(result).toEqual(offerHistory);
    expect(getAxiosInstance).toHaveBeenCalledWith(TEST_USER, 'apiUrl');
  });

  it('should handle API errors gracefully', async () => {
    mockedAxiosInstance.mockReturnValue({
      get: jest.fn().mockRejectedValue(new Error('Request failed with status code 500')),
    });

    await expect(getChangeHistory(TEST_USER, id)).rejects.toThrow(
      'Request failed with status code 500',
    );
  });
});

Enter fullscreen mode Exit fullscreen mode

Lets see how can we mock any method present in file or package.

I am taking example of axios which is having it owns instance


jest.mock('axios');
const mockAxios = axios as jest.Mocked<any>;

Enter fullscreen mode Exit fullscreen mode

And define its implementation like

const fetchedBrands = () =>{}

mockAxios.create.mockImplementation(() => mockAxios);
mockAxios.get.mockResolvedValue({ data: fetchedBrands });
Enter fullscreen mode Exit fullscreen mode

Here create and get are the methods which is present in AxiosInstance . We have provided mock implementation using mockResolvedValue where fetchedBrands is mocked data.

Hence your test file look like -


jest.mock('axios');
const mockAxios = axios as jest.Mocked<any>;

const mockedData = {}

describe('Test : Search data API', () => {
  it('Should search data successfully', async () => {
    mockAxios.create.mockImplementation(() => mockAxios);
    mockAxios.get.mockResolvedValue({ data: fetchedBrands });

    const dataKeyWord = 'vers';
    const receivedResponse = await searchData(dataKeyWord);
    expect(receivedResponse).toStrictEqual(mockedData);
    expect(axios.get).toHaveBeenCalledWith(apiUrl);
  });
});
Enter fullscreen mode Exit fullscreen mode

Actually seachData method is look like -


export const searchBrands = async (user: User, brandName: string) => {
  const params: string = new URLSearchParams({ brandName }).toString();
  const searchBrandsApiUrl: string = 'apiUrl;
  const apiInstance: AxiosInstance = getAxiosInstance();
  const response: AxiosResponse = await apiInstance.get(searchBrandsApiUrl);
  return response.data;
};

Enter fullscreen mode Exit fullscreen mode

Now lets see how can we make any function from any file / package and define implementation

Like same for package -


 jest.mock('@my-package-name/folder', () => ({
      fooFunction: jest.fn(),
    }));
Enter fullscreen mode Exit fullscreen mode

Lets define the mock implementation -


 let mockfooFunction: jest.MockedFunction<any>;
  beforeEach(() => {
    jest.mock('@my-package-name/folder', () => ({
      fooFunction: jest.fn(),
    }));
    mockGetFooFunction = fooFunction as jest.MockedFunction<
      typeof fooFunction
    >;
  });
Enter fullscreen mode Exit fullscreen mode

Your test case will look like -


describe('Test Cases', () => {
  let mockFooFunction: jest.MockedFunction<any>;
  beforeEach(() => {
    jest.mock('@my-package-name/folder', () => ({
      fooFunction: jest.fn(),
    }));
    mockFooFunction= fooFuction as jest.MockedFunction<
      typeof fooFunction
    >;
  });

  it('Should do something', async () => {
    mockFooFunction.mockResolvedValue(mockedStoreData);
    /* fooFunction will be called inside MyLayout. It is a network call to fetch data available inside '@my-package-name/folder' */
    render(
      <MyLayout/>,
    );
});


Enter fullscreen mode Exit fullscreen mode

Loading....

Notes -

To improve your tests, ensure they are readable and well-structured. Here are some key points:

  • Separate Rendered and Event-Based Tests: Write tests for rendering and events separately to maintain clarity.

  • Use Mock Data Helper Functions: Create helper functions for mock data to keep your tests clean and reusable.

  • Name Tests Clearly: Follow the “Should be” convention for test case names to make their purpose clear.

  • Use act with await: For interactive tests, such as setting a text box value or clicking a button, use act with await to handle asynchronous updates.

  • Isolate Components: Ensure each component is isolated from others to avoid dependencies and side effects.

  • Focus on Integration Testing: Prioritize integration tests that cover interactions between all the tiny components to ensure comprehensive coverage.

Show me your love ❤️

Buy Me A Coffee

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more