【问题标题】:How to test component with API call in react?如何在反应中使用 API 调用测试组件?
【发布时间】:2020-09-19 20:54:49
【问题描述】:

我在测试从 API 获取数据并在屏幕上呈现的反应组件时遇到问题。 这是我得到的错误。

     ● 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)

我的测试文件CompanyDetail.test.js代码:

    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');
      });
    });

我要测试的代码 (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;

以防万一需要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;

我可以通过 props 发送数据来测试它,但我不知道如何模拟数据来测试该 url 以接收 id 并将其呈现到特定位置。任何帮助,将不胜感激。我知道为什么会出现错误,因为我没有通过任何公司名称作为 Google 进行检查。问题是我如何通过传递一些虚拟数据来测试它。

【问题讨论】:

标签: reactjs jestjs fetch react-hooks react-testing-library


【解决方案1】:

由于useFetch 预计会以任何方式异步,这可能会影响组件的工作方式,因此它需要以比返回值的 Jest spy 更复杂的方式进行模拟。请求本身可以被模拟而不是整个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,谢谢你的帮助。实施后我收到此错误。 TypeError: Cannot destructure property 'name' of '(0 , _useFetch.default)(...)' as it is undefined.
  • 我更新了代码,响应应该有data属性。如果您没有删除jest.mock,请考虑这样做,它也可能导致此错误。
  • 它解决了我上面提到的问题。是的,我也删除了 jest.mock 并将 waitFor 更改为 waitForElement 。我从这一行 await waitFor(() =&gt; expect(getByTestId('company-name').textContent).toMatch('Google')); 收到我在问题上发布的错误。 Here 是我的要点。你能告诉我我哪里做错了吗?
  • 我明白了。 waitFor 和 waitForElement 是不同的函数。 waitForElement 需要一个选择器,它不应该在这里工作,它也被弃用了。
  • 当我在@testing-library 挖掘node_modules 时有wait-for-element.js 。每当我使用 waitFor 时,它都会显示错误:TypeError: (0 , _react2.waitFor) is not a function。要使其与 waitForElement 一起使用,我必须进行哪些更改?
猜你喜欢
  • 2018-08-14
  • 2019-11-05
  • 2019-12-25
  • 1970-01-01
  • 2017-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-29
相关资源
最近更新 更多