使用 react-testing-library 测试具有动态内容的列表的惯用方法是什么

use*_*886 5 testing reactjs react-testing-library

刚接触 RTL 并试图了解如何以地道的方式做事。我有一个包含动态元素的列表(它出现在某些行而不是其他行中)。

这是组件:

import React from 'react'
export default function DummyList ({ items }) {
  return <div>
    {items.map(item => <ListItem item={item} key={item.name} />)}
  </div>
}

export function ListItem ({ item: { name, isActive } }) {
  return <div data-testid='list-item'>
    <span>{name}</span>
    {isActive && <span>Active!</span>}
  </div>
}
Run Code Online (Sandbox Code Playgroud)

这是测试

import React from 'react'
import { render, getByText, queryByText, getAllByTestId } from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect'
import DummyList from './index'

describe('DummyList', () => {
  it('renders', async () => {
    const items = [
      { name: 'Unused Item' },
      { name: 'Used Item', isActive: true }
    ]

    render(<DummyList items={items} />)

    const listItems = getAllByTestId(document.body, 'list-item')
    expect(listItems).toHaveLength(2)

    expect(getByText(listItems[0], 'Unused Item')).toBeInTheDocument()
    expect(queryByText(listItems[0], 'Active!')).not.toBeInTheDocument()

    expect(getByText(listItems[1], 'Used Item')).toBeInTheDocument()
    expect(queryByText(listItems[1], 'Active!')).toBeInTheDocument()
  })
})
Run Code Online (Sandbox Code Playgroud)

问题

1) 有没有办法避免在这种情况下使用 data-testid?或者这是对逃生舱口的合理使用吗?

2)更一般地说,是否有使用 RTL 来测试此类组件的更惯用的方法?

谢谢!

Gio*_*Gpx 16

我会使用ulli标签呈现您的列表,以使其更具语义。如果由于某种原因你不能这样做,你仍然可以添加aria-role属性。完成后,您可以使用getAllByRole('listitem')来获取元素:

describe('DummyList', () => {
  it('render the items', async () => {
    const items = [
      { name: 'Unused Item' },
      { name: 'Used Item', isActive: true }
    ]

    // You can get the query methods directly from render
    const { getAllByRole } = render(<DummyList items={items} />)

    const listItems = getAllByRole('listitem')
    expect(listItems).toHaveLength(2)

    // I use a `forEach` to make the test dynamic in case we decide
    // to generate items dynamically in the future
    // This method is also implicitly testing the order
    listItems.forEach((item, index) => {
      // You can import wihthin from @testing-library/react
      const { getByText, queryByText } = within(item)
      const { name, isActive } = items[index]
      expect(getByText(name)).toBeInTheDocument()
      isActive
        ? expect(getByText('Active!')).toBeInTheDocument()
        : expect(queryByText('Active!')).not.toBeInTheDocument()
    })
  })
})
Run Code Online (Sandbox Code Playgroud)