React-testing-library: byTag Query

Created on 29 Jul 2019  路  17Comments  路  Source: testing-library/react-testing-library

It is very exhaustive do this:

getByText((content, element) => element.tagName.toLowerCase() === 'header'))

I could create something like a parent function that uses

(tag, content, element) => element.tagName.toLowerCase() === tag)

But... Maybe a default byTag could be interesting for the library.

Most helpful comment

For good screen reader accessibility having a h1 is very important. I'd like to be able to query by HTML type for checking the h1 of the page.

Using expect(container.querySelector("h1") works but it's not ideal.

All 17 comments

Hi @FabianoLothor.

Thanks for the suggestion. However it doesn't follow the guiding principles considering that tagName is not something that end users know about.

That said, there are two solutions to this that I can suggest:

const {container} = render(<YourThing />)
container.querySelector('header')

Or, even better:

const {getByText} = render(<YourThing />)
getByText(/text that is in the header/i)

Good luck!

OK, I see...

But, i don't know... Please, tell me...

What are the cases where the user see the role?

image

I understand your principles, and I like them.

But I don't understand why some basic features can't be implemented...

role is not a something that the user can see, but is been there.

Think a little...

I could write my code like this:

...
<header role="header">
...
</header>
...

But this dosen't make any sense. I should not change my code because the principles of a library.

You'll notice that role is low on the "Which query should I use?" list: https://testing-library.com/docs/guide-which-query

Role has semantic meaning for assistive technologies. This is what makes it better than querying based on the tag name.

Again, I strongly recommend querying by text...

Technically role doesn't make part of html. It is a custom attribute.

Plus: The same way that the role attribute it is been forced to be accepted by the principles, tags could been too.

If I am seeing a button in my screen, I am know that the element it is a button. This works to an image too, and others tags.

I agree that tags like div, span are not user-friendly, but others, could be.

Anyway... I will make a HelperFunction for it.

Something like this or close:

(tag, content, element) => element.tagName.toLowerCase() === tag)

I understand that the most of the components can be tested using querying by text, but some guarantees that my component have some at least a tag for example, are essential.

You'll notice that role is low on the "Which query should I use?" list: https://testing-library.com/docs/guide-which-query

Role has semantic meaning for assistive technologies. This is what makes it better than querying based on the tag name.

Plus 2: A good html page, following the html semantics has a important role for the assistive technologies. Even more than the role tag.

Please note that DOM Testing Library's getByRole query supports implicit roles. So as long as you're using semantic HTML, you can use getByRole to get elements without having to specify a role attribute.

If you wanted to write a helper function for that, then I don't recommend passing it to getByText because getByText(byTag('header')) doesn't make any sense...

Is there any reason you wont just use container.querySelector?

Please note that DOM Testing Library's getByRole query supports implicit roles. So as long as you're using semantic HTML, you can use getByRole to get elements without having to specify a role attribute.

If you wanted to write a helper function for that, then I don't recommend passing it to getByText because getByText(byTag('header')) doesn't make any sense...

Is there any reason you wont just use container.querySelector?

I will try to do something about tomorrow.

Thanks.

For good screen reader accessibility having a h1 is very important. I'd like to be able to query by HTML type for checking the h1 of the page.

Using expect(container.querySelector("h1") works but it's not ideal.

@BBlackwo You can build your own queries if you find that you repeat yourself often:

const [queryHeading, queryAllHeadings, getHeading, getAllHeadings, findHeading, findAllHeadings] = buildQueries(
  function queryAllHeadings(container, level) {
    return container.querySelectorAll(`h${level}`);
  },
  function getMultipleError() {
    return `Insert helpfull error message`;
  },
  function getMissingError() {
    return `Insert helpfull error message`;
  },
);
...
getHeading(1)

You can implement ByTag in a similar fashion though we don't recommend it. ByRole is a better ByTag.

Ok thanks @eps1lon

Would this not be useful for when a component can conditionally render different html elements depending on props?

Please note that DOM Testing Library's getByRole query supports implicit roles. So as long as you're using semantic HTML, you can use getByRole to get elements without having to specify a role attribute.

If you wanted to write a helper function for that, then I don't recommend passing it to getByText because getByText(byTag('header')) doesn't make any sense...

Is there any reason you wont just use container.querySelector?

container.querySelector fails terribly with Typescript though.
Would be nice to just query by tag name

Was this page helpful?
0 / 5 - 0 ratings

Related issues

julienw picture julienw  路  4Comments

alejandronanez picture alejandronanez  路  4Comments

bdauria picture bdauria  路  4Comments

addamove picture addamove  路  3Comments

chasen-bettinger picture chasen-bettinger  路  3Comments