如何使用反应测试库模拟 ResizeObserver 以在单元测试中工作
Posted
技术标签:
【中文标题】如何使用反应测试库模拟 ResizeObserver 以在单元测试中工作【英文标题】:How to mock ResizeObserver to work in unit tests using react testing library 【发布时间】: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();
);
);
【问题讨论】:
【参考方案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 & 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 中进行了开玩笑测试。谢谢以上是关于如何使用反应测试库模拟 ResizeObserver 以在单元测试中工作的主要内容,如果未能解决你的问题,请参考以下文章