diff --git a/src/__tests__/type.js b/src/__tests__/type.js
index 66dbf67b..26652f36 100644
--- a/src/__tests__/type.js
+++ b/src/__tests__/type.js
@@ -1,4 +1,4 @@
-import React from 'react'
+import React, {Fragment} from 'react'
import {render, screen} from '@testing-library/react'
import userEvent from '../../src'
@@ -256,3 +256,63 @@ test.each(['input', 'textarea'])(
expect(onKeyUp).not.toHaveBeenCalled()
},
)
+
+test('should fire events on the currently focused element', async () => {
+ const changeFocusLimit = 7
+ const onKeyDown = jest.fn(event => {
+ if (event.target.value.length === changeFocusLimit) {
+ screen.getByTestId('input2').focus()
+ }
+ })
+
+ render(
+
+
+
+ ,
+ )
+
+ const text = 'Hello, world!'
+
+ const input1 = screen.getByTestId('input1')
+ const input2 = screen.getByTestId('input2')
+
+ await userEvent.type(input1, text)
+
+ expect(input1).toHaveValue(text.slice(0, changeFocusLimit))
+ expect(input2).toHaveValue(text.slice(changeFocusLimit))
+ expect(input2).toHaveFocus()
+})
+
+test('should enter text up to maxLength of the current element if provided', async () => {
+ const changeFocusLimit = 7
+ const input2MaxLength = 2
+
+ const onKeyDown = jest.fn(event => {
+ if (event.target.value.length === changeFocusLimit) {
+ screen.getByTestId('input2').focus()
+ }
+ })
+
+ render(
+ <>
+
+
+ >,
+ )
+
+ const text = 'Hello, world!'
+ const input2ExpectedValue = text.slice(
+ changeFocusLimit,
+ changeFocusLimit + input2MaxLength,
+ )
+
+ const input1 = screen.getByTestId('input')
+ const input2 = screen.getByTestId('input2')
+
+ await userEvent.type(input1, text)
+
+ expect(input1).toHaveValue(text.slice(0, changeFocusLimit))
+ expect(input2).toHaveValue(input2ExpectedValue)
+ expect(input2).toHaveFocus()
+})
diff --git a/src/index.js b/src/index.js
index a0920dd4..b1a8a1bf 100644
--- a/src/index.js
+++ b/src/index.js
@@ -334,21 +334,30 @@ async function type(...args) {
async function typeImpl(element, text, {allAtOnce = false, delay} = {}) {
if (element.disabled) return
- const previousText = element.value
- const computedText =
- element.maxLength > 0
- ? text.slice(0, Math.max(element.maxLength - previousText.length, 0))
+ element.focus()
+
+ // The focussed element could change between each event, so get the currently active element each time
+ const currentElement = () => element.ownerDocument.activeElement
+ const currentValue = () => element.ownerDocument.activeElement.value
+
+ const computeText = () =>
+ currentElement().maxLength > 0
+ ? text.slice(
+ 0,
+ Math.max(currentElement().maxLength - currentValue().length, 0),
+ )
: text
if (allAtOnce) {
if (!element.readOnly) {
+ const previousText = element.value
+
fireEvent.input(element, {
- target: {value: previousText + computedText},
+ target: {value: previousText + computeText()},
})
}
} else {
- let actuallyTyped = previousText
for (let index = 0; index < text.length; index++) {
const char = text[index]
const key = char // TODO: check if this also valid for characters with diacritic markers e.g. úé etc
@@ -357,28 +366,28 @@ async function typeImpl(element, text, {allAtOnce = false, delay} = {}) {
// eslint-disable-next-line no-await-in-loop
if (delay > 0) await wait(delay)
- const downEvent = fireEvent.keyDown(element, {
+ if (currentElement().disabled) return
+
+ const downEvent = fireEvent.keyDown(currentElement(), {
key,
keyCode,
which: keyCode,
})
if (downEvent) {
- const pressEvent = fireEvent.keyPress(element, {
+ const pressEvent = fireEvent.keyPress(currentElement(), {
key,
keyCode,
charCode: keyCode,
})
- const isTextPastThreshold =
- (actuallyTyped + key).length > (previousText + computedText).length
+ const isTextPastThreshold = !computeText().length
if (pressEvent && !isTextPastThreshold) {
- actuallyTyped += key
if (!element.readOnly) {
- fireEvent.input(element, {
+ fireEvent.input(currentElement(), {
target: {
- value: actuallyTyped,
+ value: currentValue() + key,
},
bubbles: true,
cancelable: true,
@@ -387,7 +396,7 @@ async function typeImpl(element, text, {allAtOnce = false, delay} = {}) {
}
}
- fireEvent.keyUp(element, {
+ fireEvent.keyUp(currentElement(), {
key,
keyCode,
which: keyCode,