-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Encourage using aria selectors #16
Comments
It always was a little problem - what to check and how to select.
Meanwhile
So - I could 90% agree with you. Text Content to test content, data-testid to test DOM structure, if you need to test it. |
You bring up good points @theKashey. I worry that if we start encouraging using |
Alrighty, so I've written out a few utilities that have proven to be pretty useful and sensible. I think I want to put them in the library. I'm sure there are more (especially for more function queryByLabelText(container, text, {selector = '*'} = {}) {
const label = Array.from(container.querySelectorAll('label')).find(l =>
matches(l.textContent, text),
)
if (!label) {
return null
}
if (label.getAttribute('for')) {
// <label for="someId">text</label><input id="someId" />
return container.querySelector(`#${label.getAttribute('for')}`)
} else if (label.getAttribute('id')) {
// <label id="someId">text</label><input aria-labelledby="someId" />
return container.querySelector(
`[aria-labelledby="${label.getAttribute('id')}"]`,
)
} else if (label.children.length) {
// <label>text: <input /></label>
return label.querySelector(selector)
}
throw new Error(`cannot find associated element for label with text ${text}`)
}
function queryByText(container, text, {selector = '*'} = {}) {
return Array.from(container.querySelectorAll(selector)).find(
node => !node.children.length && matches(node.textContent, text),
)
}
function queryByPlaceholder(container, text) {
return Array.from(container.querySelectorAll('[placeholder]')).find(
node =>
node.getAttribute('placeholder') &&
matches(node.getAttribute('placeholder'), text),
)
}
function matches(textToMatch, matcher) {
if (typeof matcher === 'string') {
return textToMatch.toLowerCase().includes(matcher.toLowerCase())
} else if (typeof matcher === 'function') {
return matcher(textToMatch)
} else {
return matcher.test(textToMatch)
}
} |
I'm working on this right now, just FYI. We'll have several handy utilities for this stuff when I'm finished :) |
I’ll prefer to write the usage of a new stuff first. |
That's where these utilities came from. I'm applying them to tests in another project. It's cleaning things up nicely 👌 |
I don't have much experience testing React but @jgwhite gave a talk recently at EmberConf that is related. I wonder if there is a good generalized aria-aware query library that could be used in tests across frameworks. |
Thanks for that link @aciccarello! @jgwhite that was a great talk! That's exactly what I'm trying to accomplish in this issue and your talk was very validating. Thank you! |
@kentcdodds it is really really exciting (and also validating) to see you working on the same ideas. I’m starting work on a formal RFC for Ember’s testing toolkit next week and I’ll be sure to reference this as prior art! Thanks to @aciccarello for making the connection 🙌 |
I'm almost finished with my implementation and improved FAQ/README recommendations. I think that tools which encourage improved practices (both for how we write tests as well as how we write applications) are really important and I'm excited by the future here. I'm also very surprised this isn't already mainstream. These ideas actually feel quite obvious... |
**What**: Add the following methods - queryByText - getByText - queryByPlaceholderText - getByPlaceholderText - queryByLabelText - getByLabelText **Why**: Closes #16 These will really improve the usability of this module. These also align much better with the guiding principles 👍 **How**: - Created a `queries.js` file where we have all the logic for the queries and their associated getter functions - Migrate tests where it makes sense - Update docs considerably. **Checklist**: * [x] Documentation * [x] Tests * [x] Ready to be merged <!-- In your opinion, is this ready to be merged as soon as it's reviewed? --> * [ ] Added myself to contributors table N/A
**What**: Add the following methods - queryByText - getByText - queryByPlaceholderText - getByPlaceholderText - queryByLabelText - getByLabelText **Why**: Closes #16 These will really improve the usability of this module. These also align much better with the guiding principles 👍 **How**: - Created a `queries.js` file where we have all the logic for the queries and their associated getter functions - Migrate tests where it makes sense - Update docs considerably. **Checklist**: * [x] Documentation * [x] Tests * [x] Ready to be merged <!-- In your opinion, is this ready to be merged as soon as it's reviewed? --> * [ ] Added myself to contributors table N/A
**What**: Add the following methods - queryByText - getByText - queryByPlaceholderText - getByPlaceholderText - queryByLabelText - getByLabelText **Why**: Closes #16 These will really improve the usability of this module. These also align much better with the guiding principles 👍 **How**: - Created a `queries.js` file where we have all the logic for the queries and their associated getter functions - Migrate tests where it makes sense - Update docs considerably. **Checklist**: * [x] Documentation * [x] Tests * [x] Ready to be merged <!-- In your opinion, is this ready to be merged as soon as it's reviewed? --> * [ ] Added myself to contributors table N/A
**What**: Add the following methods - queryByText - getByText - queryByPlaceholderText - getByPlaceholderText - queryByLabelText - getByLabelText **Why**: Closes #16 These will really improve the usability of this module. These also align much better with the guiding principles 👍 **How**: - Created a `queries.js` file where we have all the logic for the queries and their associated getter functions - Migrate tests where it makes sense - Update docs considerably. **Checklist**: * [x] Documentation * [x] Tests * [x] Ready to be merged <!-- In your opinion, is this ready to be merged as soon as it's reviewed? --> * [ ] Added myself to contributors table N/A
I'm glad to see connections made. I'd like to see this pattern brought into test Angular applications as well. 👍 to everyone who has been working on this. |
I've been in a discussion @neoziro on my blog where he suggests using
aria-
attributes and text content instead ofdata-testid
. He makes great points and I think that it would be great if this library could provide selectors to encourage this behavior. I'm thinking that aria attributes wont always make sense for every test, in which case we could fallback todata-testid
, and for localization reasons text content may not make the most sense either, but making it easier to select based on text content could still make sense for some use cases and we could explain what those are.So, out of this issue, I'd like to see some examples of what it would take to make utilities for selecting based on aria attributes as well as text content. If it works out, then we could recommend the following order of preference for selecting:
aria-
attributes (your app should be accessible anyway, and this would encourage that as well).data-testid
s because they're way better than using class names, dom structure, or querying by React component classes.Anyone want to try doing this?
The text was updated successfully, but these errors were encountered: