3

I am having trouble with testing react component that fetch data from API and renders on screen. This is the error that I get.

     ● Company Details › renders company details with given data

    expect(received).toMatch(expected)

    Expected substring: "Google"
    Received string:    "no name provided"

      18 |     );
      19 | 
    > 20 |     expect(getByTestId('company-name').textContent).toMatch('Google');
         |                                                     ^
      21 |     expect(getByTestId('sponsors-visa').textContent).toMatch('Yes');
      22 |     expect(getByTestId('description').textContent).toMatch('this is a company description');
      23 |   });

      at Object.<anonymous> (src/tests/components/company-detail/CompanyDetail.test.js:20:53)

My test file CompanyDetail.test.js code :

    import React from 'react';
    import CompanyDetail from '../../../components/company-detail/CompanyDetail';
    import { BrowserRouter } from 'react-router-dom';
    import { render } from '@testing-library/react';
    describe('Company Details', () => {
      let mockData;
      beforeEach(() => {
        mockData = { match: { params: { id: 4 } } };
        jest.mock('../../../components/effects/use-fetch.effect');
      });

      it('renders company details with given data', async () => {
        const { getByTestId } = render(
          <BrowserRouter>
            <CompanyDetail {...mockData} />,
          </BrowserRouter>
        );

        expect(getByTestId('company-name').textContent).toMatch('Google');
        expect(getByTestId('sponsors-visa').textContent).toMatch('Yes');
        expect(getByTestId('description').textContent).toMatch('this is a company description');
      });
    });

Code that I want to test (CompanyDetail.js)

    import CONSTANTS from '../../constants/constants';
    import { Link } from 'react-router-dom';
    import useFetch from '../effects/use-fetch.effect';

    const CompanyDetail = (props) => {
      const { id } = props.match.params;
      const { name, description, jobs, known_to_sponsor_visa } = useFetch(`${CONSTANTS.BASE_URL}/companies/${id}`);
      return (
        <React.Fragment>
          <Container>
            <Row className="m-2">
              <Col>
                <Card>
                  <Card.Body>
                    <Card.Title>
                      <h3 data-testid="company-name">{name ? name : 'no name provided'}</h3>
                    </Card.Title>
                    <Card.Text data-testid="sponsors-visa">
                      <b>Known to sponsor work visa: </b>
                      {known_to_sponsor_visa ? known_to_sponsor_visa : 'No data'}
                    </Card.Text>
                    <Card.Text data-test-id="description">{description}</Card.Text>
                  </Card.Body>
                </Card>
              </Col>
            </Row>
          </Container>
        </React.Fragment>
      );
    };

    export default CompanyDetail;

Just in case if it needs use-fetch.effect.js:

    import { useState, useEffect } from 'react';

    const useFetch = (url) => {
      const [dataArray, setData] = useState([]);

      useEffect(() => {
        try {
          const fetchData = async () => {
            const res = await fetch(url);
            const dataArray = await res.json();
            setData(dataArray.data)
          }
          fetchData();

        } catch (err) {
          console.error(err);
        }
      }, [url]);

      return dataArray;
    };

    export default useFetch;

I could test it by sending data via props but I have no idea how can I mock data to test that url to receive id and render it into specific place. Any help would be appreciated. I know why error is there because i have not passed any company name as Google to check. Problem is how can i test that by passing some dummy data .

Józef Podlecki
  • 10,453
  • 5
  • 24
  • 50
Bishwas
  • 183
  • 2
  • 18
  • Does this answer your question? [React - how do I unit test an API call in Jest?](https://stackoverflow.com/questions/61576450/react-how-do-i-unit-test-an-api-call-in-jest) – tony g Feb 10 '21 at 15:24

1 Answers1

2

Since useFetch is expected to be asynchronous any way and this may affect how the component works, it needs to be mocked in more complicated way than Jest spy that returns a value. The request itself can be mocked instead of entire useFetch:

let data = { name: 'Google', ... };
spyOn(global, 'fetch').mockResolvedValue({ json: jest.fn().mockResolvedValue({ data }) });

...

expect(getByTestId('company-name').textContent).toMatch('no name provided');
await waitFor(() => expect(getByTestId('company-name').textContent).toMatch('Google'));
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • 1
    Hello @Estus , Thank you for you help. I am getting this error after implementing it. `TypeError: Cannot destructure property 'name' of '(0 , _useFetch.default)(...)' as it is undefined.` – Bishwas Jun 01 '20 at 18:07
  • 1
    I updated the code, the response should have `data` property. In case you didn't remove `jest.mock`, consider doing this, it may cause this error too. – Estus Flask Jun 01 '20 at 20:18
  • 1
    It solved the problem I mentioned above. Yes i removed `jest.mock` as well and changed `waitFor` to `waitForElement` . I am getting the error that I posted on question from this line `await waitFor(() => expect(getByTestId('company-name').textContent).toMatch('Google'));` . [Here](https://gist.github.com/20was/2415c2e542523739b842a540038a7491) is my gist . Can you please tell me where did I wrong ? – Bishwas Jun 02 '20 at 04:27
  • I see. waitFor and waitForElement are different functions. waitForElement expects a selector, it shouldn't work here, also it's deprecated. – Estus Flask Jun 02 '20 at 05:51
  • 1
    when I dig into node_modules at the `@testing-library` has `wait-for-element.js` . Whenever I use `waitFor` it shows me error : `TypeError: (0 , _react2.waitFor) is not a function` . To make it work with `waitForElement` , what change do I have to make ? – Bishwas Jun 02 '20 at 06:05
  • I'm not sure waitForElement supports selectors to match contents, so you likely can't make it work. waitFor is supposed to be there, https://testing-library.com/docs/react-testing-library/example-intro . It's essential for blackbox testing, you won't get far without it. I see it in the package. Consider updating it to the latest version. – Estus Flask Jun 02 '20 at 06:15
  • Thank you . I finally made it work . Need to upgrade `react testing library` and had to install `jest-environment-jsdom-sixteen` . Thank you so much. – Bishwas Jun 02 '20 at 09:16