如何使用jest和react-testing-library测试元素是否不存在?

我有一个组件库,我正在使用Jest和react-testing-library编写单元测试。基于某些道具或事件,我想验证某些元素没有被渲染。

getByTextgetByTestId等,如果在react-testing-library中未找到该元素,则会在expect函数触发之前导致测试失败,则在react-testing-library中抛出和错误。

如何使用react-testing-library测试不存在的东西?

205437 次浏览

DOM测试库文档-出现和消失

不存在断言元素

标准getBy方法在找不到元素时抛出错误,因此 如果你想断言DOM中的元素是, 你可以使用queryBy api代替:

const submitButton = screen.queryByText('submit')
expect(submitButton).toBeNull() // it doesn't exist
queryAll api版本返回一个匹配节点的数组。的长度 类中添加或删除元素后,数组对于断言非常有用 DOM . < / p >
const submitButtons = screen.queryAllByText('submit')
expect(submitButtons).toHaveLength(2) // expect 2 elements

not.toBeInTheDocument

jest-dom实用程序库提供了 .toBeInTheDocument()匹配器,可用于断言元素为 在文件正文中,或者不是。这可能比断言更有意义 查询结果为null

import '@testing-library/jest-dom/extend-expect'
// use `queryBy` to avoid throwing an error with `getBy`
const submitButton = screen.queryByText('submit')
expect(submitButton).not.toBeInTheDocument()

你必须使用querybytestd而不是getbytestd。

这里是一个代码示例,我想测试是否组件与“汽车”id不存在。

 describe('And there is no car', () => {
it('Should not display car mark', () => {
const props = {
...defaultProps,
base: null,
}
const { queryByTestId } = render(
<IntlProvider locale="fr" messages={fr}>
<CarContainer{...props} />
</IntlProvider>,
);
expect(queryByTestId(/car/)).toBeNull();
});
});

您可以使用react-native-testing-library "getAllByType",然后检查该组件是否为空。优点是不必设置testd,也应该与第三方组件一起工作

 it('should contain Customer component', () => {
const component = render(<Details/>);
const customerComponent = component.getAllByType(Customer);
expect(customerComponent).not.toBeNull();
});

使用queryBy / queryAllBy

如你所说,如果没有找到任何东西,getBy*getAllBy*将抛出一个错误。

然而,等价的方法queryBy*queryAllBy*返回null[]:

queryBy

queryBy*查询返回查询的第一个匹配节点,如果没有匹配的元素则返回null。这对于断言不存在的元素非常有用。如果找到多个匹配项,则会抛出(使用queryAllBy代替)。

< >强queryAllBy queryAllBy*查询返回一个包含所有匹配节点的数组,如果没有元素匹配则返回一个空数组([])

https://testing-library.com/docs/dom-testing-library/api-queries#queryby

所以对于你提到的两个特定的查询,你应该使用queryByTextqueryByTestId,但它们适用于所有查询,而不仅仅是这两个。

当没有找到元素时,getBy*将抛出一个错误,因此您可以检查它

expect(() => getByText('your text')).toThrow('Unable to find an element');

另一个解决方案:你也可以使用try/catch

expect.assertions(1)
try {
// if the element is found, the following expect will fail the test
expect(getByTestId('your-test-id')).not.toBeVisible();
} catch (error) {
// otherwise, the expect will throw, and the following expect will pass the test
expect(true).toBeTruthy();
}
const submitButton = screen.queryByText('submit')
expect(submitButton).toBeNull() // it doesn't exist


expect(submitButton).not.toBeNull() // it exist

对我来说(如果你想使用getbytestd):

expect(() => getByTestId('time-label')).toThrow()

我最近为一个笑话黄瓜项目写了一个检查元素可见性的方法。

希望对大家有用。

public async checknotVisibility(page:Page,location:string) :Promise<void>
{
const element = await page.waitForSelector(location);
expect(element).not.toBe(location);
}

不想埋没线索,所以这里有正确的解决方案✅

waitFor(() => queryByTestId(/car/) === null)

到目前为止,这里所有的答案都有问题……

不要使用getByTestId,它将不得不等待😴的超时,因为它期望元素最终会在那里。然后它就会抛出,你必须捕捉它,这是一个可读性较差的测试。最后,您可以有一个RACE CONDITION🚫,其中getbytestd在元素消失之前被求值,我们的测试将消失。

如果页面正在改变,元素还没有消失,只使用queryByTestId而不使用waitFor是有问题的。竞态🚫

deleteCarButton.click();
expect(queryByTestId(/car/)).toBeNull(); //

如果expect()在点击处理程序和渲染完成之前得到计算,我们将会有一个糟糕的时间。

希望这对你有所帮助

该表显示了函数错误的原因/时间

哪些函数是异步的

函数的return语句是什么

enter image description here

// check if modal can be open
const openModalBtn = await screen.findByTestId("open-modal-btn");
fireEvent.click(openModalBtn);


expect(
await screen.findByTestId(`title-modal`)
).toBeInTheDocument();




// check if modal can be close
const closeModalBtn = await screen.findByTestId(
"close-modal-btn"
);
fireEvent.click(closeModalBtn);


const sleep = (ms: number) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};


await sleep(500);
expect(screen.queryByTestId("title-modal")).toBeNull();