В современном фронтенд-разработке компоненты часто зависят от
размеров элементов DOM для корректного рендеринга и логики. Например,
адаптивные таблицы, карусели, динамические сетки и компоненты с
анимациями могут использовать ResizeObserver для
отслеживания изменений размеров. В среде тестирования, такой как Jest с
React Testing Library, ResizeObserver отсутствует в
стандартной среде Node.js, что приводит к ошибкам вроде:
ReferenceError: ResizeObserver is not defined
Для корректного тестирования требуется его мокирование.
Можно создать глобальный мок в файле конфигурации тестов (например,
setupTests.js), чтобы все тесты использовали поддельную
реализацию ResizeObserver:
class ResizeObserverMock {
constructor(callback) {
this.callback = callback;
}
observe(target) {
this.callback([{ target }]); // сразу вызываем callback для имитации изменения
}
unobserve() {}
disconnect() {}
}
global.ResizeObserver = ResizeObserverMock;
Ключевые моменты:
observe должен принимать DOM-элемент и вызывать
callback, чтобы компоненты, зависящие от изменения размеров, корректно
инициализировались.unobserve и disconnect можно
оставить пустыми, если в тестах не проверяется их поведение.ResizeObserver используется только для наблюдения за
размерами.Если необходимо контролировать вызовы методов
ResizeObserver, можно использовать jest.fn()
для слежки за вызовами:
const observeMock = jest.fn();
const unobserveMock = jest.fn();
const disconnectMock = jest.fn();
global.ResizeObserver = jest.fn().mockImplementation((callback) => ({
observe: observeMock,
unobserve: unobserveMock,
disconnect: disconnectMock,
}));
Особенности такого подхода:
Позволяет проверять, вызывались ли методы observe,
unobserve или disconnect с правильными
аргументами:
expect(observeMock).toHaveBeenCalledWith(expect.any(HTMLElement));Подходит для unit-тестов, где важно убедиться в правильной
интеграции компонента с API ResizeObserver.
Для более сложных сценариев, когда требуется имитировать изменение размеров элемента после монтирования, можно вызывать callback вручную:
let resizeCallback;
global.ResizeObserver = class {
constructor(callback) {
resizeCallback = callback;
}
observe(target) {
// начальная симуляция размера
resizeCallback([{ target, contentRect: { width: 100, height: 100 } }]);
}
unobserve() {}
disconnect() {}
};
// В тесте можно изменять размеры
resizeCallback([{ target: divElement, contentRect: { width: 200, height: 200 } }]);
Преимущества:
При мокировании ResizeObserver в сочетании с RTL важно
учитывать асинхронность обновлений компонента:
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import ResponsiveComponent from './ResponsiveComponent';
test('отслеживание изменения размера', async () => {
const { container } = render(<ResponsiveComponent />);
const box = container.querySelector('.resize-box');
// имитация изменения размера
resizeCallback([{ target: box, contentRect: { width: 300, height: 300 } }]);
// проверка реакции компонента
expect(screen.getByText('Ширина: 300')).toBeInTheDocument();
});
Важно:
ResizeObserver вызывается синхронно в моках, но
компонент может обновлять состояние асинхронно через
setState. Поэтому при необходимости использовать
await waitFor(...) или findBy... для ожидания
ререндеров.setupTests.js, чтобы не
дублировать его в каждом тесте.unobserve и
disconnect.jest.fn().contentRect.ResizeObserver убедиться, что мок сбрасывается между
тестами, чтобы избежать побочных эффектов.Мокирование ResizeObserver позволяет безопасно
тестировать компоненты, зависящие от размеров DOM, и интегрировать их с
React Testing Library без ошибок среды Node.js. Правильная организация
мока обеспечивает как простое прохождение тестов, так и возможность
проверки сложной логики адаптивного поведения.