preactjs / preact

⚛️ Fast 3kB React alternative with the same modern API. Components & Virtual DOM.

Home Page:https://preactjs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Compatibility issue: Jest mock works in React / fails in Preact when using ForwardRef in a component

DanielMaczak opened this issue · comments

I am using Preact 10.19.6 (should be the latest).

The bug

Jest does not call event handler in ForwardRef component when using Preact.
This behavior does not happen in both of the following cases:

  • I use React in place of Preact and I keep ForwardRef in my component.
  • I use Preact and I don't use ForwardRef in my component.

It seems the onChange event does not trigger at all in tests while using forwardRef because I never reach it, even when putting a breakpoint directly inside the event:

...
      <input                      // <-- breakpoint here does trigger
        type="date"
        value={value}
        id="test-id"
        onChange={e => {
          storeValue(e);          // <-- breakpoint here does not trigger
        }}
        ref={ref as Ref<HTMLInputElement>}
      />
...

To Reproduce

Preact repo where you can see the error: https://github.com/DanielMaczak/testing-jest-forwardref-bug
React repo where the test passes: https://github.com/DanielMaczak/testing-react-forwardref-bug
I did my best to make both as close to each other as possible:

  • Using the latest version of Preact and React
  • Using the same version of Jest
  • Using raw Jest instead to Vitest to ensure it is not Vitest issue
  • Scaling the code to minimum and using virtually identical code in both repos

Steps to verify the behavior (in both repos):

  1. Run npm i
  2. Run npm run test

You will see that one of the repos throws error on the mocked function not being called once while the other does not complain and the test passes.

Expected behavior

Both repos use the same code for the component and for the test, thus results in both should be the same.

Further information on this bug:

It occurs even when the forwardRef is used in the tested module like this, e.g. not referencing the tested component and not even imported in the tests at all:

export const Test= forwardRef(() => {
  return <div></div>;
});

I also pinpointed where the tests diverge between the two scenarios when forwardRef is used and isn't in the tested module:

node_modules / jsdom / lib / jsdom / living / events / EventTarget-impl.js > innerInvokeEventListeners :

  if (!listeners || !listeners[type]) {
    return found; // the code exits here when using forwardRef()
  }

EDIT: I found the compat piece of code causing this. I will try to come up with a solution and submit a pull request.

This is an issue with preact-testing-library. It does not translate event names to React version when preact/compat is imported. I will submit a fix there.