ZeeCoder / use-resize-observer

A React hook that allows you to use a ResizeObserver to measure an element's size.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

"ResizeObserver is not defined" error when running Jest

remidej opened this issue ยท comments

Hello ๐Ÿ‘‹

Using useResizeObserver crashes my app's tests. Jest uses JSDom, which apparently doesn't support the ResizeObserver API.

I know we can detect when Jest is running, but React doesn't support conditionally calling hooks, so I don't know how to prevent Jest from crashing. I think the fix has to be done inside the hook.

Hey ๐Ÿ‘‹

There must be some way to patch the test environment.
I'm quite certain that the answer won't lie in detecting the test environment within the hook. ๐Ÿ˜…

I am having the same issue with jest.

I'll be happy to add a section to the Readme if someone comments a solution.

I used polyfilled version, import useResizeObserver from "use-resize-observer/polyfilled"; because of issues in IOs 12. Maybe this will help.

I managed to bypass the issue like that.

import React from 'react';

import { render, fireEvent } from '@testing-library/react';

import { AuthProvider } from '../context/AuthProvider';
import LoginPage from './LoginPage';

const pass = 'pass';
const user = 'user';
class ResizeObserver {
  observe() {}
  unobserve() {}
}
describe('loginpage ', () => {
  window.ResizeObserver = ResizeObserver;
  test('should update username and password', async () => {
    const { findByPlaceholderText } = render(
      <AuthProvider>
        <LoginPage />
      </AuthProvider>,
    );
    const username = await findByPlaceholderText('Your username...');
    const password = await findByPlaceholderText('Password...');
    fireEvent.change(username, { target: { value: user } });
    fireEvent.change(password, { target: { value: pass } });
    expect(username.value).toBe(user);
    expect(password.value).toBe(pass);
  });
});

I work on a component library where we use the hook to enhance component functionality behind a prop. So if hasResize=false, we don't use the values provided from the hook. The library does not provide a polyfill for the same reasons you list in the readme.

The hook can't be placed behind a browser support conditional - so even when hasResize=false is false, the hook throws an error in environments where RO is not supported. This effectively requires our consumers to provide an RO polyfill when they may not even have configured props to use the hook.

The only solution for us is to have two components, Component and ComponentWithResize. Render one or the other depending on prop and support.

A check for RO support in the hook would be very inexpensive and fix these issues.

@tay1orjones that sounds to me like a different issue.
For that I think the hook could be smart enough not to create a ResizeObserver instance when there's nothing to observe.
So then when hasResize=false in your case, you would simply not pass in anything to the hook to observe, and it would do nothing.

I ran into the same problem, in that I'd like to use this hook with graceful degradation for IE. I put up #42 which does just this, though it still needs some tests added.

I added a test to #42, it should be ready to go.

@ZeeCoder yep, thats fair. #42 will solve that for us, thanks @GreenGremlin!

In case it helps someone, I found that you can mock module to use polyfilled when in tests with a few lines. This will at least get around the undefined error. It won't add any functionality tho.

jest.mock('use-resize-observer', () => {
  return jest.requireActual('use-resize-observer/polyfilled');
});

@tay1orjones the latest alpha release (https://github.com/ZeeCoder/use-resize-observer/releases/tag/v6.2.0-alpha.1) will not instantiate the ResizeObserver, until there's an actual element it receives, so it should handle your case.

I still think the original issue with Jest reported here is not something the library needs to adapt to, but rather the environment needs to be mocked or polyfilled.
Also see the documentation for other options to opt out of RO instantiation altogether if needed.:
https://github.com/ZeeCoder/use-resize-observer#opting-out-of-or-delaying-resizeobserver-instantiation

Another possible mock solution - create a minimal mock of useResizeObserver which at least returns an object with width

// JSDom (which is used by jest) does not implement layout/rendering.
// we create this mock to simply simulate a desktop view with a width of 1000
function useResizeObserverMock() {
  return {
    width: 1000,
  };
}

jest.mock('use-resize-observer', () => useResizeObserverMock);

adding this line of code in the testing file fixed the error for me
global.ResizeObserver = require('resize-observer-polyfill')

For those looking for a more configurable solution, the below worked for me:

jest.config.js

module.exports = {
  moduleNameMapper: {
    'use-resize-observer': 'use-resize-observer/polyfilled'
  }
};

Solution for vitest
write in the file with the test at the highest level of nesting

const ResizeObserverMock = vi.fn(() => ({
  observe: vi.fn(),
  unobserve: vi.fn(),
  disconnect: vi.fn()
}))

vi.stubGlobal('ResizeObserver', ResizeObserverMock)

I managed to bypass the issue like that.

import React from 'react';

import { render, fireEvent } from '@testing-library/react';

import { AuthProvider } from '../context/AuthProvider';
import LoginPage from './LoginPage';

const pass = 'pass';
const user = 'user';
class ResizeObserver {
  observe() {}
  unobserve() {}
}
describe('loginpage ', () => {
  window.ResizeObserver = ResizeObserver;
  test('should update username and password', async () => {
    const { findByPlaceholderText } = render(
      <AuthProvider>
        <LoginPage />
      </AuthProvider>,
    );
    const username = await findByPlaceholderText('Your username...');
    const password = await findByPlaceholderText('Password...');
    fireEvent.change(username, { target: { value: user } });
    fireEvent.change(password, { target: { value: pass } });
    expect(username.value).toBe(user);
    expect(password.value).toBe(pass);
  });
});

Hi,
I was getting "please install a polyfill for ResizeObserver" after migrating jest26 to jest28 version in angular application. We are not using ResizeObserver in our application but I am not sure whether any dependency with NGXCHARTS, So I was getting this error suddenly.

I have tried above solution of bypassing, it worked thank you.

class ResizeObserver {
observe() {}
unobserve() {}
disconnect() {}
}

describe('Component', () => {
window.ResizeObserver = ResizeObserver;
})

adding this line of code in the testing file fixed the error for me global.ResizeObserver = require('resize-observer-polyfill')

import ResizeObserver from 'resize-observer-polyfill';
global.ResizeObserver = ResizeObserver;

adding this line of code in the testing file fixed the error for me global.ResizeObserver = require('resize-observer-polyfill')

import ResizeObserver from 'resize-observer-polyfill';
global.ResizeObserver = ResizeObserver;

Thanks, It really works. I am rendering ReactFlow in JEST. Surprisingly it works.

global.ResizeObserver = class {
observe() {}
unobserve() {}
disconnect() {}
};
This code solved my issue

adding this line of code in the testing file fixed the error for me global.ResizeObserver = require('resize-observer-polyfill')

import ResizeObserver from 'resize-observer-polyfill';
global.ResizeObserver = ResizeObserver;

directy in jest.setup.ts works well ๐Ÿ‘

npm i -D resize-observer-polyfill

In setupTests.ts

import ResizeObserver from 'resize-observer-polyfill';
global.ResizeObserver = ResizeObserver;