As already mentioned, it is advisable to use behavior centric selectors (aria, text etc...) but I came across a case where I needed to query by tag name (I have an html string with paragraph tags in it, and want to truncate this in a component to see if the html tags stay intact - and getByRole('paragraph')
does not work).
That being said, I wanted to show how one could create custom queries for this case, instead of using container.querySelector
. While that's fine for most cases, a custom query will allow for more control on what to do when none are found, too many are found, etc... (& custom error messages).
The documentation only has examples for custom queries based on attributes, so what we can do is the following:
import { queryHelpers } from '@testing-library/dom';
import { queries as libraryQueries } from '@testing-library/react';
function getAllByTagName(
container: HTMLElement,
tagName: keyof JSX.IntrinsicElements,
) {
return Array.from(container.querySelectorAll<HTMLElement>(tagName));
}
function getByTagName(
container: HTMLElement,
tagName: keyof JSX.IntrinsicElements,
) {
const result = getAllByTagName(container, tagName);
if (result.length > 1) {
throw queryHelpers.getElementError(
`Found multiple elements with the tag ${tagName}`,
container,
);
}
return result[0] || null;
}
export const queries = {
...libraryQueries,
getAllByTagName,
getByTagName,
};
Now we can use these queries in our render method's options.
import { queries } from '../helpers/queries'
// it('...')
const { getAllByTagName } = render(<MyComponent />, { queries } )
const paragraphs = getAllByTagName('p')
The queries can also be globally added via a custom render method (where providers might be included, etc.)
import { render } from '@testing-library/react';
import { queries } from '../helpers/queries'
function renderWithProviders(node: JSX.Element) {
return render(
<SomeProvider>{node}</SomeProvider>, { queries }
)
}