Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: testing-library/user-event
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v12.6.0
Choose a base ref
...
head repository: testing-library/user-event
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v12.6.1
Choose a head ref
  • 5 commits
  • 5 files changed
  • 4 contributors

Commits on Dec 22, 2020

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    f1ccaad View commit details
  2. docs: add daleseo as a contributor (#528)

    * docs: update README.md
    
    * docs: update .all-contributorsrc
    
    Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
    allcontributors[bot] authored Dec 22, 2020

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    377e99c View commit details
  3. toHaveAttribute doesn't work (#524)

    Co-authored-by: Nick McCurdy <nick@nickmccurdy.com>
    DaleSeo and nickserv authored Dec 22, 2020

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    481267b View commit details
  4. docs: add nickmccurdy as a contributor (#517)

    * docs: update README.md
    
    * docs: update .all-contributorsrc
    
    Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com>
    allcontributors[bot] authored Dec 22, 2020

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    6c21e1f View commit details

Commits on Jan 21, 2021

  1. fix: selectOptions (#543)

    * fix: selectOptions on options with role #542
    
    * fix: selectOptions click event on option
    
    * fix: aria-selected
    
    * fix: handle invalid element
    ph-fritsche authored Jan 21, 2021

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    6a02a14 View commit details
Showing with 110 additions and 68 deletions.
  1. +11 −1 .all-contributorsrc
  2. +5 −4 README.md
  3. +11 −0 src/__tests__/helpers/utils.js
  4. +29 −26 src/__tests__/select-options.js
  5. +54 −37 src/select-options.js
12 changes: 11 additions & 1 deletion .all-contributorsrc
Original file line number Diff line number Diff line change
@@ -422,7 +422,8 @@
"projectManagement",
"question",
"code",
"test"
"test",
"doc"
]
},
{
@@ -706,6 +707,15 @@
"code",
"doc"
]
},
{
"login": "daleseo",
"name": "Dale Seo",
"avatar_url": "https://avatars1.githubusercontent.com/u/5466341?v=4",
"profile": "https://www.daleseo.com",
"contributions": [
"doc"
]
}
],
"commitConvention": "none",
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -120,7 +120,7 @@ test('click', () => {
)

userEvent.click(screen.getByText('Check'))
expect(screen.getByLabelText('Check')).toHaveAttribute('checked', true)
expect(screen.getByLabelText('Check')).toBeChecked()
})
```

@@ -149,8 +149,8 @@ import userEvent from '@testing-library/user-event'

test('double click', () => {
const onChange = jest.fn()
render(<input type="checkbox" id="checkbox" onChange={onChange} />)
const checkbox = screen.getByTestId('checkbox')
render(<input type="checkbox" onChange={onChange} />)
const checkbox = screen.getByRole('checkbox')
userEvent.dblClick(checkbox)
expect(onChange).toHaveBeenCalledTimes(2)
expect(checkbox).not.toBeChecked()
@@ -640,7 +640,7 @@ Thanks goes to these people ([emoji key][emojis]):
<td align="center"><a href="https://github.com/nanivijay"><img src="https://avatars0.githubusercontent.com/u/5945591?v=4" width="100px;" alt=""/><br /><sub><b>Vijay Kumar Otti</b></sub></a><br /><a href="https://github.com/testing-library/user-event/issues?q=author%3Ananivijay" title="Bug reports">🐛</a></td>
<td align="center"><a href="http://tompicton.com"><img src="https://avatars2.githubusercontent.com/u/12588098?v=4" width="100px;" alt=""/><br /><sub><b>Tom Picton</b></sub></a><br /><a href="https://github.com/testing-library/user-event/issues?q=author%3Atpict" title="Bug reports">🐛</a> <a href="https://github.com/testing-library/user-event/commits?author=tpict" title="Code">💻</a> <a href="https://github.com/testing-library/user-event/commits?author=tpict" title="Tests">⚠️</a></td>
<td align="center"><a href="https://hung.dev"><img src="https://avatars3.githubusercontent.com/u/8603085?v=4" width="100px;" alt=""/><br /><sub><b>Hung Viet Nguyen</b></sub></a><br /><a href="https://github.com/testing-library/user-event/issues?q=author%3Anvh95" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://nickmccurdy.com/"><img src="https://avatars0.githubusercontent.com/u/927220?v=4" width="100px;" alt=""/><br /><sub><b>Nick McCurdy</b></sub></a><br /><a href="#projectManagement-nickmccurdy" title="Project Management">📆</a> <a href="#question-nickmccurdy" title="Answering Questions">💬</a> <a href="https://github.com/testing-library/user-event/commits?author=nickmccurdy" title="Code">💻</a> <a href="https://github.com/testing-library/user-event/commits?author=nickmccurdy" title="Tests">⚠️</a></td>
<td align="center"><a href="https://nickmccurdy.com/"><img src="https://avatars0.githubusercontent.com/u/927220?v=4" width="100px;" alt=""/><br /><sub><b>Nick McCurdy</b></sub></a><br /><a href="#projectManagement-nickmccurdy" title="Project Management">📆</a> <a href="#question-nickmccurdy" title="Answering Questions">💬</a> <a href="https://github.com/testing-library/user-event/commits?author=nickmccurdy" title="Code">💻</a> <a href="https://github.com/testing-library/user-event/commits?author=nickmccurdy" title="Tests">⚠️</a> <a href="https://github.com/testing-library/user-event/commits?author=nickmccurdy" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="http://timdeschryver.dev"><img src="https://avatars1.githubusercontent.com/u/28659384?v=4" width="100px;" alt=""/><br /><sub><b>Tim Deschryver</b></sub></a><br /><a href="https://github.com/testing-library/user-event/commits?author=timdeschryver" title="Tests">⚠️</a></td>
@@ -680,6 +680,7 @@ Thanks goes to these people ([emoji key][emojis]):
</tr>
<tr>
<td align="center"><a href="https://github.com/vasilii-kovalev"><img src="https://avatars0.githubusercontent.com/u/10310491?v=4" width="100px;" alt=""/><br /><sub><b>Vasilii Kovalev</b></sub></a><br /><a href="https://github.com/testing-library/user-event/commits?author=vasilii-kovalev" title="Code">💻</a> <a href="https://github.com/testing-library/user-event/commits?author=vasilii-kovalev" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.daleseo.com"><img src="https://avatars1.githubusercontent.com/u/5466341?v=4" width="100px;" alt=""/><br /><sub><b>Dale Seo</b></sub></a><br /><a href="https://github.com/testing-library/user-event/commits?author=daleseo" title="Documentation">📖</a></td>
</tr>
</table>
11 changes: 11 additions & 0 deletions src/__tests__/helpers/utils.js
Original file line number Diff line number Diff line change
@@ -74,6 +74,17 @@ function setupListbox() {
document.body.append(wrapper)
const listbox = wrapper.querySelector('[role="listbox"]')
const options = Array.from(wrapper.querySelectorAll('[role="option"]'))

// the user is responsible for handling aria-selected on listbox options
options.forEach(el =>
el.addEventListener('click', e =>
e.target.setAttribute(
'aria-selected',
JSON.stringify(!JSON.parse(e.target.getAttribute('aria-selected'))),
),
),
)

return {
...addListeners(listbox),
listbox,
55 changes: 29 additions & 26 deletions src/__tests__/select-options.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import userEvent from '../'
import {setupSelect, addListeners, setupListbox} from './helpers/utils'
import {setupSelect, addListeners, setupListbox, setup} from './helpers/utils'

test('fires correct events', () => {
const {select, options, getEventSnapshot} = setupSelect()
@@ -22,6 +22,13 @@ test('fires correct events', () => {
select[name="select"][value="1"] - click: Left (0)
select[name="select"][value="2"] - input
select[name="select"][value="2"] - change
select[name="select"][value="2"] - pointerover
select[name="select"][value="2"] - pointerenter
select[name="select"][value="2"] - mouseover: Left (0)
select[name="select"][value="2"] - mouseenter: Left (0)
select[name="select"][value="2"] - pointerup
select[name="select"][value="2"] - mouseup: Left (0)
select[name="select"][value="2"] - click: Left (0)
`)
const [o1, o2, o3] = options
expect(o1.selected).toBe(false)
@@ -35,33 +42,22 @@ test('fires correct events on listBox select', () => {
expect(getEventSnapshot()).toMatchInlineSnapshot(`
Events fired on: ul[value="2"]
ul - pointerover
li#2[value="2"][aria-selected=false] - pointerover
ul - pointerenter
ul - mouseover: Left (0)
li#2[value="2"][aria-selected=false] - mouseover: Left (0)
ul - mouseenter: Left (0)
ul - pointermove
ul - mousemove: Left (0)
ul - pointerdown
ul - mousedown: Left (0)
ul - pointerup
ul - mouseup: Left (0)
ul - click: Left (0)
li#2[value="2"][aria-selected=true] - pointerover
ul[value="2"] - pointerenter
li#2[value="2"][aria-selected=true] - mouseover: Left (0)
ul[value="2"] - mouseenter: Left (0)
li#2[value="2"][aria-selected=true] - pointermove
li#2[value="2"][aria-selected=true] - mousemove: Left (0)
li#2[value="2"][aria-selected=true] - pointerover
ul[value="2"] - pointerenter
li#2[value="2"][aria-selected=true] - mouseover: Left (0)
ul[value="2"] - mouseenter: Left (0)
li#2[value="2"][aria-selected=true] - pointermove
li#2[value="2"][aria-selected=true] - mousemove: Left (0)
li#2[value="2"][aria-selected=true] - pointerdown
li#2[value="2"][aria-selected=true] - mousedown: Left (0)
li#2[value="2"][aria-selected=true] - pointerup
li#2[value="2"][aria-selected=true] - mouseup: Left (0)
li#2[value="2"][aria-selected=false] - pointermove
li#2[value="2"][aria-selected=false] - mousemove: Left (0)
li#2[value="2"][aria-selected=false] - pointerover
ul - pointerenter
li#2[value="2"][aria-selected=false] - mouseover: Left (0)
ul - mouseenter: Left (0)
li#2[value="2"][aria-selected=false] - pointermove
li#2[value="2"][aria-selected=false] - mousemove: Left (0)
li#2[value="2"][aria-selected=false] - pointerdown
li#2[value="2"][aria-selected=false] - mousedown: Left (0)
li#2[value="2"][aria-selected=false] - pointerup
li#2[value="2"][aria-selected=false] - mouseup: Left (0)
li#2[value="2"][aria-selected=true] - click: Left (0)
li#2[value="2"][aria-selected=true] - pointermove
li#2[value="2"][aria-selected=true] - mousemove: Left (0)
@@ -150,6 +146,13 @@ test('a previously focused input gets blurred', () => {
`)
})

