#reactjs #unit-testing #jestjs #react-hooks #react-testing-library
#reactjs #модульное тестирование #jestjs #реагирующие хуки #react-testing-library
Вопрос:
У меня есть тестовый пример, в котором мне нужно издеваться над useRef, чтобы вернуть фиктивное текущее значение. Я попробовал jest.mock, но вместо этого он возвращает HTMLDivElement.
код:
const ref = useRef<HTMLDivElement | null>(null);
тест:
jest.mock('react', () => {
const originReact = jest.requireActual('react');
return {
...originReact,
useRef: jest.fn(),
};
});
React.useRef.mockReturnValue({ current: {offsetWith: 100} });
Макет возвращает
[ { type: 'return', value: { current: [HTMLDivElement] } } ]
Комментарии:
1. Не издевайтесь ни над одним из API React, он вам не принадлежит. Проверьте поведение компонента, а не реализацию .
2. я вижу. есть ли способ проверить, изменяется ли текущее значение ссылки, например offsetWidth. Спасибо
Ответ №1:
предложение @jonrsharpe — это общий принцип тестирования компонентов, но ваш вопрос является частным случаем, связанным с некоторыми свойствами и методами DOM, такими как offsetWidth
и getBoundingClientRect()
методы. Среда выполнения jsdom
не может вернуть, а механизм рендеринга в среде выполнения браузера возвращает результат, который приводит к offsetWidth
тому, что значения свойств, возвращаемые getBoundingClientRect()
методом, всегда будут 0
.
Итак, здесь нам нужен макет ref
.
Макет ref
здесь тоже особенный. В дополнение к использованию jest.mock()
для частичного издевательства, ref.current
свойство будет присвоено react
после монтирования компонента. Чтобы перехватить эту операцию, нам нужно создать макет ref
объекта со current
свойством object , использовать Object.defineProperty()
метод для определения getter
и setter
для этого ref.current
свойства и перехватить назначение свойства.
jest.spyOn
метод принимает необязательный третий аргумент AccessType, который может быть либо ‘get’, либо ‘set’, что оказывается полезным, когда вы хотите шпионить за получателем или установщиком соответственно.
Например.
index.tsx
:
import React, { useEffect, useRef } from 'react';
export default function App() {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
console.log(ref.current?.offsetWidth);
}, [ref]);
return <div ref={ref}>app</div>;
}
index.test.tsx
:
import { render } from '@testing-library/react';
import React, { useRef } from 'react';
import { mocked } from 'ts-jest/utils';
import App from './';
jest.mock('react', () => {
return {
...jest.requireActual<typeof React>('react'),
useRef: jest.fn(),
};
});
const useMockRef = mocked(useRef);
describe('66332902', () => {
afterEach(() => {
jest.clearAllMocks();
});
afterAll(() => {
jest.resetAllMocks();
});
test('should mock ref and offsetWidth', () => {
const ref = { current: {} };
Object.defineProperty(ref, 'current', {
set(_current) {
if (_current) {
jest.spyOn(_current, 'offsetWidth', 'get').mockReturnValueOnce(100);
}
this._current = _current;
},
get() {
return this._current;
},
});
useMockRef.mockReturnValueOnce(ref);
render(<App />);
});
});
результат теста: (см. Журналы)
PASS examples/66332902/index.test.tsx (9.518 s)
66332902
✓ should mock ref and offsetWidth (39 ms)
console.log
100
at examples/66332902/index.tsx:6:13
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.106 s
Комментарии:
1. Это не сработает, если внутри
<App>
других компонентов вызывается useRef. Есть идеи, как решить эту проблему @slideshowp2?2. @philk — я также ищу способ издеваться над свойствами ссылки для данного компонента… не весь хук useRef!