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
userEvent.type doesn't work well when a value is formatted after the onChange is fired #369
Comments
Have you tried wrapping your |
That was my first thought but seeing as the test fails because the value is reversed rather than not having a value, i was able to rule that out. |
Ah sorry, I think I misunderstood the issue. Have you tried |
Paste did avoid the bug, but that would mean I'm not testing the same thing right? Or is it close enough to typing that its still a valid test for how the component responds to a user typing? |
I'm 90% certain that your test as written above should pass and this is a bug, probably related to: #346 Reproducing this would probably be a matter of adding another test here: user-event/src/__tests__/type.js Line 708 in f4eae9c
I'm not sure about the solution, but that's where I'd start first to know for certain that this is a user-event bug. I don't have the bandwidth to work on this myself unfortunately. |
To be clear, I wasn't suggesting to actually keep |
I'll pull down the repo and see if I can figure out what's going on. |
After digging into this some, here is what I found: The assumed new value and next location to insert text is calculated by the Lines 95 to 135 in f4eae9c
Lines 158 to 161 in f4eae9c
I'm not proposing it as a change, but by forcing Line 163 in f4eae9c
setSelectionRange({ newValue, newSelectionStart: currentElement().value.length}); Edit: I should note, the above change makes 7 tests fail, 4 of which are snapshots. |
Hm, that's interesting. If the snapshot changes look okay to you feel free to start a PR and we can hopefully figure out the other failures. |
Well, the tests are failing because this prevents any scenario of inserting text in the middle of the input. I'll probably take a crack at implementing something that works for both scenarios sometime in the next couple days and open a PR if I get something working. |
The problem I ran into is I'm not sure how to convert my react test into one for this library (since its framework agnostic), so if anyone as ideas on that it would be appreciated. |
You're probably looking for the user-event/src/__tests__/paste.js Lines 1 to 19 in f4eae9c
|
Thanks, that put me in the right direction and I've got a test written locally now. I tried to replicate what I had done in my react test with formatting the value on change but it doesn't seem to be firing a change event. When I format the value on the input event, it works fine. So I'm stumped now. The test I wrote in test('typing a value that is formatted on change', () => {
function formatPhone(unformattedPhone) {
if (unformattedPhone == null) return ''
// Remove all formatting from input
let matchedValue = unformattedPhone.replace(/[^0-9]*/g, '').match(/\d*/g)
const cleanedValue = matchedValue ? matchedValue.join('') : ''
// group between areaCode, firstGroup, and secondGroup
matchedValue = cleanedValue.match(/(\d{0,3})(\d{0,3})(\d{0,4})/)
const [areaCode, firstGroup, secondGroup] = matchedValue
? matchedValue.slice(1)
: ['', '', '']
// initialize phoneNumber
let phoneNumber = ''
// begin with '(' after any digit input
if (areaCode !== '') phoneNumber = `(${areaCode}`
// end area code with ')' if there are more than 3 digits (at least 1 digit in firstGroup)
if (firstGroup !== '') phoneNumber = `${phoneNumber}) ${firstGroup}`
// add '-' if there are more than 6 digits (at least 1 digit in secondGroup)
if (secondGroup !== '') phoneNumber = `${phoneNumber}-${secondGroup}`
return phoneNumber
}
const {element} = setup('<input />', {
eventHandlers: {
input: e => {
console.log('Input event fired!')
e.target.value = formatPhone(e.target.value)
},
change: e => {
console.log('Change event fired!')
e.target.value = formatPhone(e.target.value)
},
},
})
userEvent.type(element, '1234567890')
expect(element).toHaveValue('(123) 456-7890')
}) |
I'm not sure 😬 you may have to do a little more digging. |
So I did a little more digging and made a lot of changes. Which ultimately helped me understand the problem and reasons behind why the code was structured how it was. I then learned that the issue was ultimately how the browser responded to a programattic change and how userEvent.type responded to it. I learned what the intentions were behind the following code and that the problem was if the value was changed programattically, the selection would never update from it's initial value. Lines 64 to 70 in 44b9011
Therefore, I have opened a PR recommending updating it to: Lines 64 to 77 in e6261e0
|
🎉 This issue has been resolved in version 12.0.4 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
I am experiencing this issue with 13.5.0, had to downgrade to 12.0.4 to solve it. |
@terraelise @mickcastle Please don't add noise to the issue board. File an issue with a reproducible example. Also try upgrading to the latest version. |
@testing-library/user-event
version: 12.0.2@testing-library/react
's render function, so jsdom?React component logic
Format function
Tests
What you did:
I have a field where we collect a phone number and format it as the user types. To do so, we format the value onChange before we call the
setState
function from theuseState
hook`.What happened:
When attempting to test this by calling
userEvent.type(..., '1234567890')
the value was being set to (098) 765-4321 instead of (123) 456-7890.Reproduction repository:
https://codesandbox.io/s/usereventtype-reverses-value-mgi2n?file=/src/App.spec.tsx
Problem description:
This was extremely confusing at first and led me to do a lot of digging in the source code of
userEvent.type(...)
. Once I did so for a while I came across the idea that it may be an issue with the selected location returning to the beginning of the input. I think it may have something to do with the newValue being different than it expected.Suggested solution:
I don't know that I have a suggested solution, as I don't have a complete grasp over the source code and the cause of the specific problem. However, I'm more than happy to help discuss options and take a crack at implementing a fix with some guidance.
The text was updated successfully, but these errors were encountered: