Accessing <select> elements by the selected option's text
In my experience using dom-testing-library, I've had no issues accessing and interacting with DOM elements in the ways that a user would, except for <select> elements. Unless a label is associated with <select> elements, they are a headache to access, and even harder to do so in a way the software is used.
I would like to get a conversation started for how we can better support <select> elements moving forward.
Here's an example of a select element that would be difficult to access and use:
<select>
<option value="">State</option>
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
<option value="AZ">Arizona</option>
<option value="AR">Arkansas</option>
</select>
The first <option> is commonly used in <select> elements, like a placeholder attribute is used for text inputs. What the user sees is the text value of the first option, but it's not possible to access the <select> element given that text value.
What I have been doing on my projects has been to create a getSelectByText() function, though I would hate to have specific, one-use functions or options added to dom-testing-library.
Maybe a user should be able to select a <select> element by using getByText() using the selector option. I can't think of any really elegant solutions, but would be curious to hear from other users of the project.
For the time being, I've been using this to access <select> values based on the innerText of the selected option:
function getSelectByText(text) {
const selectElems = document.querySelectorAll('select')
for (let i = 0; i < selectElems.length; i++) {
const selectInstance = selectElems[i]
const selectedText = selectInstance.selectedOptions[0].innerText
if (selectedText === text) return selectInstance
}
throw new Error(`Unable to find a select element with the value: ${text}`)
}
What I have been doing on my projects has been to create a getSelectByText() function, though I would hate to have specific, one-use functions or options added to dom-testing-library.
As you suggest, it'd be better to use getByLabelText to get a select element, but in the event that there is no label text (though there definitely should be) it'd be better to use a getSelectByText than a getByTestId.
So I'm in favor of adding your getSelectByText utility, though rather than always referencing the first option, it should reference the currently selected option I think because that's what will be shown to the user.
What do you think? Would you like to contribute this?
I wouldn't mind taking on this task. 馃槃
The implementation above does what you described. HTMLSelectElement.selectedOptions returns an array of options that are currently selected, which there can be multiple of if the <select> element has the multiple attribute.
How would that work with queryAll? Array of arrays?
How would that work with queryAll? Array of arrays?
I think the return value of queryBySelectText would be an HTMLSelectElement or null and queryAllBySelectText would be an array of HTMLSelectElements.
Also, note that I changed from getSelectByText to getBySelectText intentionally to be consistent with other APIs (also getAllSelectByText sounds funny).
are that queryBySelectText and queryAllBySelectText looks for first default option with empty value.
Examples :
should we get Select Element by only State text or by any value( Alabama, Arizona, etc.. in the options) of options in that select.
<select>
<option value="">State</option>
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
<option value="AZ">Arizona</option>
<option value="AR">Arkansas</option>
</select>
The way I'm implementing it is that it will allow you to use the currently selected option's text value, and only that.
From the user's perspective, that is what they would see and click on if the <select> field has no label.
:tada: This issue has been resolved in version 3.6.0 :tada:
The release is available on:
npm package (@latest dist-tag)Your semantic-release bot :package::rocket:
We've added selectOptions and deselectOptions to #616
Most helpful comment
I think the return value of
queryBySelectTextwould be anHTMLSelectElementornullandqueryAllBySelectTextwould be an array ofHTMLSelectElements.Also, note that I changed from
getSelectByTexttogetBySelectTextintentionally to be consistent with other APIs (alsogetAllSelectByTextsounds funny).