I want to be able to select an option by the text that it contains, or improve documentation to make an existing strategy easier to find.
I use react-testing-library and cypress-testing-library.
getByRole('option', { contains: 'Some Option' })
Best:
getByText('Some Option', { selector: '[role=option]' })
Not best:
getAllByRole('option').filter(option =>
checkOptionForText('Some Option') // not sure where to look
)
If a new option would not break anything. I realize that getByRole supports every role available. Some roles like navigation would be a bad case for this enhancement. Other roles such as link would be improved.
Hi @jsphstls,
Thanks for bringing this up. What do you think of this:
const someOption = getByRole((role, element) => role === 'option' && element.textContent === 'Some Option')
That is supported today and gives you the most amount of flexibility. I'm not sure that I want to promote this use case to a simpler API, so I'm thinking that the current API should be enough for you. What does everyone watching think?
Another idea
within(getByLabelText('select something')).getByText('the option I want')
Thanks folks, that's some speedy feedback 馃槃
I made a codesandbox: https://codesandbox.io/s/dom-testing-libraryissues354-zscq0
@kentcdodds I tried out your suggestion but the feedback for failed selections was cryptic:
Error: Unable to find an element with the role "function (role, element) {
return role === "option" && element.textContent === "Hello";
}"
Once I realized I needed a match for whitespace (my bad) it started working 馃憤
@alexkrolick I forgot about the magical power of within. Unfortunately I still need to select role=option specifically due to duplicate text. Even if I clean up the HTML, a real user is looking for an option regardless and I want to match their usage.
Overall, there are ways to currently achieve this but each comes with their own fragility. What I am after is:
IDK, maybe there should be a way of combining queries. Someone did propose that before. This would work for combining queryAll queries:
_.intersection(queryAllByRole('option'), queryAllByText('whatever'))
https://lodash.com/docs/4.17.15#intersection
If we had a builtin version of that it would need to have a way to do something like the get/find/(All) variants
Why not have an API like within() ?
among(getAllByRole('option')).getByText('Some option')
I guess within could take an array, that wouldn't be a breaking change
How about a more generic queryAllBy (and the corresponding getAllBy({ ... })):
queryAllBy({ text: /some option/, role: 'option' })
And why not, the corresponding versions without All in the name, that returns the first match.
Someone suggested something like that a while ago, but we weren't sure it was worth making a substantial API change to support this use case. https://github.com/testing-library/dom-testing-library/issues/266
I might be falling into the habit of teasing too often but this would be covered by accessible name computation as well. The API would be as simple as getByRole('option', { name: "Option 1" })
I guess
withincould take an array, that wouldn't be a breaking change
That could be misinterpreted as querying within multiple parents.
I'm really intrigued by this accessible name query @eps1lon :)
I'm going to go ahead and close this in favor of the accessible name computation @eps1lon is working on.
Most helpful comment
Another idea