-
Notifications
You must be signed in to change notification settings - Fork 470
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add more robust selector handling for getByLabelText #373
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking good.
I want to make this a non-breaking change, but it really is a breaking change 🙁
src/queries/label-text.js
Outdated
const elementsMatchingSelector = new Set(container.querySelectorAll(selector)) | ||
return allMatches.filter(matchingElement => | ||
elementsMatchingSelector.has(matchingElement), | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'd be better off with matches
here: https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a feeling this wasn't the best way. Probably could have done a little more digging haha.
expect(result).toHaveLength(1) | ||
expect(result[0].id).toBe('input1') | ||
}) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add another test for the situation I found myself in where we had two elements that had the same label text?
const {getByLabelText} = render(`
<label>
Test Label
<input />
</label>
<label>
Test Label
<textarea></textarea>
</label>
`)
// select the input
Thanks!
Relates to [this PR](testing-library/dom-testing-library#373).
Passes with no changes to production code
Yeah, it totally is. Even one of the cases I pointed out in the issue
|
matchingElement.matches sounds a little weird
Wait. So to be clear, what you're saying is that with these changes I can't get the input in your example with |
More specifically, the query will return the input and the span as matches. So if you only want the input it needs to be filtered down with the selector. |
It's easy enough to change if that's not what you want. What is the correct behavior is in that situation? The Example: const {getAllByLabelText} = render(`
<label>
<h1>Test</h1>
<h2>Label</h2>
<input id="input1" />
</label>
`)
// Returns 3 elements [h1, h2, input]
const result = getAllByLabelText(/Test Label/i) |
That case with the h1/h2 should only return the input element. |
That definitely makes sense. How should we qualify which children are the label and which are labeled? The current behavior with label children (before this change), is to do Does one of these make sense?
|
I went ahead with something like my second option. If that's not right I can totally change it 👍 So it will now pick up
Then those results are filtered down based on the provided |
src/queries/label-text.js
Outdated
} | ||
if (label.childNodes.length) { | ||
// <label>text: <input /></label> | ||
return label.querySelector(selector) | ||
label | ||
.querySelectorAll('input, textarea') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is insufficient. We need to select every form control element type. Unfortunately there's not a common class that all form control elements inherit from, but I think we'd be safe if we found every element that supports the .labels
property.
I'm not sure of the best way to do this, but here's a list of all the element types: https://developer.mozilla.org/en-US/docs/Web/API (Everything named something like HTML*Element).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll look into that and see if I can find all of them. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your work on this!
Happy to help! |
I think I got all of them. One thing that's a little unsatisfying is it necessitates updating the list of supported elements manually if another element is added. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me! Because this is a breaking change, I'd like to consider whether there's anything else we'd like to include in this major version bump. I don't expect it to be a difficult upgrade for people, but it would probably be a good thing to include as many breaking changes at once if there's anything else we'd like to break 🤔
Somewhat related to this change, I wonder if it's worth doing a quick look at the other queries to make sure the behavior of the selector option is consistent across them? |
I believe all the other queries are directed at the element that's actually returned, rather than taking a hop like this one does, but if you'd like to double check that'd be great :) |
Another thing that we should maybe consider is adding a |
I'm not fully sure what the The main case where people will run into issues is if they have a label that does multiple of these things:
Before, if the label had a So if we added a Edit: If we do want it to completely go back to the old behavior, maybe we could do a boolean option instead. |
I checked the docs and it looks like |
Awesome. Thanks for checking. I think we're about ready to make this happen. But since it's a breaking change, I want to take advantage of that churn to make other breaking changes we've been wanting to make (#376). I'd love it if you want to weigh in :) |
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit d5ca2f8:
|
Codecov Report
@@ Coverage Diff @@
## next #373 +/- ##
===================================
Coverage 100% 100%
===================================
Files 22 22
Lines 404 409 +5
Branches 95 95
===================================
+ Hits 404 409 +5
Continue to review full report at Codecov.
|
I am having the same issue when working with Downshift I would love to switch back to getLabelByText. My current solution is to use getByRole('textbox') but that doesn't make me excited. My question is how can I help to get this PR merged? |
I'm finally back from a bit of a break. I'll be taking a hard look at breaking shipping some breaking changes soon. |
Sorry this has taken so long. Really hoping to get to this soon. It's just been a beast to make enough time for this major version bump. And I try to avoid doing those 😅 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, ready to merge this into next
!
🎉 This PR is included in version 6.16.0 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
I made a little mistake with the auto-release here, but the latest is still pointing to the right version so hopefully we don't have issues with people getting 6.16.0 by mistake. In any case, you will soon be able to test this via |
Closes #372 BREAKING CHANGE: If you used the `selector` option in `ByLabelText` queries, then you will probably need to update that code to be able to find the label you're looking for.
Closes #372 BREAKING CHANGE: If you used the `selector` option in `ByLabelText` queries, then you will probably need to update that code to be able to find the label you're looking for.
Closes #372 BREAKING CHANGE: If you used the `selector` option in `ByLabelText` queries, then you will probably need to update that code to be able to find the label you're looking for.
Closes #372 BREAKING CHANGE: If you used the `selector` option in `ByLabelText` queries, then you will probably need to update that code to be able to find the label you're looking for.
Closes #372 BREAKING CHANGE: If you used the `selector` option in `ByLabelText` queries, then you will probably need to update that code to be able to find the label you're looking for.
Awesome! Glad I was able to help. :) |
hmm... I've got a bit lost on where this change was introduced, i guess it was 6.16.0 but that release is tagged as pre-release and this change is highlighted once again in v7.0.0-beta.1, where it was properly marked as BREAKING unfortunately, that mention didn't make it to the final 7.0.0 release notes, so I suggest we add it there cc @kentcdodds also this is breaking in one more way not mentioned in this PR: now so this change can be breaking even for those who don't use |
on the other hand WHATWG Spec states
So apparently having several inputs within one label is not that against the spec and the first input should be the one returned |
Whoops! Sorry about that. We had a few bumps in the release and missed a few things in the notes 😬 I'll get that added asap. |
@kentcdodds, do you want me to put in a PR to address @dreyks suggestion that it return the first input instead of all of them in the case that a label contains multiple inputs? |
That seems reasonable to me, yes. Thank you! I'll consider this a bug fix rather than a breaking change. |
Relates to [this PR](testing-library/dom-testing-library#373).
What:
Adds more robust handling of the
selector
option that can be passed to thegetByLabelText
family of queries. Fixes #372.Why:
More info in related issue (#372)
How:
Just some tweaking to
label-text.js
. It wasn't trying to find all the possible matches, and instead would short-circuit when it found something. For example, if the label had afor
attribute, it wouldn't also check for elements that werearia-labelledby
that label. Then I also added another step at the end where it filters down the elements it found based on theselector
option.Checklist: