Search code examples
javascriptreactjsunit-testingjestjsreact-testing-library

Use Mock in Jest test for rendering element in screen and find them with "findAllBy" method


So basically I'm trying to use a mock that I made with fake data for test some components. It was all fine but when I was trying to make use of the "findAllByRole" method it just return me an empty object and throws me an error telling me that all the items with the role "listitem" don't exist.


MainSection.test.js
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import MainSection from './MainSection.js';
import { getItems } from '../../Database/Database.js';
import axios from 'axios';
import mockProducts from '../../Database/mockProducts.js';

jest.mock('axios');

beforeEach(() => {
    render(<MainSection />);
});

test('Check if renders all the 20 items in the MainSection', async () => {
    axios.get.mockResolvedValue({
        data: mockProducts,
    });

    await getItems();

    const allBoxes = screen.findAllByRole('listitem');

    expect(allBoxes).toHaveLength(20);
});

MainSection.js
import React, { useState, useEffect } from 'react';
import SearchBar from './SearchBar/SearchBar.js';
import FiltersBox from './FiltersBox/FiltersBox.js';
import { getItems } from '../../Database/Database.js';
import './MainSection.css';

function MainSection() {
    const [items, setItems] = useState([]);

    useEffect(() => {
        getItems().then(res => setItems(res));
    }, []);

    return (
        <section>
            <article className='items_container-main'>
                <div className='items_container' role='list'>
                    items.map(item => (
                            <div
                                className='item_box'
                                style={{ backgroundImage: `url(${item.image})` }}
                                key={item.id}
                                role='listitem'>
                                <div className='item_box-data_container'>
                                    <div className='item_box-data_container-price_star'>
                                        <div className='item_box-price'>${item.price}</div>
                                    <div className='item_box-title'>{item.title}</div>
                                </div>
                            </div>
                        ))}
                </div>
            </article>
        </section>
    );
}

export default MainSection;


Database.js
import axios from 'axios';

export async function getItems() {
    try {
        const { data } = await axios.get('https://fakestoreapi.com/products');

        return data;
    } catch (error) {
        console.log('Error! D:', error);
    }
}

Error

error message


All my files (if you need it)

files


I think that's the reason of that error, because I need to make the test use that mock with fake data as an API response data, but I don't know how can I do it...


Solution

    • You don't need to mock the entire axios module using jest.mock('axios'), you can just mock axios.get() method.
    • You should render the component after mocking the axios.get().
    • You should use await screen.findAllByRole('listitem') to waiting for appearance

    MainSection.jsx:

    import React, { useState, useEffect } from 'react';
    import { getItems } from './Database';
    
    function MainSection() {
      const [items, setItems] = useState([]);
      console.log("🚀 ~ file: MainSection.jsx:6 ~ MainSection ~ items:", items)
    
      useEffect(() => {
        getItems().then((res) => setItems(res));
      }, []);
    
      return (
        <section>
          <article className="items_container-main">
            <div className="items_container" role="list">
              {items.map((item) => {
                return <div key={item.id} role='listitem'>{item.title}</div>;
              })}
            </div>
          </article>
        </section>
      );
    }
    
    export default MainSection;
    

    MainSection.test.jsx:

    import React from 'react';
    import { render, screen } from '@testing-library/react';
    import MainSection from './MainSection';
    import axios from 'axios';
    
    test('Check if renders all the 20 items in the MainSection', async () => {
      const axiosGetSpy = jest.spyOn(axios, 'get').mockResolvedValue({
        data: [
          { id: 1, title: 'a' },
          { id: 2, title: 'b' },
        ],
      });
      render(<MainSection />);
      const allBoxes = await screen.findAllByRole('listitem');
      expect(allBoxes).toHaveLength(2);
      axiosGetSpy.mockRestore();
    });
    

    Test result:

     PASS  stackoverflow/75539392/MainSection.test.jsx (9.547 s)
      ✓ Check if renders all the 20 items in the MainSection (96 ms)
    
      console.log
        🚀 ~ file: MainSection.jsx:6 ~ MainSection ~ items: []
    
          at MainSection (stackoverflow/75539392/MainSection.jsx:6:11)
    
      console.log
        🚀 ~ file: MainSection.jsx:6 ~ MainSection ~ items: [ { id: 1, title: 'a' }, { id: 2, title: 'b' } ]
    
          at MainSection (stackoverflow/75539392/MainSection.jsx:6:11)
    
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        10.348 s, estimated 12 s