【问题标题】:How to test a React functional component that loads data during mount如何测试在挂载期间加载数据的 React 功能组件
【发布时间】:2020-07-23 07:38:13
【问题描述】:

我希望有不同的单元测试来测试我的组件的不同状态以及它与异步请求的交互。我这样做有很多困难。大多数文档都说要“模拟”触发异步状态更改的事件(即模拟组件的单击),但是,我的状态应该在组件加载时更改,而不是通过任何用户交互来更改。我看到了对act 函数(https://reactjs.org/blog/2019/02/06/react-v16.8.0.html#testing-hooks)的引用,但我不知道如何在这种情况下实现它。

这是我的功能性反应组件:

import { useRequest } from '@umijs/hooks' // Request custom hook

// An async function that does an async task to get data
async function someAsyncFunctionToFetch() => {
    return Promise.resolve({data: 'data'})
}

// The functional component
export function TestComponent() {
  const { data, error, loading } = useRequest(FulfillmentService.getFullfillmentServices)

  const loadingMarkup = (
    <p>Loading</p>
  )

  const errorMarkup = (
    <p>Error</p>
  )

  const contentMarkup = (
    <p>{ data }</p>
  )

  if (loading) {
    return loadingMarkup
  } else if (error) {
    return errorMarkup
  } else if (!isEmpty(data)) {
    return contentMarkup
  } else {
    return <p>Some empty state</p>
  }
}

这些是我想要实现的测试:

describe('TestComponent', () => {
    it.todo('when data is loading the loading markup should be rendered')
    it.todo('when data fetching results in an error the error markup should be rendered')
    it.todo('when data fetching returns with valid data the content markup should be rendered')
    it.todo('when data fetching returns an empty data object the empty state markup should be rendered')
})

【问题讨论】:

    标签: reactjs unit-testing jestjs enzyme


    【解决方案1】:

    我建议尝试通过将 FulfillmentService.getFullfillmentServices 移至您的 props 或创建上下文来抽象出它。这样您就可以轻松地模拟来自FulfillmentService.getFullfillmentServices 的每个响应。

    第二种选择是使用nock并拦截FulfillmentService.getFullfillmentServices的api调用。

    【讨论】:

      【解决方案2】:

      要测试组件为每个状态呈现所需的标记,您可以模拟 useRequest 挂钩的返回值。这可以使用jest.mock 函数来模拟@umijs/hooks 模块的行为来实现:

      import { useRequest } from "@umijs/hooks";
      
      jest.mock("@umijs/hooks");
      

      现在可以使用mockReturnValue 函数模拟每个状态。例如模拟加载状态:

      useRequest.mockReturnValue({ 
        loading: true 
      });
      

      每个场景的测试看起来都是这样的:

      import { useRequest } from "@umijs/hooks";
      
      jest.mock("@umijs/hooks");
      
      describe("TestComponent", () => {
        describe("loading description", () => {
          beforeEach(() => useRequest.mockReturnValue({ loading: true }));
      
          it("loading assertion", () => {/* ... */});
        });
      
        describe("error description", () => {
          beforeEach(() => useRequest.mockReturnValue({ error: "Given error" }));
      
          it("error assertion", () => {/* ... */});
        });
      
        describe("valid data description", () => {
          beforeEach(() => {
            useRequest.mockReturnValue({ data: { value: "Given data" }});
          });
      
          it("valid data assertion", () => {/* ... */});
        });
      
        describe("empty data description", () => {
          beforeEach(() => useRequest.mockReturnValue({ data: {} }));
      
          it("empty data assertion", () => {/* ... */});
        });
      });
      

      【讨论】:

      • 谢谢,这就是我最终所做的。我最终没有直接模拟模块,而是使用 DI 模式将模拟函数作为道具传递给函数。
      猜你喜欢
      • 2020-09-18
      • 2014-04-30
      • 2018-10-15
      • 2021-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-12
      • 2021-07-26
      相关资源
      最近更新 更多