【问题标题】:How to mock ResizeObserver to work in unit tests using react testing library如何使用反应测试库模拟 ResizeObserver 以在单元测试中工作
【发布时间】:2021-02-09 22:42:04
【问题描述】:

如果有人可以提供帮助,我有一个自定义钩子,它使用 ResizeObserver 来更改组件的宽度。我的问题是,当我去运行我的单元测试时,它会破坏我的所有测试并查看快照,它并没有渲染 dom 中的所有元素。在我实现 ResizeObserver 之前它一直在工作。有谁知道我是否有办法将 ResizeObserver 模拟为未定义。或其他建议。

import * as React from 'react';
import ResizeObserver from 'resize-observer-polyfill';

const useResizeObserver = (ref: { current: any }) => {
    const [dimensions, setDimensions] = React.useState<DOMRectReadOnly>();
    React.useEffect(() => {
        const observeTarget = ref.current;
        const resizeObserver = new ResizeObserver((entries) => {
            entries.forEach((entry) => {
                setDimensions(entry.contentRect);
            });
        });
        resizeObserver.observe(observeTarget);
        return () => {
            resizeObserver.unobserve(observeTarget);
        };
    }, [ref]);
    return dimensions;
};

export default useResizeObserver;



import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';

import mockFetchProfileActivity from '../../../services/mocks/fetch-profile-activity';
import BarChart from './BarChart';

const component = <BarChart userActivity={mockFetchProfileActivity} />;

describe('Render barElement Chart component', () => {
    const observers: any[] = [];
    let resizeHandler: (observers: any[]) => void;
    (window as any).ResizeObserver = (e: any) => {
        resizeHandler = e;

        return {
            observe(element: any) {
                observers.push(element);
            },
            unobserve(element: any) {
                const i = observers.indexOf(element);
                if (i !== -1) {
                    observers.splice(i, 1);
                }
            }
        };
    };

    it('Matches the snapshot', () => {
        // resizeHandler(observers);
        const container = render(component);
        expect(container).toMatchSnapshot();
    });

    it('when clicking on a chart barElement drilldown "challenges" are shown', async () => {
        // arrange
        const componentRender = render(component);
        waitFor(() => resizeHandler(observers));

        // act
        const barElement = componentRender.container.querySelector('svg rect');

        if (barElement) userEvent.click(barElement);

        // assert
        expect(screen.getByText('Challenge 1')).toBeInTheDocument();
    });
});

【问题讨论】:

    标签: reactjs unit-testing jestjs react-testing-library window-resize


    【解决方案1】:

    我选择将 polyfill 添加为开发依赖项,并将以下行添加到 setupTests.js/ts:

    global.ResizeObserver = require('resize-observer-polyfill')
    

    【讨论】:

    • 非常流畅,并且完美运行。我喜欢!为了让您的类型很好地匹配,请将其换成 import 等效项,然后在下一行中分配它。
    • 不错!我不得不这样做 window.ResizeObserver = require... 但后来它没有问题。
    【解决方案2】:

    模拟 ResizeObserver:

    class ResizeObserver {
        observe() {
            // do nothing
        }
        unobserve() {
            // do nothing
        }
    }
    
    window.ResizeObserver = ResizeObserver;
    export default ResizeObserver;
    

    sample.test.js

    import ResizeObserver from './__mocks__/ResizeObserver';
    import module from 'sample';
    
    describe('module', ()=> {
         it('returns an instance of ResizeObserver', () => {
               // do something that uses the resize observer
               // NOTE: The actual observe handler would not be called in jsdom anyway as no resize would be triggered.
               // e.g.
               expect(module.somethingThatReturnAReference to the resize observer).toBeInstanceOf(ResizeObserver);
            });
    });
    

    source

    【讨论】:

    • 我如何测试 resizeObserver 回调中发生了什么?例如,我对需要测试的 HTML 元素样式进行了一些更改。怎么样?
    【解决方案3】:

    我在使用 Create React App 设置时遇到了类似的问题。

    如果是这种情况,您可以在根目录中创建一个名为 setupTest.js 的文件并添加以下代码:

      import '@testing-library/jest-dom/extend-expect';
      import 'jest-extended';
        
      jest.mock('./hooks/useResizeObserver', () => () => ({
        __esModule: true,
        default: jest.fn().mockImplementation(() => ({
            observe: jest.fn(),
            unobserve: jest.fn(),
            disconnect: jest.fn(),
        })),
      }));
    

    您可以找到更多信息来配置 Create React App here 和 ResizeObserver API here 的测试环境

    【讨论】:

    • 看起来不错,唯一的问题是我得到一个错误,你真的得到这个工作了吗这是我得到的错误。 Property 'ResizeObserver' does not exist on type 'Global &amp; typeof globalThis'
    • 嗨,是的,对我来说工作正常。如果我删除代码,我会收到此错误This browser does not support ResizeObserver out of the box. See: https://github.com/react-spring/react-use-measure/#resize-observer-polyfills。您是否删除了polyfill?与上面的代码一样,您不需要它。如果是这样,可能是版本问题。我正在使用 react-scripts 4.0.0
    • 对不起,我刚刚忘记提到我得到的错误(如果我删除调整大小的观察者模拟)来自我在项目中使用的库(@visx/tooltip)。在您的情况下,错误可能会有所不同,因为您使用的是不同的库
    • 我没有使用任何库,只是在自定义挂钩中使用了 resizeObserver API,因为不需要使用库。我正在使用 react-scripts 4.0.1 但错误更多是打字稿错误,而不是浏览器错误。
    • 抱歉,上面提出的解决方案仅适用于 Javascript。我刚刚找到了一个可以帮助here 的答案,如果你添加global.ResizeObserver = resizeObserverMock; 而不是const globalAny:any = global; globalAny.ResizeObserver = resizeObserverMock;。让我知道这是否有效,我将编辑我的答案
    【解决方案4】:

    我已经在 setupTests.js/ts 中添加了下一个代码:

    global.ResizeObserver = jest.fn().mockImplementation(() => ({
        observe: jest.fn(),
        unobserve: jest.fn(),
        disconnect: jest.fn(),
    }))
    

    【讨论】:

    • 这对我来说在模板 js 中进行了开玩笑测试。谢谢
    猜你喜欢
    • 2019-05-03
    • 2018-07-17
    • 1970-01-01
    • 2020-03-10
    • 2022-10-08
    • 1970-01-01
    • 1970-01-01
    • 2017-06-14
    • 2022-07-13
    相关资源
    最近更新 更多