Reputation: 970
I have some text like "Message failed to send" that I want to assert will not appear on screen. According to this answer, I should avoid compound logic in my assertions. And according to the React Testing Library guiding principles, I should write tests based on the user experience. So it seems like I should do something like this:
test('it does not display an error', () => {
render(<App />);
expect(screen).not.toDisplayText('failed to send');
});
This matcher doesn't seem to exist, though, and I can't find one equivalent to it.
expect(screen.queryByText('fail')).not.toBeInTheDocument()
, which passes if the text is nonexistent but fails if it is nonvisible.expect(screen.queryByText('fail')).not.toBeVisible()
, which passes if the text is nonvisible but fails if it is nonexistent.It seems like "this text does not exist and I don't care why" should be a pretty common query, but I can't find a clean way to test for it. Right now I'm just switching which test I use based on whether I expect the element to be nonexistent or nonvisible, but that feels wrong. Is there a better way?
Upvotes: 2
Views: 2280
Reputation: 970
Use a custom text match function that only matches visible text.
function matchVisible(text) {
return (content, element) => content.startsWith(text) && element.getAttribute('aria-hidden') !== 'true';
}
test('everything is fine', () => {
render(<MyApp />);
const error = screen.queryByText(matchVisible('flagrant error'));
expect(error).toBeNull();
});
Reference: https://github.com/testing-library/dom-testing-library/issues/929#issuecomment-1571823720
Upvotes: 0
Reputation: 1427
"None-existant" and "not visible" are fundamentally two different things which is why the test matchers you mentioned are working differently.
Setting styling properties like visibility: hidden;
and opacity: 0;
on an element means that the element will still occupy space on the screen and appear in the DOM tree.
On the other hand, setting display: none;
(or not rendering an element at all) will prevent the element from occupying any space or appearing in the DOM.
Both approaches to "hide" an element or text are valid depending on your requirements. With that being said, Even if there was such a custom matcher that covers both cases, I would advise to against using it. This is because using a specific test matcher for each approach, gives better context to your future self or other developers on your team on how the component works, what its intended behavior, and why a test might by failing.
Upvotes: 0