react-intersection-observer icon indicating copy to clipboard operation
react-intersection-observer copied to clipboard

Version >= 9.12.0 breaks automatic InteractionOberserver setup with jest

Open valleywood opened this issue 1 year ago • 6 comments
trafficstars

We have a test environment where we've used mockAllIsIntersecting from react-intersection-observer/test-utils together with Jest This has worked just fine until we updated to version 9.12.0 and beyond after that we've started to get type errors when running tests.

After that we got the error:

TypeError: observer.observe is not a function

      at observe (node_modules/react-intersection-observer/src/observe.ts:153:12)
      at node_modules/react-intersection-observer/src/useInView.tsx:66:19
      at commitHookEffectListMount (node_modules/react-dom/cjs/react-dom.development.js:23189:26)

The error could be resolved by manually adding this code to our Jest tests:

beforeEach(() => {
  setupIntersectionMocking(jest.fn);
});

afterEach(() => {
  resetIntersectionMocking();
});

So it seems like version 9.12.0 broke the automatic setup with Jest? 🤔

To Reproduce Try and recreate the issue in a Codesandbox:

Expected behavior If react-intersection-observer should still be possible to run together with Jest without manually using setupIntersectionMocking and resetIntersectionMocking types should be fixed.

I suspect that this error comes from this update mentioned in the release notes for version 9.12.0

"Types cleanup in test-utils, getting rid of @types/jest (replaced with vitest)"

Screenshots Skärmavbild 2024-08-21 kl  12 00 22

**Desktop **

  • OS: Mac OS Sonoma
  • Browser N/A (Jest tests)
  • Version >= 9.12.0

valleywood avatar Aug 21 '24 10:08 valleywood

Can you verify that it's 9.12 it first happens? What if you run just one test? It could be Jest resets the observer after a run, so before All isn't working as expected. Do you have something in your code that resets it after a test?

I unfortunately won't have a chance to look into it until September.

thebuilder avatar Aug 24 '24 14:08 thebuilder

I've now verified that the error isn't there with version 9.11 it starts with 9.12. I've also verified that the error doesn't occur if I run just one test.

The error occurs only when I have two or more tests that both contains a call to mockAllIsIntersecting(true);

I didn't have anything that resets between the test before I've added a the fix to circumvent this error (the setupIntersectionMocking/resetIntersectionMocking mentioned above)

valleywood avatar Aug 26 '24 06:08 valleywood

Could be a difference between vitest and jest, and how they reset code. Might have to go back to beforeEach for Jest tests then.

thebuilder avatar Aug 26 '24 16:08 thebuilder

I've tried installing and running the hooks.test.tsx tests using Jest instead of Vitest - Using a default Jest configuration, it correctly does the mocking, so mockAllIsIntersecting works as expected. CleanShot 2024-09-03 at 12 36 22@2x

Is there anything special in your setup or Jest configuration?

thebuilder avatar Sep 03 '24 10:09 thebuilder

I just want to chime in and say I'm experiencing the same issue as well using Jest and starting with 9.12, though my error looks slightly different:

    TypeError: io.observe is not a function

@valleywood 's workaround solved the issue for me, but I only needed setupIntersectionMocking(jest.fn) in the beforeEach() hook. I did not need resetIntersectionMocking() in afterEach()

denchen avatar Sep 05 '24 07:09 denchen

We're running into the same issue, updating from 9.10.3 to 9.13.1 and getting the observer.observe is not a function error.

In terms of custom setup, the only thing that comes to mind is that we add a top-level

import "intersection-observer";

at the top of our test setup file.

Toolo avatar Sep 11 '24 10:09 Toolo

We experience the same issue. For us the problem is that setupIntersectionMocking(jest.fn) is called in the beforeAll step. However, since we use jest with resetMocks=true, the mocks are reset after each test, but only setup at the beginning.

Calling setupIntersectionMocking(jest.fn) in beforeEach fixes the error for us.

julian-jambit avatar Jan 13 '25 15:01 julian-jambit

@julian-jambit that could explain the issue. This change was made because of the issue in #689 - I'm thinking it might sense to just go back to beforeEach to be safe.

thebuilder avatar Jan 14 '25 09:01 thebuilder

:tada: This issue has been resolved in version 9.15.0 :tada:

The release is available on:

Your semantic-release bot :package::rocket:

thebuilder avatar Jan 14 '25 09:01 thebuilder

Hi @thebuilder thank you for the quick fix. Unfortunately, the version 9.15.0 still doesn't solve the issue and even breaks our mentioned worarkound. The additional check for isMocking in setupIntersectionMocking does not work well together with resetMocks=true in jest. With resetMocks jest resets all mocks after each test, but it does not reset your isMocking variable, so the mock is never setup again.

julian-jambit avatar Jan 14 '25 13:01 julian-jambit

Right. Okay. I should be able to determine the mock state without using a variable.

thebuilder avatar Jan 14 '25 13:01 thebuilder

@julian-jambit could you try https://github.com/thebuilder/react-intersection-observer/pull/716 - You should be able to install it before it's released with the pkg-pr-new bundle:

npm i https://pkg.pr.new/thebuilder/react-intersection-observer@716

thebuilder avatar Jan 14 '25 13:01 thebuilder

This has the same error. From the documentation of resetMocks:

This will lead to any mocks having their fake implementations removed but does not restore their initial implementation.

So isMockFunction seems to still return true, even if the mock is reset. I don't know if there is a way to check if there is no mock implementation.

julian-jambit avatar Jan 14 '25 15:01 julian-jambit

Jeez, what kind of pseudo reset is that. Seems like Vitest does the same. Can't find an obvious way to determine if it has been reset. Maybe I have to skip that check then, and always create a new instance.

thebuilder avatar Jan 14 '25 15:01 thebuilder

:tada: This issue has been resolved in version 9.15.1 :tada:

The release is available on:

Your semantic-release bot :package::rocket:

thebuilder avatar Jan 21 '25 11:01 thebuilder

I can confirm that it works now, thank you!

Vinnl avatar Jan 21 '25 14:01 Vinnl