Skip to content

Commit

Permalink
fix: click links on 'enter' key press (#534)
Browse files Browse the repository at this point in the history
Trigger click event for userEvent.type('{enter}') on HTMLAnchorElements.

Co-authored-by: Philipp Fritsche <ph.fritsche@gmail.com>
  • Loading branch information
benadamstyles and ph-fritsche committed Feb 13, 2021
1 parent 217b487 commit 8a34d0b
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 81 deletions.
165 changes: 92 additions & 73 deletions src/__tests__/type.js
Original file line number Diff line number Diff line change
Expand Up @@ -1121,84 +1121,84 @@ test('can type into an input with type `time`', () => {
const {element, getEventSnapshot} = setup('<input type="time" />')
userEvent.type(element, '01:05')
expect(getEventSnapshot()).toMatchInlineSnapshot(`
Events fired on: input[value="01:05"]
input[value=""] - pointerover
input[value=""] - pointerenter
input[value=""] - mouseover: Left (0)
input[value=""] - mouseenter: Left (0)
input[value=""] - pointermove
input[value=""] - mousemove: Left (0)
input[value=""] - pointerdown
input[value=""] - mousedown: Left (0)
input[value=""] - focus
input[value=""] - focusin
input[value=""] - pointerup
input[value=""] - mouseup: Left (0)
input[value=""] - click: Left (0)
input[value=""] - keydown: 0 (48)
input[value=""] - keypress: 0 (48)
input[value=""] - keyup: 0 (48)
input[value=""] - keydown: 1 (49)
input[value=""] - keypress: 1 (49)
input[value=""] - keyup: 1 (49)
input[value=""] - keydown: : (58)
input[value=""] - keypress: : (58)
input[value=""] - keyup: : (58)
input[value=""] - keydown: 0 (48)
input[value=""] - keypress: 0 (48)
input[value="01:00"] - input
"{CURSOR}" -> "{CURSOR}01:00"
input[value="01:00"] - change
input[value="01:00"] - keyup: 0 (48)
input[value="01:00"] - keydown: 5 (53)
input[value="01:00"] - keypress: 5 (53)
input[value="01:05"] - input
"{CURSOR}01:00" -> "{CURSOR}01:05"
input[value="01:05"] - change
input[value="01:05"] - keyup: 5 (53)
`)
Events fired on: input[value="01:05"]
input[value=""] - pointerover
input[value=""] - pointerenter
input[value=""] - mouseover: Left (0)
input[value=""] - mouseenter: Left (0)
input[value=""] - pointermove
input[value=""] - mousemove: Left (0)
input[value=""] - pointerdown
input[value=""] - mousedown: Left (0)
input[value=""] - focus
input[value=""] - focusin
input[value=""] - pointerup
input[value=""] - mouseup: Left (0)
input[value=""] - click: Left (0)
input[value=""] - keydown: 0 (48)
input[value=""] - keypress: 0 (48)
input[value=""] - keyup: 0 (48)
input[value=""] - keydown: 1 (49)
input[value=""] - keypress: 1 (49)
input[value=""] - keyup: 1 (49)
input[value=""] - keydown: : (58)
input[value=""] - keypress: : (58)
input[value=""] - keyup: : (58)
input[value=""] - keydown: 0 (48)
input[value=""] - keypress: 0 (48)
input[value="01:00"] - input
"{CURSOR}" -> "{CURSOR}01:00"
input[value="01:00"] - change
input[value="01:00"] - keyup: 0 (48)
input[value="01:00"] - keydown: 5 (53)
input[value="01:00"] - keypress: 5 (53)
input[value="01:05"] - input
"{CURSOR}01:00" -> "{CURSOR}01:05"
input[value="01:05"] - change
input[value="01:05"] - keyup: 5 (53)
`)
expect(element).toHaveValue('01:05')
})

test('can type into an input with type `time` without ":"', () => {
const {element, getEventSnapshot} = setup('<input type="time" />')
userEvent.type(element, '0105')
expect(getEventSnapshot()).toMatchInlineSnapshot(`
Events fired on: input[value="01:05"]
input[value=""] - pointerover
input[value=""] - pointerenter
input[value=""] - mouseover: Left (0)
input[value=""] - mouseenter: Left (0)
input[value=""] - pointermove
input[value=""] - mousemove: Left (0)
input[value=""] - pointerdown
input[value=""] - mousedown: Left (0)
input[value=""] - focus
input[value=""] - focusin
input[value=""] - pointerup
input[value=""] - mouseup: Left (0)
input[value=""] - click: Left (0)
input[value=""] - keydown: 0 (48)
input[value=""] - keypress: 0 (48)
input[value=""] - keyup: 0 (48)
input[value=""] - keydown: 1 (49)
input[value=""] - keypress: 1 (49)
input[value=""] - keyup: 1 (49)
input[value=""] - keydown: 0 (48)
input[value=""] - keypress: 0 (48)
input[value="01:00"] - input
"{CURSOR}" -> "{CURSOR}01:00"
input[value="01:00"] - change
input[value="01:00"] - keyup: 0 (48)
input[value="01:00"] - keydown: 5 (53)
input[value="01:00"] - keypress: 5 (53)
input[value="01:05"] - input
"{CURSOR}01:00" -> "{CURSOR}01:05"
input[value="01:05"] - change
input[value="01:05"] - keyup: 5 (53)
`)
Events fired on: input[value="01:05"]
input[value=""] - pointerover
input[value=""] - pointerenter
input[value=""] - mouseover: Left (0)
input[value=""] - mouseenter: Left (0)
input[value=""] - pointermove
input[value=""] - mousemove: Left (0)
input[value=""] - pointerdown
input[value=""] - mousedown: Left (0)
input[value=""] - focus
input[value=""] - focusin
input[value=""] - pointerup
input[value=""] - mouseup: Left (0)
input[value=""] - click: Left (0)
input[value=""] - keydown: 0 (48)
input[value=""] - keypress: 0 (48)
input[value=""] - keyup: 0 (48)
input[value=""] - keydown: 1 (49)
input[value=""] - keypress: 1 (49)
input[value=""] - keyup: 1 (49)
input[value=""] - keydown: 0 (48)
input[value=""] - keypress: 0 (48)
input[value="01:00"] - input
"{CURSOR}" -> "{CURSOR}01:00"
input[value="01:00"] - change
input[value="01:00"] - keyup: 0 (48)
input[value="01:00"] - keydown: 5 (53)
input[value="01:00"] - keypress: 5 (53)
input[value="01:05"] - input
"{CURSOR}01:00" -> "{CURSOR}01:05"
input[value="01:05"] - change
input[value="01:05"] - keyup: 5 (53)
`)
expect(element).toHaveValue('01:05')
})

