When I have an anchor with some nested elements like this:
<a
href="https://www.example.com"
role="button"
>
<span>
<span class="some-icon-class" />
<span>Click here!</span>
</span>
<span class="MuiTouchRipple-root" />
</a>
I would love to have an easy way to get this anchor with a function like
getAnchorByText()
queryAnchorByText()
that returns the anchor when I say getAnchorByText('Click here!').
I did not look into that yet as I want to make sure others consider this feature as useful as well. If yes I might find the time to create a PR.
getByTestId('button-wrapper').querySelector('a')
getByText('Click here!').parentNode.parentNode
There are other HTML elements than anchors that people might want to query for. So if it is preferred we could make it an universal function:
getElementByText(<ElementName>, <Text>)
This would always return the closest element (of the type ElementName) of the text found when you go up the DOM tree.
In my example above I would use it like this:
getElementByText('a', 'Click here!')
Thanks for the suggestion!
There are other HTML elements than anchors that people might want to query for.
This goes against the goals of the library, which is to provide queries that resemble how users find elements. Tag names are invisible to a user.
There are some some cases that have special treatment by assistive technology, but I'm not sure a tag-based query is the right way to do it, or if this sufficiently resembles the way a _mouse_ (sighted) user would interact. For this I'm thinking a "getFocusableElement" query would resemble how screen readers and tab navigation allow you to cycle between links, buttons, and aria roles that mimic buttons.
I kinda feel like this is a dupe of https://github.com/kentcdodds/dom-testing-library/issues/201
Thoughts?
Yes, #201 would allow selecting the link by text at least (but not specifying that it must be a link unless you add the selector option).
Oh, that's true. This is slightly different. Hmmm...
Well, normally you interact with the elements and events bubble up, but if you were wanting to make an assertion on the element (like the HREF attribute is set correctly, which would be a totally legit assertion) then being able to access the nearest parent anchor would be useful.
What if we added an option to the query:
const anchor = getByText('Click here!', {getParent: '<selector>'})
By making it an option it de-emphasizes it as something that we don't really want people to typically use, but it gives the escape hatch we want while reducing the impact of implementation details leaking in your tests (by that I mean, this would be better than .parentElement.parentElement).
Thoughts?
If the innertext query was implemented, this would work:
getByText('nested text', {selector: 'a'})
I'd worry that a parent selector would be abused because in most cases an aria-labelledby association clarifies the relationship correctly.
Let's stick with that Alex :+1: I like that.
Sounds good to me, Alex. I try to find time during the weekend to implement it.
Any update on this @KevinHerklotz ?
I just did a quick and dirty workaround for now:
const getAnchorByText = (getByText, text) => {
let el = getByText(text)
while (el.parentNode) {
if (el.tagName === 'A') {
return el
}
el = el.parentNode
}
throw new Error(`Couldn't find a anchor with the "${text}" text`)
}
I think I could have used a custom query for this but I didn't manage to do it with https://testing-library.com/docs/api-helpers#custom-queries
You could probably use closest
Indeed, it's much cleaner, thanks for the suggestion! 馃檪
I wonder if the best way to solve this would be to say: "find me the closest interactive element" via a config option like this:
getByText(container, 'submit', {closestInteractiveElement: true})
And the implementation would be basically to add something like this to the end of the query:
return foundNode.closest('a,button') // or anything else?
Just an idea... Not sure I like it.
I like this very much!
I found it can be interesting.
Are you willing a PR to test if it works as expect?
I can try, since it looks like a good first issue to me and a good learning opportunity.
Go ahead and make the PR. No promises that I'll merge it though. I'm not sure I like the option.
I really don't think this is the right place for this. PR would still be interesting to look at (and would give this particular feature the best chance of success), but I'd need to be convinced it'd be worthwhile.
I'm going to close this for now.
Most helpful comment
I wonder if the best way to solve this would be to say: "find me the closest interactive element" via a config option like this:
And the implementation would be basically to add something like this to the end of the query:
Just an idea... Not sure I like it.