Summary
-
This post tries to avoid the usage of the attribute
data-testid
as much as possible -
If the ordered elements can be queried by
role
(usually ali
element), usegetAllByRole
,findAllByRole
, orqueryAllByRole
to get the ordered array of elements, and iterate each elements to make sure of the order -
If the ordered elements can not be queried by
role
, follow the steps below -
In each iteration, compare the current item/node with next item using the method
compareDocumentPosition
-
If the next node is actually positioned after the current node, the method
compareDocumentPosition
should return4
or, precisely, equal to the value of the constantNode.DOCUMENT_POSITION_FOLLOWING
expect(currentNode.compareDocumentPosition(nextNode)).toBe( Node.DOCUMENT_POSITION_FOLLOWING );
So I have been trying out TDD (test-driven development) lately, and I have met with some roadblock: how do I properly test ordered elements, and make sure those elements are in the correct order?
I gotta say, the approach Testing Library use on finding elements are quite unique. Instead of using class name, elements are quried by using several matchers:
- role
- label text (usually in form elements)
- text
- display value
- alt text (usually in image)
- title attribute
- test id (not really recommended, explanation below)
This has many benefits, but also makes me stuck in a roadblock I mentioned before.
We need to be careful, as, for example, if we query using the text matcher, like this:
render(
<article>
<p>There's an empty space inside my heart</p>
<p>Where the weeds take root</p>
<p>So now I'll set you free</p>
<p>I'll set you free</p>
</article>
);
screen.getByText("There's an empty space inside my heart");
screen.getByText("Where the weeds take root");
screen.getByText("So now I'll set you free");
screen.getByText("I'll set you free");
it only get and assert that those elements exists, not assserting that those elements are in the correct order.
Using getAllByRole
when the elements' role are defined
If the elements' role are defined, usually in li
element, querying elements
are simpler, by using getAllByRole
method.
Let's say there's an HTML document like this:
render(
<>
<h1>My Top 5 Favorite Radiohead Albums</h1>
<ol>
<li>In Rainbows</li>
<li>The Bends</li>
<li>OK Computer</li>
<li>The King Of Limbs</li>
<li>Kid A</li>
</ol>
</>
);
you can query those elements like this:
// Will return every <li /> element
const listElements = screen.getAllByRole("listitem");
and, to make sure those elements are in the correct order, iterate every list element:
// Defining the expected list order
const albumList = [
"In Rainbows",
"The Bends",
"OK Computer",
"The King Of Limbs",
"Kid A",
];
// Assert it on every element
listElements.forEach((listElement, index) => {
expect(listElement).toHaveTextContent(albumList[index]);
});
It's also important to note that li
are one of the elements you can do
this--take a look at this
docs.
Using the compareDocumentPosition
method
Another approach of asserting the order of elements are comparing the position
of elements in DOM tree, using the compareDocumentPosition
method.
Let's say there exists a HTML document like this:
render(
<>
<p>text 1</p>
<p>text 2</p>
<p>text 3</p>
<p>text 4</p>
<p>text 5</p>
</>
);
Unlike previous example, we actually can't use getAllByRole
because, by
default, the p
tag doesn't have ARIA roles defined.
So, an alternative way in this case are like this:
// Define the expected order
const paragraphElements = ["text 1", "text 2", "text 3", "text 4", "text 5"];
// Iterate every element of the expected order
for (let i = 0; i < paragraphElements.length - 1; i++) {
const currentParagraph = screen.getByText(paragraphElements[i]);
const nextParagraph = screen.getByText(paragraphElements[i + 1]);
// Compare the current paragraph element position relative to the expected
// next paragraph element.
//
// If `compareDocumentPosition` returns value 4 or in other words equal to
// the constant `Node.DOCUMENT_POSITION_FOLLOWING` the test should pass.
expect(currentParagraph.compareDocumentPosition(nextParagraph)).toBe(
Node.DOCUMENT_POSITION_FOLLOWING
);
}
This way, the elements are assert to have the correct order.
Hope this helps.