testing-library / dom-testing-library

🐙 Simple and complete DOM testing utilities that encourage good testing practices.
https://testing-library.com/dom
MIT License
3.25k stars 460 forks source link

feat: Allow null type for node on fireEvent and its shortcuts #1307

Closed jdufresne closed 2 months ago

jdufresne commented 2 months ago

What:

Allow the null type for node argument on fireEvent and its shortcuts.

Why:

A common pattern in some testing code is:

const btn = document.getElementById('my-button')
fireEvent.click(btn)

However, document.getElementById() may return null and then TypeScript will report an error:

error TS2345: Argument of type 'HTMLElement | null' is not assignable to parameter of type 'Document | Node | Element | Window'.

To resolve the TypeScript error, library users can assert or check the returned value with something like:

const btn = document.getElementById('my-button')
if (!btn) {
   throw new Error("Unable to find 'my-button')
}
fireEvent.click(btn)

But dom-testing-library is already doing this check, so let fireEvent accept null as a convenience to call sites.

The error already reported by dom-testing-library is:

Unable to fire a "click" event - please provide a DOM element.

Some might suggest that using document.getElementById() should be replaced by a dom-testing-library query method, but that is non-trivial on legacy codebases with many tests trying to adopt and introduce dom-testing-library.

How:

Augmented the types of fireEvent & friends to allow null for the node argument.

Checklist:

codesandbox-ci[bot] commented 2 months ago

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit ff95b7abaa00337f67398150f4eb18e672536829:

Sandbox Source
react-testing-library-examples Configuration
jdufresne commented 2 months ago

For me, that runtime error is desired as that gets converted into a test failure by Jest.

Using the TypeScript ! is an escape hatch to bypass type checking. Generally speaking, I try to avoid these escape hatches as much as possible and instead adjust the types to better reflect the state and capability of things.

In this case, the fireEvent function is prepared to handle null. True, it handles it by throwing an error, but it is handled none-the-less and so, IMO, isn't invalid input from a typing perspective.

My goal is to reduce the burden on the call site within tests as the same expected outcome happens: either continue with the non-null value or fail the test. Asking every call site to add ! reintroduces a burden (albeit a small one).

If this proposal is against the principles of this library, no worries, feel free to close.

eps1lon commented 2 months ago

The principle is that runtime errors should be caught at compile time.