-
Notifications
You must be signed in to change notification settings - Fork 190
react-intersection-observer/test-utils causes issues in projects using a mix of browser and non-browser test environments#711Description
Hello,
I think I've found an issue with the (otherwise very helpful!) automatic mocking feature of react-intersection-observer/test-utils in projects with a variety of test environments.
I work on a Next.js project. Our Vitest setup uses the jsdom environment by default, but some test files for API route handlers opt into using the node environment instead:
* @vitest-environment node
*/
// server-side test code goes here
I wanted to mock the IntersectionObserver in all my browser tests, so I added this to my Vitest setup file:
// Only mock IntersectionObserver if we're pretending to be a browser
// otherwise we get a 'window is undefined' error when
// react-intersection-observer's test utils try to do their thing.
beforeEach(() => {
setupIntersectionMocking(vi.fn);
});
afterEach(() => {
resetIntersectionMocking();
});
}
However, despite the check for global.window I still got errors:
FAIL src/app/api/store/set/route.test.ts [ src/app/api/store/set/route.test.ts ]
ReferenceError: window is not defined
setupIntersectionMocking node_modules/react-intersection-observer/test-utils/index.mjs:40:3
38| }
39| function setupIntersectionMockin...
40| window.IntersectionObserver = ...
| ^
41| var _a, _b, _c;
42| const item = {
node_modules/react-intersection-observer/test-utils/index.mjs:14:7
I think this is because by importing setupIntersectionMocking and resetIntersectionMocking from react-intersection-observer/test-utils the global beforeEach and afterEach were run as a side effect, and those setup the mocks - rendering my idea of only setting up the mocks if global.window !== undefined pointless.
I've fixed this by using patch-package but I think the options for fixing it at the source could include these ideas:
- Provide a way to opt-out of the automatic mocking
- Find a way to only add automatic mocking if the test environment looks like a browser one
- Provide
setupIntersectionMockingandresetIntersectionMockingexports from a file with no side effects, e.g. something likeimport { setupIntersectionMocking } from 'react-intersection-observer/test-utils/setupIntersectionMocking';
The third idea (provide an export with no side effects) seems like the easiest approach to me. If you like that idea I could have a go at making a PR?
This is the patch I used:
index f189bfa..c3d7cf3 100644
--- a/node_modules/react-intersection-observer/test-utils/index.js
+++ b/node_modules/react-intersection-observer/test-utils/index.js
@@ -45,17 +45,6 @@ var act3 = (
);
var isMocking = false;
var observers = /* @__PURE__ */ new Map();
-if (typeof beforeAll !== "undefined" && typeof afterEach !== "undefined") {
- beforeAll(() => {
- if (typeof jest !== "undefined") setupIntersectionMocking(jest.fn);
- else if (typeof vi !== "undefined") {
- setupIntersectionMocking(vi.fn);
- }
- });
- afterEach(() => {
- resetIntersectionMocking();
- });
-}
function warnOnMissingSetup() {
if (isMocking) return;
console.error(
diff --git a/node_modules/react-intersection-observer/test-utils/index. mjs b/node_modules/react-intersection-observer/test-utils/index.mjs
index 589c8b6..4135433 100644
--- a/node_modules/react-intersection-observer/test-utils/index.mjs
+++ b/node_modules/react-intersection-observer/test-utils/index.mjs
@@ -7,17 +7,6 @@ var act3 = (
);
var isMocking = false;
var observers = /* @__PURE__ */ new Map();
-if (typeof beforeAll !== "undefined" && typeof afterEach !== "undefined") {
- beforeAll(() => {
- if (typeof jest !== "undefined") setupIntersectionMocking(jest.fn);
- else if (typeof vi !== "undefined") {
- setupIntersectionMocking(vi.fn);
- }
- });
- afterEach(() => {
- resetIntersectionMocking();
- });
-}
function warnOnMissingSetup() {
if (isMocking) return;
console.error(
This issue body was partially generated by patch-package.