From 6759c4a998db9cb35f2a787f1af6347cbec95be6 Mon Sep 17 00:00:00 2001 From: Ben Styles Date: Mon, 28 Dec 2020 11:25:07 +0100 Subject: [PATCH 1/4] Support 'Enter' key press on links --- src/utils.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils.js b/src/utils.js index 96578020..fc46985a 100644 --- a/src/utils.js +++ b/src/utils.js @@ -288,6 +288,7 @@ const CLICKABLE_INPUT_TYPES = [ function isClickable(element) { return ( element.tagName === 'BUTTON' || + (element.tagName === 'A' && element.href) || (isInstanceOfElement(element, 'HTMLInputElement') && CLICKABLE_INPUT_TYPES.includes(element.type)) ) From da153f6830e07f09e9fe92d08b1d5c55f10e7f90 Mon Sep 17 00:00:00 2001 From: Ben Styles Date: Mon, 28 Dec 2020 10:56:25 +0000 Subject: [PATCH 2/4] Add tests --- src/__tests__/type.js | 165 +++++++++++++++++++++++------------------- 1 file changed, 92 insertions(+), 73 deletions(-) diff --git a/src/__tests__/type.js b/src/__tests__/type.js index 18fb97d5..9940e78a 100644 --- a/src/__tests__/type.js +++ b/src/__tests__/type.js @@ -1121,43 +1121,43 @@ test('can type into an input with type `time`', () => { const {element, getEventSnapshot} = setup('') 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') }) @@ -1165,40 +1165,40 @@ test('can type into an input with type `time` without ":"', () => { const {element, getEventSnapshot} = setup('') 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') }) @@ -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) @@ -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) @@ -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('link') + + 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) + `) +}) From 9864966f2880338e78e7c586bb6bed8c9dc9b67f Mon Sep 17 00:00:00 2001 From: Ben Styles Date: Thu, 11 Feb 2021 20:33:47 +0100 Subject: [PATCH 3/4] Feedback --- src/type.js | 12 ++++++++---- src/utils.js | 5 ++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/type.js b/src/type.js index 71fdf1cd..57fd4f00 100644 --- a/src/type.js +++ b/src/type.js @@ -8,7 +8,7 @@ import { getActiveElement, calculateNewValue, setSelectionRangeIfNecessary, - isClickable, + isClickableInput, isValidDateValue, getSelectionRange, getValue, @@ -321,7 +321,7 @@ function fireInputEventIfNeeded({ const prevValue = getValue(currentElement()) if ( !currentElement().readOnly && - !isClickable(currentElement()) && + !isClickableInput(currentElement()) && newValue !== prevValue ) { if (isContentEditable(currentElement())) { @@ -583,7 +583,11 @@ function handleEnter({currentElement, eventOverrides}) { }) if (keyPressDefaultNotPrevented) { - if (isClickable(currentElement())) { + if ( + isClickableInput(currentElement()) || + // Links with href handle Enter the same as a click + (currentElement().tagName === 'A' && currentElement().href) + ) { fireEvent.click(currentElement(), { ...eventOverrides, }) @@ -712,7 +716,7 @@ function handleSelectall({currentElement}) { } function handleSpace(context) { - if (isClickable(context.currentElement())) { + if (isClickableInput(context.currentElement())) { handleSpaceOnClickable(context) return } diff --git a/src/utils.js b/src/utils.js index fc46985a..604c17c8 100644 --- a/src/utils.js +++ b/src/utils.js @@ -285,10 +285,9 @@ const CLICKABLE_INPUT_TYPES = [ 'submit', ] -function isClickable(element) { +function isClickableInput(element) { return ( element.tagName === 'BUTTON' || - (element.tagName === 'A' && element.href) || (isInstanceOfElement(element, 'HTMLInputElement') && CLICKABLE_INPUT_TYPES.includes(element.type)) ) @@ -354,7 +353,7 @@ function isValidInputTimeValue(element, timeValue) { export { FOCUSABLE_SELECTOR, isFocusable, - isClickable, + isClickableInput, getMouseEventOptions, isLabelWithInternallyDisabledControl, getActiveElement, From 6109baf16ed2cbbbb26bbd409116cae6e8fdf523 Mon Sep 17 00:00:00 2001 From: Ben Styles Date: Fri, 12 Feb 2021 09:40:29 +0100 Subject: [PATCH 4/4] Feedback --- src/type.js | 6 ++++-- src/utils.js | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/type.js b/src/type.js index 57fd4f00..125c1968 100644 --- a/src/type.js +++ b/src/type.js @@ -15,6 +15,7 @@ import { isContentEditable, isValidInputTimeValue, buildTimeValue, + isInstanceOfElement, } from './utils' import {click} from './click' import {navigationKey} from './keys/navigation-key' @@ -585,8 +586,9 @@ function handleEnter({currentElement, eventOverrides}) { if (keyPressDefaultNotPrevented) { if ( isClickableInput(currentElement()) || - // Links with href handle Enter the same as a click - (currentElement().tagName === 'A' && currentElement().href) + // Links with href defined should handle Enter the same as a click + (isInstanceOfElement(currentElement(), 'HTMLAnchorElement') && + currentElement().href) ) { fireEvent.click(currentElement(), { ...eventOverrides, diff --git a/src/utils.js b/src/utils.js index 604c17c8..7b96a086 100644 --- a/src/utils.js +++ b/src/utils.js @@ -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 {