繁体   English   中英

如何使用异步调用测试具有嵌套组件/元素的 React 组件?

[英]How to test React component with nested components/elements with async calls?

我在 React 中创建了一个天气仪表板组件,它包含一个 Select 下拉列表,并基于 Select 下拉列表的值,它获取数据、设置状态然后呈现图表 这是代码:

仪表板.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 获取数据? 任何意见,将不胜感激。 我感到被困住了,我已经为此工作了几个小时。

通常,您会使用像React 测试库这样的东西,它允许您在 jest 中安装一个组件,然后通过检查该组件的 DOM output 的实用程序对其进行断言。

正如您提到的,您还需要处理您的组件进行的网络调用。 要模拟 .network 调用,您可以在window.fetch上使用 Jests spyOn功能,您可以在其中提供虚假响应,以便在调用fetch时返回您的虚假响应,而不是实际进行调用。

然而,这可能很麻烦。 我通常会使用像MSW这样的东西,它有一个很好的 faking.network 调用接口。

在呈现图表时,您的示例断言起来相当复杂。 实际上,作为为 React 编写的第一个测试,这是一个更高级的级别。 您可以决定对图表中的每个条形元素进行断言,但通常,您会说这太过分了,因为您使用的图表库可能也经过了充分测试(除非您自己实现了这些?),您不会需要在您自己的应用程序中对其进行广泛测试。

此外,通常图表不会在 Jest 内部呈现,因为它是一个虚假的 DOM 环境,实际上并没有在布局方面完全模拟浏览器。

因此,只说“它为正确的选项获取正确的数据并在到达时使用正确的数据呈现图表”可能没问题。 由于您可能不想对实际的 SVG 图表元素进行断言(并且可能不能因为我所说的 Jest 不是真正的浏览器),您可以将图表组件模拟为基本上只是 output 传入的数据到 DOM,以允许您对其进行断言。 这是一个相当高级的用例。 在大多数情况下,您通常会避免使用 mocking 实际组件,而是对实际组件输出的实际 dom 进行断言。

我不知道您使用的是什么图表库,所以我的回答很有限,因为我无法编写必要的模拟。 如果我能提供进一步帮助,请告诉我。

此外,我不知道您使用的是什么 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]))

   })

})

您将为其他选项重复此操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM