Jest.js 如何使用异步调用测试包含嵌套组件/元素的React组件?

k2arahey  于 2023-01-15  发布在  Jest
关注(0)|答案(1)|浏览(203)

我在React中创建了一个天气 Jmeter 板组件,它包含一个Select Dropdown,根据Select Dropdown的值,它获取数据,设置状态,然后呈现图表
Dashboard.js

function Dashboard() {

  const [label, setLabel] = useState(null) 
  const [labels, setLabels] = useState<String[]>([]) 
  const [data, setData] = useState<Number[]>([])

  const options = [
    { value: 'temperature', label: 'Temperature' },
    { value: 'dewPoint', label: 'Dew Point' },
    { value: 'visibility', label: 'Visibility' }
];

  const handleChange = async (selectedOption: any) => {
    const response = await fetch('http://localhost:3000/getData');
    if (!response.ok) {
        const message = `An error has occured: ${response.status}`;
        throw new Error(message);
    }
    const jsonData = await response.json();
    setLabel(selectedOption.value)
    setLabels(jsonData.map((item: { timestamp: any; }) => item.timestamp))
    if (selectedOption.value === 'temperature') {
      setData(jsonData.map((item: { temperature: any; }) => item.temperature))
    } else if (selectedOption.value === 'dewPoint') {
      setData(jsonData.map((item: { dewPoint: any; }) => item.dewPoint))
    } else {
      setData(jsonData.map((item: { visibility: any; }) => item.visibility))
    }
    
  }

  return (
    <div>
      <div  data-testid = "Select">
      <Select options={options} onChange={handleChange}/>
      </div>
      {label != null && data  != null &&
        <div data-testid= "charts"> 
          <BarChart data-testid = "BarChart" label = {label} labels={labels} selectedData = {data} />
          <RadarChart data-testid = "RadarChart" label = {label} labels={labels} selectedData = {data} />
          <LineChart  data-testid = "LineChart" label = {label} labels={labels} selectedData = {data} />
        </div>
      }
      {
        label == null && data == null &&
        <div data-testid= "no-charts">
          <h1> No data to fetch. </h1>
        </div>
      }
    </div>
    
  );
}

我如何使用Jest测试这个组件?我正在查看教程和示例,但是我遇到了一些简单的示例,其中被测试的组件只包含一些html元素。我可以使用jest.mock()来测试这个吗?我如何让它通过Jest获取数据?任何建议都将受到欢迎。我感觉被卡住了,我已经在这个上面花了几个小时了。

fd3cxomn

fd3cxomn1#

一般来说,您可以使用类似React Testing Library这样的工具,它允许您在jest内部挂载一个组件,然后通过检查该组件的DOM输出的实用程序对其进行Assert。
正如您提到的,您还需要处理组件进行网络调用的问题。要模拟网络调用,您可以在window.fetch上使用Jests spyOn功能,在此您将提供一个假响应,以便当fetch被调用时,它返回您的假响应,而不是实际进行调用。
不过,这可能会很麻烦,我通常会使用MSW之类的东西,它有一个很好的界面来伪造网络呼叫。
在呈现图表时,Assert示例相当复杂。实际上,作为编写React的第一个测试,这是一个更高级的级别。您可以决定Assert图表中的每个条形图元素,但通常您会说这是多余的,因为您使用的图表库可能也经过了良好的测试(除非您自己实现了这些功能?),您不需要在自己的应用中进行大量测试。
此外,通常图表不会在Jest内部呈现,因为它是一个伪DOM环境,实际上在布局方面并没有完全模拟浏览器。
因此,只需说“它为正确的选项获取正确的数据,并在数据到达时用正确的数据呈现图表”就可以了,因为您可能不想对实际的SVG图表元素进行Assert(可能因为我所说的Jest不是一个真实的的浏览器而不能),您可以模拟图表组件,基本上只是将传入的数据输出到DOM,来允许你Assert它。这是一个相当高级的用例。你通常会避免模拟实际的组件,而是在大多数情况下Assert由实际组件输出的真实的域。
我不知道你用的是什么样的chart lib,所以我的回答是有限的,因为我不能写必要的模拟。让我知道,如果我能进一步帮助。
另外,我不知道您使用的是什么select库,所以我无法编写有关选择选项的内容。

import { rest } from 'msw'
import { setupServer } from 'msw/node'
import { fireEvent, render, screen } from '@testing-library/react'
import Dashboard from './Dashboard' // Change to your file/import

const server = setupServer(
  rest.get('http://localhost:3000/getData', (req, res, ctx) => {
    return res(
        ctx.json([ // I made this up cos I'm not a weather expert but you'd give realistic data
            { temperature: 25, dewPoint: 2, visibility: 10 },
            { temperature: 12, dewPoint: 4, visibility: 9 },
            { temperature: 27, dewPoint: 5, visibility: 4 }
        ])
     )
  }),
)

describe('<Dashboard />', () => {

    beforeAll(() => { 
       // TODO: Mock the chart components with a fake react component that passes through `data` but `JSON.stringify`'ed in the HTML output so you can assert on it.
       server.listen() 
    })
    afterEach(() => server.resetHandlers())
    afterAll(() => server.close())

 
   it('renders temperature charts when temperature option is selected', async () => {
      const { findByTestId } = render(<Dashboard />)
      
      // TODO: Get the option for temperature and use `fireEvent.click` to click it.

      const barChart = await findByTestId('BarChart')
      expect(barChart.innerHTML).toBe(JSON.stringify([25, 12, 27]))

      const radarChart = await findByTestId('RadarChart')
      expect(radarChart.innerHTML).toBe(JSON.stringify([25, 12, 27]))

      const lineChart = await findByTestId('LineChart  ')
      expect(lineChart.innerHTML).toBe(JSON.stringify([25, 12, 27]))

   })

})

对于其他选项,您将重复此操作。

相关问题