carbon-design-system / carbon

A design system built by IBM
https://www.carbondesignsystem.com
Apache License 2.0
7.85k stars 1.81k forks source link

[Bug]: Setting an `HTMLInputElement`'s `value` to `null` #17393

Closed s100 closed 1 month ago

s100 commented 2 months ago

Package

@carbon/react

Browser

Edge

Package version

1.65.0

React version

18.3.1

Description

During unit testing involving <FileUploaderDropContainer> using @testing-library/user-event, we see the following error:

Cannot use 'in' operator to search for 'Symbol(Displayed value in UI)' in null
TypeError: Cannot use 'in' operator to search for 'Symbol(Displayed value in UI)' in null
    at Object.isUIValue (C:\...\node_modules\@testing-library\user-event\dist\cjs\document\UI.js:7:49)
    at HTMLInputElement.interceptorImpl (C:\...\node_modules\@testing-library\user-event\dist\cjs\document\interceptor.js:40:25)
    at HTMLInputElement.intercept [as value] (C:\...\node_modules\@testing-library\user-event\dist\cjs\document\interceptor.js:23:73)
    at onClick (C:\...\node_modules\@carbon\react\lib\components\FileUploader\FileUploaderDropContainer.js:156:24)
    at HTMLUnknownElement.callCallback (C:\...\node_modules\react-dom\cjs\react-dom.development.js:4164:14)
    at ...

The cause of this is this code where we are setting evt.target.value = null.

The actual error comes from @testing-library/user-event here where they are seemingly failing to account for the possibility of the value property of an HTMLInputElement being null. However, in actuality, the value property of an <input type='file'> can't be null. It's always a string. As far as I can tell, the types check out. The fact that it's possible to manually set it to null is an artifact of testing. In reality, setting the value to null sets it to the empty string, ''.

My recommendation is that Carbon's code should be changed to evt.target.value = ''.

Reproduction/example

https://stackblitz.com/edit/github-6ae745?file=src%2FApp.jsx

Steps to reproduce

This isn't a bug I can reproduce in a web browser, it only appears during Jest testing:

/* eslint-env jest */

import { FileUploaderDropContainer } from '@carbon/react'
import { render } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import React from 'react'

describe('suite, () => {
  it('test', async () => {
    const rendered = render(
      <FileUploaderDropContainer
        labelText='my label'
        accept={['*']}
      />
    )
    await userEvent.upload(rendered.getByLabelText('my label'), new File([''], 'fakeaccounts.yaml', {
      type: 'application/yaml'
    }))
  })
})

Suggested Severity

None

Application/PAL

IBM App Connect Enterprise (don't know what a PAL is)

Code of Conduct

s100 commented 2 months ago

Actually, after hacking @testing-library/user-event to bypass isUIValue, I see a different error, this one from JSDOM:

InvalidStateError: This input element accepts a filename, which may only be programmatically set to the empty string.

I think this indicates that this isn't an issue with @testing-library/user-event but in <FileUploaderDropContainer>.