Description
dom-testing-library
version: 3.16.4react
version: 16.8.0-alpha.1node
version: 8.11.3npm
(oryarn
) version: 5.6.0
Relevant code or config:
test("off-screen element not queryable", () => {
const { queryByText } = render(
<div style={{ height: "150px", overflow: "auto" }}>
<div style={{ height: "100px" }}>Paragraph-1</div>
<div style={{ height: "100px" }}>Paragraph-2</div>
<div style={{ height: "100px" }}>Paragraph-3</div>
<div style={{ height: "100px" }}>Paragraph-4</div>
</div>
);
const paragraph = queryByText("Paragraph-4");
expect(paragraph).toBeNull();
});
test("non-displayed element not queryable", () => {
const { queryByText } = render(
<div style={{ height: "200px", overflow: "auto" }}>
<div style={{ height: "100px" }}>Paragraph-1</div>
<div style={{ height: "100px", display: "none" }}>
NotDisplayed-Paragraph
</div>
</div>
);
const paragraph = queryByText("NotDisplayed-Paragraph");
expect(paragraph).toBeNull();
});
test("hidden element not queryable", () => {
const { queryByText } = render(
<div style={{ height: "200px", overflow: "auto" }}>
<div style={{ height: "100px" }}>Paragraph-1</div>
<div style={{ height: "100px", visibility: "hidden" }}>
Hidden-Paragraph
</div>
</div>
);
const paragraph = queryByText("Hidden-Paragraph");
expect(paragraph).toBeNull();
});
What you did:
Tried to write the tests above, expected them to pass.
What happened:
Tests failed:
off-screen element not queryable
2ms
expect(received).toBeNull()
Expected value to be null, instead received
<div style="height: 100px;">Paragraph-4</div>
14 | </div>
15 | );
16 | const paragraph = queryByText("Paragraph-4");
> 17 | expect(paragraph).toBeNull();
18 | });
20 | test("non-displayed element not queryable", () => {
non-displayed element not queryable
1ms
expect(received).toBeNull()
Expected value to be null, instead received
<div style="height: 100px; display: none;">NotDisplayed-Paragraph</div>
27 | </div>
28 | );
29 | const paragraph = queryByText("NotDisplayed-Paragraph");
> 30 | expect(paragraph).toBeNull();
31 | });
33 | test("hidden element not queryable", () => {
hidden element not queryable
1ms
expect(received).toBeNull()
Expected value to be null, instead received
<div style="height: 100px; visibility: hidden;">Hidden-Paragraph</div>
40 | </div>
41 | );
42 | const paragraph = queryByText("Hidden-Paragraph");
> 43 | expect(paragraph).toBeNull();
44 | });
Reproduction:
https://codesandbox.io/s/2zwjwyp13n
Problem description:
First off, I'm new to react-testing-library
. I read @kentcdodds philosophy - this quote I totally agree with: "The more your tests resemble the way your software is used, the more confidence they can give you.".
That said, I was expecting in the tests above that the given elements would not be able to queried because they are hidden/non-visible/off-screen. I dug around in the dom-testing-library
code and noticed that querySelector
is still being used but I don't understand how this implementation accounts for elements that the user cannot see, like things that are off-screen, hidden, etc.
I would absolutely love to be able to write tests that exercise a product the way a user would interact with it. But I'm unsure if I can trust dom-testing-library
in this sense.
Outside of hidden/off-screen elements cases (and not related to this issue), what about clicking on elements that are unclickable? This is a (surprisingly) frequent z-index bug I've seen. fireEvent
wouldn't really cut it. There are lots of edge cases here...
Suggested solution:
I realize that it would be quite difficult to account for all of the cases where an element can't be queried (off the top of my head - opacity = 0, transforms off screen, scaled down, filters, clip-path, etc.) But I would expect at least display = none, visibility = hidden, and off-screen elements to be accounted for. I think this can be handled through getBoundingClientRect
but that would sacrifice perf. Maybe this is something that a user could toggle through render
?