使用 react-testing-library 测试具有动态内容的列表的惯用方法是什么
What's the idiomatic way of testing a list with dynamic content using 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>
}
这是测试
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()
})
})
问题
1)有没有办法避免在这种情况下使用data-testid?或者这是对逃生舱口的合理使用?
2) 更一般地说,是否有更惯用的方法使用 RTL 来测试此类组件?
谢谢!
我会使用 ul
和 li
标签呈现您的列表,使其更具语义。如果由于某种原因您不能这样做,您仍然可以添加 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()
})
})
})
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>
}
这是测试
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()
})
})
问题
1)有没有办法避免在这种情况下使用data-testid?或者这是对逃生舱口的合理使用?
2) 更一般地说,是否有更惯用的方法使用 RTL 来测试此类组件?
谢谢!
我会使用 ul
和 li
标签呈现您的列表,使其更具语义。如果由于某种原因您不能这样做,您仍然可以添加 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()
})
})
})