Expand All @@ -1208,7 +1208,7 @@ test('can type more a number higher than 60 minutes into an input `time` and the

expect(getEventSnapshot()).toMatchInlineSnapshot(`
Events fired on: input[value="23:59"]
input[value=""] - pointerover
input[value=""] - pointerenter
input[value=""] - mouseover: Left (0)
Expand Down Expand Up @@ -1254,7 +1254,7 @@ test('can type letters into an input `time` and they are ignored', () => {

expect(getEventSnapshot()).toMatchInlineSnapshot(`
Events fired on: input[value="16:36"]
input[value=""] - pointerover
input[value=""] - pointerenter
input[value=""] - mouseover: Left (0)
Expand Down Expand Up @@ -1495,3 +1495,22 @@ test('{arrowup} fires keyup/keydown events', () => {
input[value=""] - keyup: ArrowUp (38)
`)
})

test('{enter} fires click on links', () => {
const {element, getEventSnapshot} = setup('<a href="#">link</a>')

element?.focus()

userEvent.type(element, '{enter}', {skipClick: true})

expect(getEventSnapshot()).toMatchInlineSnapshot(`
Events fired on: a
a - focus
a - focusin
a - keydown: Enter (13)
a - keypress: Enter (13)
a - click: Left (0)
a - keyup: Enter (13)
`)
})
14 changes: 10 additions & 4 deletions src/type.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import {
getActiveElement,
calculateNewValue,
setSelectionRangeIfNecessary,
isClickable,
isClickableInput,
isValidDateValue,
getSelectionRange,
getValue,
isContentEditable,
isValidInputTimeValue,
buildTimeValue,
isInstanceOfElement,
} from './utils'
import {click} from './click'
import {navigationKey} from './keys/navigation-key'
Expand Down Expand Up @@ -321,7 +322,7 @@ function fireInputEventIfNeeded({
const prevValue = getValue(currentElement())
if (
!currentElement().readOnly &&
!isClickable(currentElement()) &&
!isClickableInput(currentElement()) &&
newValue !== prevValue
) {
if (isContentEditable(currentElement())) {
Expand Down Expand Up @@ -583,7 +584,12 @@ function handleEnter({currentElement, eventOverrides}) {
})

if (keyPressDefaultNotPrevented) {
if (isClickable(currentElement())) {
if (
isClickableInput(currentElement()) ||
// Links with href defined should handle Enter the same as a click
(isInstanceOfElement(currentElement(), 'HTMLAnchorElement') &&
currentElement().href)
) {
fireEvent.click(currentElement(), {
...eventOverrides,
})
Expand Down Expand Up @@ -712,7 +718,7 @@ function handleSelectall({currentElement}) {
}

function handleSpace(context) {
if (isClickable(context.currentElement())) {
if (isClickableInput(context.currentElement())) {
handleSpaceOnClickable(context)
return
}
Expand Down
8 changes: 4 additions & 4 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {getWindowFromNode} from '@testing-library/dom/dist/helpers'
/**
* Check if an element is of a given type.
*
* @param Element The element to test
* @param string Constructor name. E.g. 'HTMLSelectElement'
* @param {Element} element The element to test
* @param {string} elementType Constructor name. E.g. 'HTMLSelectElement'
*/
function isInstanceOfElement(element, elementType) {
try {
Expand Down Expand Up @@ -285,7 +285,7 @@ const CLICKABLE_INPUT_TYPES = [
'submit',
]

function isClickable(element) {
function isClickableInput(element) {
return (
element.tagName === 'BUTTON' ||
(isInstanceOfElement(element, 'HTMLInputElement') &&
Expand Down Expand Up @@ -353,7 +353,7 @@ function isValidInputTimeValue(element, timeValue) {
export {
FOCUSABLE_SELECTOR,
isFocusable,
isClickable,
isClickableInput,
getMouseEventOptions,
isLabelWithInternallyDisabledControl,
getActiveElement,
Expand Down

0 comments on commit 8a34d0b

Please sign in to comment.