Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(type): allow typing negative numbers #338

Merged
merged 1 commit into from Jun 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/__tests__/type.js
Expand Up @@ -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('<input type="number" />')
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('<input type="number" />')
const negativeNumber = '-{backspace}3'
await userEvent.type(element, negativeNumber)
expect(element).toHaveValue(3)
})

test('-a3', async () => {
const {element} = setup('<input type="number" />')
const negativeNumber = '-a3'
await userEvent.type(element, negativeNumber)
expect(element).toHaveValue(-3)
})

test('typing an invalid input value', async () => {
const {element} = setup('<input type="number" />')
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)
})
40 changes: 34 additions & 6 deletions src/type.js
Expand Up @@ -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
}
}
}
Expand All @@ -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(), {
Expand All @@ -251,6 +254,8 @@ async function typeImpl(

setSelectionRange({newValue, newSelectionStart})
}

return {prevValue}
}

// yes, calculateNewBackspaceValue and calculateNewValue look extremely similar
Expand Down Expand Up @@ -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,
Expand All @@ -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 === '-'
}
}
}
}

Expand All @@ -371,6 +397,8 @@ async function typeImpl(
which: keyCode,
...eventOverrides,
})

return {prevWasMinus: nextPrevWasMinus}
}

function modifier({name, key, keyCode, modifierProperty}) {
Expand Down