diff --git a/src/__tests__/select-focus.js b/src/__tests__/select-focus.js new file mode 100644 index 00000000..48cd05c6 --- /dev/null +++ b/src/__tests__/select-focus.js @@ -0,0 +1,65 @@ +import * as React from 'react' +import {render, fireEvent, screen} from '../' + +test.each(['input', 'textarea'])( + 'fireEvent.select flushes automatic %s focus and previous blur updates', + elementType => { + function Example() { + const [focused, setFocused] = React.useState(false) + const [blurred, setBlurred] = React.useState(false) + return ( + <> + setBlurred(true)} /> + {React.createElement(elementType, { + 'aria-label': 'selection', + onFocus: () => setFocused(true), + 'data-focused': focused, + 'data-blurred': blurred, + })} + + ) + } + render() + const previous = screen.getByRole('textbox', {name: 'previous'}) + previous.focus() + const input = screen.getByRole('textbox', {name: 'selection'}) + fireEvent.select(input) + expect(input).toHaveFocus() + expect(input).toHaveAttribute('data-focused', 'true') + expect(input).toHaveAttribute('data-blurred', 'true') + }, +) + +test('fireEvent.select preserves native focus, selection and key event ordering', () => { + const events = [] + const handleSelect = jest.fn() + render() + const input = screen.getByRole('textbox', {name: 'selection'}) + const focusSpy = jest.fn(() => events.push('focus')) + input.addEventListener('select', () => events.push('select')) + input.addEventListener('focus', focusSpy) + input.addEventListener('keyup', () => events.push('keyup')) + fireEvent.select(input) + expect(events).toEqual(['select', 'focus', 'keyup']) + expect(handleSelect).toHaveBeenCalledTimes(1) + fireEvent.select(input) + expect(focusSpy).toHaveBeenCalledTimes(1) +}) + +test('fireEvent.select flushes updates when the input is already focused', () => { + function Example() { + const [selected, setSelected] = React.useState(false) + return ( + setSelected(true)} + data-selected={selected} + /> + ) + } + render() + const input = screen.getByRole('textbox', {name: 'selection'}) + input.focus() + fireEvent.select(input) + expect(input).toHaveAttribute('data-selected', 'true') +}) diff --git a/src/fire-event.js b/src/fire-event.js index cb790c7f..cc95a2e4 100644 --- a/src/fire-event.js +++ b/src/fire-event.js @@ -1,4 +1,4 @@ -import {fireEvent as dtlFireEvent} from '@testing-library/dom' +import {fireEvent as dtlFireEvent, getConfig} from '@testing-library/dom' // react-testing-library's version of fireEvent will call // dom-testing-library's version of fireEvent. The reason @@ -39,7 +39,9 @@ const select = fireEvent.select fireEvent.select = (node, init) => { select(node, init) // React tracks this event only on focused inputs - node.focus() + getConfig().eventWrapper(() => { + node.focus() + }) // React creates this event when one of the following native events happens // - contextMenu