Higher Order Components (HOC) в React — это паттерн для повторного использования логики компонентов. HOC — это функция, которая принимает компонент и возвращает новый компонент с дополнительной функциональностью. Примером HOC может быть компонент, который добавляет функциональность отслеживания состояния или подключает компонент к Redux.
При тестировании компонентов с использованием React Testing Library, тестирование HOC может быть немного сложнее, чем обычных компонентов, поскольку HOC изменяет поведение переданного компонента. Необходимо уделить внимание тому, как HOC взаимодействует с состоянием и как он влияет на отображение компонентов.
Тестирование HOC в первую очередь зависит от того, как он взаимодействует с переданным компонентом и как предоставляет или изменяет пропсы. Вот несколько способов тестирования HOC:
Тестирование в контексте обертки Многие HOC используют контекст или другие механизмы для добавления функциональности компонентам. Это значит, что при тестировании нужно учитывать, как HOC оборачивает компонент. Например, если HOC использует контекст, тест должен убедиться, что компонент правильно получает данные из контекста.
Тестирование исходного компонента HOC обычно добавляет или изменяет поведение компонента. Чтобы протестировать такой компонент, необходимо проверить, как поведение исходного компонента изменяется в результате применения HOC. Это означает, что в тестах важно имитировать состояние и пропсы, передаваемые HOC, и убедиться, что результат соответствует ожидаемому.
Мока функции или пропсов, добавленных HOC Иногда HOC добавляет дополнительные функции или изменяет поведение существующих пропсов, например, выполняет запросы данных или добавляет обработчики событий. В таких случаях можно использовать моки или шпионов, чтобы проверить, вызываются ли эти функции, и правильно ли компонент получает пропсы.
Рассмотрим пример простого HOC, который оборачивает компонент и передает ему данные из состояния.
// HOC.js
import React, { useState } from 'react';
export function withCounter(Component) {
return function WithCounter(props) {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
return <Component {...props} count={count} increment={increment} />;
};
}
В этом примере HOC withCounter добавляет состояние
счётчика и передает его как пропсы в оборачиваемый компонент.
Тестирование такого HOC должно удостовериться, что передаваемые пропсы
изменяются, и компонент правильно обновляется при изменении
состояния.
Для тестирования можно использовать React Testing Library и Jest.
// Counter.js
import React from 'react';
export function Counter({ count, increment }) {
return (
<div>
<p>{count}</p>
<button onCl ick={increment}>Increment</button>
</div>
);
}
// App.js
import React from 'react';
import { withCounter } from './HOC';
import { Counter } from './Counter';
const EnhancedCounter = withCounter(Counter);
function App() {
return <EnhancedCounter />;
}
export default App;
Теперь, чтобы протестировать withCounter, нужно
удостовериться, что состояние счетчика работает корректно, и компонент
обновляется после вызова функции increment.
// HOC.test.js
import { render, fireEvent, screen } from '@testing-library/react';
import { EnhancedCounter } from './App'; // импорт обёрнутого компонента
test('счётчик увеличивается при клике на кнопку', () => {
render(<EnhancedCounter />);
const button = screen.getByText(/Increment/i);
const countText = screen.getByText(/0/);
expect(countText).toBeInTheDocument();
fireEvent.click(button);
expect(screen.getByText(/1/)).toBeInTheDocument();
});
В данном тесте:
withCounter.Если HOC использует контекст, например, для управления состоянием или
передачи данных, тестирование становится немного сложнее. Для этого
можно использовать Mock контекста, чтобы тестировать
поведение компонента, не создавая зависимости от реального
контекста.
Пример:
// ThemeContext.js
import React, { createContext, useContext } from 'react';
const ThemeContext = createContext();
export function useTheme() {
return useContext(ThemeContext);
}
export function ThemeProvider({ children }) {
const theme = 'dark';
return <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>;
}
HOC, который использует ThemeContext:
// withTheme.js
import React from 'react';
import { useTheme } from './ThemeContext';
export function withTheme(Component) {
return function WithTheme(props) {
const theme = useTheme();
return <Component {...props} theme={theme} />;
};
}
В тестах можно замокировать ThemeContext, чтобы
проверить, как работает HOC:
import { render, screen } from '@testing-library/react';
import { withTheme } from './withTheme';
import { ThemeProvider } from './ThemeContext';
const ThemedComponent = withTheme(({ theme }) => <div>{theme}</div>);
test('HOC передает значение контекста', () => {
render(
<ThemeProvider>
<ThemedComponent />
</ThemeProvider>
);
expect(screen.getByText('dark')).toBeInTheDocument();
});
Здесь:
ThemedComponent обернут в HOC
withTheme, который передает значение контекста в
компонент.ThemeProvider, который
предоставляет контекст.HOC может передавать дополнительные пропсы или функции, что также нужно тестировать. Например, если HOC добавляет обработчик событий или изменяет данные пропсов, тест должен проверять, как это влияет на поведение компонента.
Пример:
// HOC с добавлением обработчика события
export function withClickHandler(Component) {
return function WithClickHandler(props) {
const handleClick = () => alert('Clicked!');
return <Component {...props} onCl ick={handleClick} />;
};
}
Тестирование:
import { render, fireEvent } from '@testing-library/react';
import { withClickHandler } from './withClickHandler';
const Button = ({ onClick }) => <button onCl ick={onClick}>Click me</button>;
const EnhancedButton = withClickHandler(Button);
test('обработчик клика вызывается при нажатии на кнопку', () => {
render(<EnhancedButton />);
const button = screen.getByText(/Click me/i);
const alertMock = jest.spyOn(window, 'alert').mockImplementation();
fireEvent.click(button);
expect(alertMock).toHaveBeenCalledWith('Clicked!');
});
В этом примере:
Button, который принимает проп
onClick.withClickHandler добавляет обработчик нажатия.Тестирование HOC в React Testing Library требует внимания к контекстам, пропсам и поведению, которое добавляется обернутыми компонентами. Важно использовать такие инструменты, как мокирование и шпионов, для проверки правильности работы HOC и его воздействия на переданные компоненты.