如何通过接近React Testing库中的另一个元素来获取元素

时间:2020-07-17 22:57:19

标签: html testing dom react-testing-library

我一直在尝试使用React Testing Library并遵循其guiding principles编写一些测试,因为这些测试应该以用户使用它的方式来测试应用程序组件。

我有一个组件,该组件呈现具有多个字段的对象列表,每个对象都具有多个字段,从而产生如下所示的DOM:

<div>
  <h1>Fluffy</h1>
  <h2>Cat</h2>
  <span>3 years old</span>
</div>
<div>
  <h1>Oscar</h1>
  <h2>Cat</h2>
  <span>2 years old</span>
</div>
<div>
  <h1>Charlie</h1>
  <h2>Dog</h2>
  <span>3 years old</span>
</div>

我想断言每个对象都正确地显示了相关字段,但是我看不到如何使用React Testing Library做到这一点。到目前为止,我有:

it('renders the animal names, species, and ages', () => {
  render(<MyAnimalsComponent />)

  const fluffyName = screen.getByRole('heading', { name: 'Fluffy' })
  expect(fluffyName).toBeInTheDocument()

  // The problem here is that there are multiple headings with the name "Cat" (Fluffy and Oscar) and I have no way of checking that the one that is returned is actually the one for Fluffy.
  const fluffySpecies = screen.getByRole('heading', { name: 'Cat' })
  expect(fluffySpecies).toBeInTheDocument()

  // Likewise, the age "3 years old" is rendered for both Fluffy and Charlie. How do I make sure I get the one that is rendered in the same container as Fluffy's name?
  const fluffyAge = screen.getByText('3 years old')
  expect(fluffyAge).toBeInTheDocument()
})

有什么方法可以使用React Testing库中的查询方法来仅查找与另一个元素具有共同父元素的元素吗?还是一种获取元素父元素然后仅查找该元素子元素的方法?

在仍然遵循React Testing库的指导原则的情况下实现此目标的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

解决此问题的一种方法是使用顶级getByRolegetByText方法并将一个元素作为第一个参数传递,以将查询限制为该元素。

在我的示例中,这涉及在一些包装器元素上设置role属性,以使其在语义上更容易找到这些元素:

<div role="list">
  <div role="listitem">
    <h1>Fluffy</h1>
    <h2>Cat</h2>
    <span>3 years old</span>
  </div>
  <div role="listitem">
    <h1>Oscar</h1>
    <h2>Cat</h2>
    <span>2 years old</span>
  </div>
  <div role="listitem">
    <h1>Charlie</h1>
    <h2>Dog</h2>
    <span>3 years old</span>
  </div>
</div>

然后在测试中,我找到了不同的列表项目,然后对这些项目进行了查询:

import { render, screen, getByText, getByRole } from '@testing-library/react'

it('renders the animal names, species, and ages', () => {
  render(<MyAnimalsComponent />)

  const animals = screen.getAllByRole('listitem')

  const fluffyName = getByRole(animals[0], 'heading', { name: 'Fluffy' })
  expect(fluffyName).toBeInTheDocument()

  const fluffySpecies = getByRole(animals[0], 'heading', { name: 'Cat' })
  expect(fluffySpecies).toBeInTheDocument()

  const fluffyAge = getByText(animals[0], '3 years old')
  expect(fluffyAge).toBeInTheDocument()
})