diff --git a/src/__tests__/type.js b/src/__tests__/type.js
index 8b57efe5..316abf62 100644
--- a/src/__tests__/type.js
+++ b/src/__tests__/type.js
@@ -571,3 +571,55 @@ test('can type into an input with type `email`', async () => {
await userEvent.type(element, email)
expect(element).toHaveValue(email)
})
+
+// https://github.com/testing-library/user-event/issues/336
+test('can type "-" into number inputs', async () => {
+ const {element, getEventCalls} = setup('')
+ const negativeNumber = '-3'
+ await userEvent.type(element, negativeNumber)
+ expect(element).toHaveValue(-3)
+
+ // NOTE: the input event here does not actually change the value thanks to
+ // weirdness with browsers. Then the second input event inserts both the
+ // - and the 3. /me rolls eyes
+ expect(getEventCalls()).toMatchInlineSnapshot(`
+ focus
+ keydown: - (45)
+ keypress: - (45)
+ input: "{CURSOR}" -> ""
+ keyup: - (45)
+ keydown: 3 (51)
+ keypress: 3 (51)
+ input: "{CURSOR}" -> "-3"
+ keyup: 3 (51)
+ `)
+})
+
+test('-{backspace}3', async () => {
+ const {element} = setup('')
+ const negativeNumber = '-{backspace}3'
+ await userEvent.type(element, negativeNumber)
+ expect(element).toHaveValue(3)
+})
+
+test('-a3', async () => {
+ const {element} = setup('')
+ const negativeNumber = '-a3'
+ await userEvent.type(element, negativeNumber)
+ expect(element).toHaveValue(-3)
+})
+
+test('typing an invalid input value', async () => {
+ const {element} = setup('')
+ await userEvent.type(element, '3-3')
+
+ // TODO: fix this bug
+ // THIS IS A BUG! It should be expect(element.value).toBe('')
+ expect(element).toHaveValue(-3)
+
+ // THIS IS A LIMITATION OF THE BROWSER
+ // It is impossible to programmatically set an input
+ // value to an invlid value. Not sure how to work around this
+ // but the badInput should actually be "true" if the user types "3-3"
+ expect(element.validity.badInput).toBe(false)
+})
diff --git a/src/type.js b/src/type.js
index 6f014cea..7c472b86 100644
--- a/src/type.js
+++ b/src/type.js
@@ -227,11 +227,13 @@ async function typeImpl(
}
}
const eventOverrides = {}
+ let prevWasMinus
for (const callback of eventCallbacks) {
if (delay > 0) await wait(delay)
if (!currentElement().disabled) {
- const returnValue = await callback({eventOverrides})
+ const returnValue = await callback({prevWasMinus, eventOverrides})
Object.assign(eventOverrides, returnValue?.eventOverrides)
+ prevWasMinus = returnValue?.prevWasMinus
}
}
}
@@ -241,7 +243,8 @@ async function typeImpl(
newSelectionStart,
eventOverrides,
}) {
- if (!currentElement().readOnly && newValue !== currentValue()) {
+ const prevValue = currentValue()
+ if (!currentElement().readOnly && newValue !== prevValue) {
await tick()
fireEvent.input(currentElement(), {
@@ -251,6 +254,8 @@ async function typeImpl(
setSelectionRange({newValue, newSelectionStart})
}
+
+ return {prevValue}
}
// yes, calculateNewBackspaceValue and calculateNewValue look extremely similar
@@ -334,9 +339,10 @@ async function typeImpl(
}
}
- async function typeCharacter(char, {eventOverrides}) {
+ async function typeCharacter(char, {prevWasMinus = false, eventOverrides}) {
const key = char // TODO: check if this also valid for characters with diacritic markers e.g. úé etc
const keyCode = char.charCodeAt(0)
+ let nextPrevWasMinus
const keyDownDefaultNotPrevented = fireEvent.keyDown(currentElement(), {
key,
@@ -356,10 +362,30 @@ async function typeImpl(
})
if (keyPressDefaultNotPrevented) {
- await fireInputEventIfNeeded({
- ...calculateNewValue(key),
- eventOverrides,
+ const newEntry = prevWasMinus ? `-${char}` : char
+
+ const {prevValue} = await fireInputEventIfNeeded({
+ ...calculateNewValue(newEntry),
+ eventOverrides: {
+ data: key,
+ inputType: 'insertText',
+ ...eventOverrides,
+ },
})
+
+ // typing "-" into a number input will not actually update the value
+ // so for the next character we type, the value should be set to
+ // `-${newEntry}`
+ // we also preserve the prevWasMinus when the value is unchanged due
+ // to typing an invalid character (typing "-a3" results in "-3")
+ if (currentElement().type === 'number') {
+ const newValue = currentValue()
+ if (newValue === prevValue && newEntry !== '-') {
+ nextPrevWasMinus = prevWasMinus
+ } else {
+ nextPrevWasMinus = newEntry === '-'
+ }
+ }
}
}
@@ -371,6 +397,8 @@ async function typeImpl(
which: keyCode,
...eventOverrides,
})
+
+ return {prevWasMinus: nextPrevWasMinus}
}
function modifier({name, key, keyCode, modifierProperty}) {