happy-dom icon indicating copy to clipboard operation
happy-dom copied to clipboard

Version 10.1.0 breaks the `event.target.value` for blur event on date input

Open zorzysty opened this issue 1 year ago • 8 comments

Describe the bug Version 10.1.0 breaks the event.target.value for blur event on date input.

To Reproduce Steps to reproduce the behavior (tested in React)

  1. Create input of type "date"
  2. Enter some value in the input
  3. Invoke a blur event

Expected behavior event.target.value in a callback for the blur event should be the same as the actual value of the input, but it's empty instead. event.target.valueAsDate on the other hand, is null.

Additional context

  • This does not happen for inputs of type "text" nor "number", only on "date".
  • This does not happen on happy-dom v 10.0.7, but happens on every version starting from 10.1.0. Console output when running happy-dom 10.1.0: image Console output when running happy-dom 10.0.7: image
  • It's probably related to changes by @malko described here: https://github.com/capricorn86/happy-dom/issues/945.

zorzysty avatar Nov 22 '23 10:11 zorzysty

@zorzysty 01/05/1990 is not a valid value for date input, effectively it can be related to the change introduced in value sanitize. But this reflect how a real browser should treat such value. You can test on chrome and see that setting 01/05/1980 on a date input will result in blank value.

malko avatar Nov 23 '23 16:11 malko

so for me this is not a bug but the expected behavior.

malko avatar Nov 23 '23 16:11 malko

@malko 01/05/1990 is a perfectly fine value to be entered into the input of type "date" in Chrome (and other browsers) as long as your browser locale matches this date format. image

zorzysty avatar Nov 23 '23 18:11 zorzysty

Here's the important piece of information straight from MDN is this: image

zorzysty avatar Nov 23 '23 18:11 zorzysty

@zorzysty the important word in your previous message is "displayed". I'm french, with locales set to french on my chrome if I programmatically try to set the input date like this: myDateInput.value = "01/05/1980" the value will be set to an empty string with the following warning message in the console:

⚠ The specified value "01/05/1980" does not conform to the required format, "yyyy-MM-dd". 

You can try by yourself.

More info can be found here https://developer.mozilla.org/fr/docs/Web/HTML/Date_and_time_formats and here https://html.spec.whatwg.org/multipage/input.html#date-state-(type=date)

So If you are setting your value by direct assignation (ie: myInputDate.value = "01/05/1980"), I'm sorry to confirm that this is expected behavior. If not can you provide a code sample of your use case to better understand the problem. (the assignation part)

I was aware at the time of change that it could break some code and it was stated here: https://github.com/capricorn86/happy-dom/pull/974

Also console output when running happy-dom 10.0.7: image Is not conform to the specs or real browser behavior, as even if you can enter date in the "dd/MM/yyyy" format with keyboard in the UI, it should be

event.target.value 1980-05-01

That also you can test by opening a console in your browser.

malko avatar Nov 24 '23 08:11 malko

even if you can enter date in the "dd/MM/yyyy" format with keyboard in the UI, it should be event.target.value 1980-05-01

This is exactly what's not working :) I'm obviously not entering value by setting the value property on the target with JavaScript, but rather by doing await user.keyboard('01/05/1980{Tab}') with UserEvent from testing-library.

value property can only be set with the "yyyy-MM-dd" format, but when typing with keyboard in the UI I should be able to enter it in the same format as I do in real browser, so in this case 01/05/1980. It's working when I do it in Chrome and in happy-dom 10.0.7, but fails in v 10.1.0.

One more thing to note is that when I change the event to await user.keyboard('1980-01-05{Tab}'), the value property of the target is 1980-01-05, but it reality it should be invalid, considering my locale (I cannot really enter 1980-01-05 in Chrome).

zorzysty avatar Nov 24 '23 09:11 zorzysty

Here's a simple reproduction of the issue:

const handleChange = vi.fn()
const { user } = render(
  <input
    type="date"
    title="birthday"
    onBlur={(e) => handleChange(e.target.value)}
  />
)

const input = screen.getByTitle('birthday')

await user.click(input)
await waitFor(() => expect(input).toHaveFocus())

await user.keyboard('01/05/1990{Tab}')
expect(handleChange).toHaveBeenCalledWith('1990-01-05')

Running it with the en_US locale (node env variable LC_ALL=en_US.UTF-8) on 10.1.0 results in this error: image

On 10.0.7 it's not perfect either, but at least I get some value to work with: image

zorzysty avatar Nov 24 '23 09:11 zorzysty

So the problem here is more related to UI and how real browsers render the input date component. I still think that the input sanitize should not be changed, but perhaps some extra work bound to keyboard input events to mimick real browser behavior can be implemented.

In fact it is a lot of work complex, if you start your input with a number > 3 with a french locale, it will move you directly to the month section of the date so entering "991980{tab}" will result in value being 1980-09-09 with chromium based browser at least (and by the way any non number character is just ignored). You have other keyboard input sanitization rules that applies, and some of them behave differently depending on min/max values as well. So it seems complicated to implement all of them depending on each locales. This will probably require to handle the UI state separatly from the value state. Track the cursor positioning when focus is grabbed and validate final value when input is blured. Thoose rules also are vendor implementation details for which I wasn't able to find any documented specs for.

Some examples of edge cases you can find on chrome with "fr" locale setting:

await user.keyboard('01051990{Tab}') // will do the same as user.keyboard('01/05/1990{Tab}')
await user.keyboard('531980{Tab}') // value will be equal to 1980-03-05
await user.keyboard('5/-3-198{Tab}') // value will be equal to 0198-03-05

I'm also curious to see how jsdom handles such cases.

In the end I'm not official maintainer of the project and @capricorn86 should decide how he want this particular case to be handled in happy-dom.

malko avatar Nov 24 '23 13:11 malko