test('throws an error if elements is neither select nor listbox', () => {
const {element} = setup(`<ul><li role='option'>foo</li></ul>`)
expect(() => userEvent.selectOptions(element, ['foo'])).toThrowError(
/neither select nor listbox/i,
)
})

test('throws an error one selected option does not match', () => {
const {select} = setupSelect({multiple: true})
expect(() =>
91 changes: 54 additions & 37 deletions src/select-options.js
Original file line number Diff line number Diff line change
@@ -36,53 +36,70 @@ function selectOptionsBase(newValue, select, values, init) {

if (select.disabled || !selectedOptions.length) return

if (select.multiple) {
for (const option of selectedOptions) {
// events fired for multiple select are weird. Can't use hover...
fireEvent.pointerOver(option, init)
if (select instanceof HTMLSelectElement) {
if (select.multiple) {
for (const option of selectedOptions) {
// events fired for multiple select are weird. Can't use hover...
fireEvent.pointerOver(option, init)
fireEvent.pointerEnter(select, init)
fireEvent.mouseOver(option)
fireEvent.mouseEnter(select)
fireEvent.pointerMove(option, init)
fireEvent.mouseMove(option, init)
fireEvent.pointerDown(option, init)
fireEvent.mouseDown(option, init)
focus(select, init)
fireEvent.pointerUp(option, init)
fireEvent.mouseUp(option, init)
selectOption(option)
fireEvent.click(option, init)
}
} else if (selectedOptions.length === 1) {
// the click to open the select options
click(select, init)

selectOption(selectedOptions[0])

// the browser triggers another click event on the select for the click on the option
// this second click has no 'down' phase
fireEvent.pointerOver(select, init)
fireEvent.pointerEnter(select, init)
fireEvent.mouseOver(option)
fireEvent.mouseOver(select)
fireEvent.mouseEnter(select)
fireEvent.pointerMove(option, init)
fireEvent.mouseMove(option, init)
fireEvent.pointerDown(option, init)
fireEvent.mouseDown(option, init)
focus(select, init)
fireEvent.pointerUp(option, init)
fireEvent.mouseUp(option, init)
selectOption(option)
fireEvent.click(option, init)
fireEvent.pointerUp(select, init)
fireEvent.mouseUp(select, init)
fireEvent.click(select, init)
} else {
throw getConfig().getElementError(
`Cannot select multiple options on a non-multiple select`,
select,
)
}
} else if (selectedOptions.length === 1) {
click(select, init)
selectOption(selectedOptions[0])
} else if (select.getAttribute('role') === 'listbox') {
selectedOptions.forEach(option => {
hover(option, init)
click(option, init)
unhover(option, init)
})
} else {
throw getConfig().getElementError(
`Cannot select multiple options on a non-multiple select`,
`Cannot select options on elements that are neither select nor listbox elements`,
select,
)
}

function selectOption(option) {
if (option.getAttribute('role') === 'option') {
option?.setAttribute?.('aria-selected', newValue)

hover(option, init)
click(option, init)
unhover(option, init)
} else {
option.selected = newValue
fireEvent(
select,
createEvent('input', select, {
bubbles: true,
cancelable: false,
composed: true,
...init,
}),
)
fireEvent.change(select, init)
}
option.selected = newValue
fireEvent(
select,
createEvent('input', select, {
bubbles: true,
cancelable: false,
composed: true,
...init,
}),
)
fireEvent.change(select, init)
}
}