React中的Jest模块模拟

时间:2019-08-20 18:06:43

标签: reactjs mocking jestjs react-hooks

进入功能组件+挂钩和React Unit测试,我正在尝试执行以下操作:

在一个组件中,我使用了实用程序API文件中的函数。在挂载时,我对我的api进行了异步函数调用。 在该实用程序API文件中,我想以各种方式模拟该函数,因此当我在测试中渲染组件时,它将在挂钩中看到不同的响应。它将返回一个Promise,该Promise将根据我正在测试的内容解析为不同的值。

所以我不是在嘲笑第三方模块,而是在嘲笑我自己的模块。

/**
 * App.js
 */
import React, { useState, useEffect } from 'react'
import { getData } from './api'

export default function App() {
  const [data, setData] = useState()

  // get data from api on mount
  useEffect(() => {
    loadData()
  }, [])

  // get the data and set the "data" state variable
  const loadData = async () => {
    try {
      let d = await getData()  // <---- this is what i want to mock with different values per test
      setData(d)
    } catch (err) {
      setErr('Error occurred')
    }
  }

  render (
    <div>
      data is: {JSON.stringify(data)}
    </div>
  )
}

只是在寻找一种在每次测试的测试文件中定义模拟的方法,因此在渲染组件时,它将解析/拒绝为不同的值

2 个答案:

答案 0 :(得分:2)

您可以按照以下步骤从api中模拟getData函数:

select distinct [date], id
      from #test
order by [date] desc

select [date], 
        count(*) over (order by date desc rows between current row and 7 following ) count_7_day,
        count(*) over (order by date desc rows between current row and 30 following ) count_30_day
from (select distinct [date], id
      from #test )x
order by [date] desc

这基本上是在导入api时返回模拟工厂返回的字典。

您可以使用import {render, wait} from 'react-testing-library'; import {getData} from 'path/to/api'; jest.mock('path/to/api', () => ({ getData: jest.fn() })) it('succeeds when promise resolves', () => { // This overrides getData with a resolved promise getData.mockResolvedValue('foo'); const { container } = render(<App />); // You need to wait for your mock promise to resolve return wait(() => { expect(container.textContent).toBe('data is: "foo"'); }); }); it('fails when promise rejects', () => { // This overrides getData with a rejected promise getData.mockRejectedValue('oh no'); const { container } = render(<App />); return wait(() => { expect(container.textContent).toBe('Error occurred'); }); }); 模拟该模块,然后覆盖该函数以在每次测试中解析/拒绝为不同的值。

答案 1 :(得分:1)

Daniel的答案说明了一种模拟模块的好方法。模拟getData的另一种方法是依赖注入。

import {getData} from './api';

export default function App(props) {
  const [data, setData] = useState()

  // get data from api on mount
  useEffect(() => {
    loadData()
  }, [])

  // get the data and set the "data" state variable
  const loadData = async () => {
    try {
      let d = await props.getData() // <-- change this to props.getData()
      setData(d)
    } catch (err) {
      setErr('Error occurred')
    }
  }
}

App.defaultProps = { getData };

通过将“真实” getData设置为默认道具,当您不使用道具渲染<App />时,您的应用将从'./api'调用“真实” getData。

但是,在测试中,您现在可以传递模拟getData

it('succeeds when promise resolves', () => {
  const mockGetData = jest.fn().mockResolvedValue('foo');

  const { container } = render(<App getData={mockGetData} />);
  // You need to wait for your mock promise to resolve
  return wait(() => {
    expect(container.textContent).toBe('data is: "foo"');
  });
});

it('fails when promise rejects', () => {
  const mockGetData = jest.fn().mockRejectedValue('oh no');

  const { container } = render(<App getData={mockGetData} />);
  return wait(() => {
    expect(container.textContent).toBe('Error occurred');
  });
});