SVG 아이콘을 컴포넌트로 사용할 때 RTL에서 발생했던 문제를 해결해보았다.
애플리케이션에서 SVG
아이콘들을 직접 public
경로에 두고 사용하는데 이들을 컴포넌트화 해서 사용하고 있었다.
... //next.config.js
webpack(config) {
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack'],
});
return config;
},
@svgr/webpack
라이브러리를 활용해서 컴포넌트로 import
해서 사용하고 있다.
import Icon1 from '@/public/icons/icon1.svg';
import Icon2 from '@/public/icons/icon2.svg';
const Icons = {
Icon1, Icon2
};
const Icon = ({ icon, color, size, className = '' }: IconProps) => {
const SVGIcon = Icons[icon];
return (
<IconLayout color={color} size={size}>
<SVGIcon className={className} viewBox="0 0 24 24" />
</IconLayout>
);
};
storybook
환경에서도 인식시켜주었고 실행환경에서도 잘 되는데 jest,react-testing-library로 컴포넌트 테스트를 할 때 문제가 생겼다.
string
이 아닌 object
가 식별되었다는데
jest
환경에서 이 SVG컴포넌트를 인식을 못해서 발생하는 오류같다.
그래서 여기를 찾아보니 jest
환경에서 svg컴포넌트
를 사용할 때 추가적으로 환경설정을 해줘야했었다.
svg
와 연결할 mock
파일을 만들어주고
jest.config.js
에 svg를 mock svg
로 인식하게 설정을 해준다.
결국은 해당 라이브러리로 svg컴포넌트를 사용할 때 테스트환경에서는 따로 mocking을 해주어야 한다는 것이 결론이다.
모든 svg파일을 아이콘 컴포넌트로만 사용하고 있기 때문에 조금 더 쉬운 방법이 생각났다.
jest 환경에 global하게 mocking하기
jest.mock('./components/common/Icon', () => {
const MockedIcon = ({ icon }) => <div>{icon}</div>;
return MockedIcon;
});
어차피 components/common/Icon
이라는 컴포넌트를 통해서만 svg 컴포넌트를 사용하는 상황이라 해당 컴포넌트 자체를 jest환경에서 전역으로 mocking
해주었다.
그리고 해당 컴포넌트에서는 등록된 모든icon
에 대한 이름 타입을 필수 props로 가지고 있어서
단순히 빈 div
ReactComponent로 나오게 하기보다는 어떤 아이콘을 사용하는지 텍스트로 jest에서 찾을 수 있게 props도 넘겨주었다.
import Icon from '@/components/common/Icon';
import { render } from '@testing-library/react';
it('Icon 컴포넌트는 Icon text를 가지는 MockedIcon 컴포넌트를 렌더링한다.', () => {
const { container } = render(<Icon icon="Ax" />);
expect(container).toHaveTextContent('Ax');
});
이런식으로 아이콘을 활용한 버튼 컴포넌트에 대해 따로 svg
를 실제로 로드하거나 하지 않고도 쉽게 찾아서 이벤트 테스트를 할 수 있어 좋은 것 같다!