testing-library / testing-library/dom-testing-library
Off-screen/hidden elements still queryable
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 3.3k
- Forks
- 474
- PR merge metrics
- No merged PRs in 30d
Description
dom-testing-libraryversion: 3.16.4reactversion: 16.8.0-alpha.1nodeversion: 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?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Review the dom-testing-library querySelector-based implementation and its existing tests first. Clarify whether display:none, visibility:hidden, and off-screen elements should be excluded and whether the behavior is opt-in; done means focused tests cover the agreed cases without assuming unsupported visual edge cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, react
- Domain
- testing-qa
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 28/100