jest react-testing-library에서 styled-component Theme 적용하기

pds·2023년 3월 9일
1

TIL

목록 보기
35/60

문제상황

미니 프로젝트를 진행하는데 Styled-Components를 써서 css를 적용하는데

ThemeProvider를 통해 공통 스타일 속성을 사용해 일관성 있게 컴포넌트를 스타일링하고자 했다.

export default function App({ Component, pageProps }: AppProps) {
  return (
    <QueryClientProvider client={queryClient}>
      <Hydrate state={pageProps.dehydratedState}>
        <RecoilRoot>
          <ThemeProvider>
            <Layout>
              <Component {...pageProps} />
            </Layout>
          </ThemeProvider>
        </RecoilRoot>
        <ReactQueryDevtools initialIsOpen={false} />
      </Hydrate>
    </QueryClientProvider>
  );
}

위 코드의 ThemeProvider는 다크모드 적용때문에 한번 더 감싸준 것이고 결국 Styled-Components의 테마이다.

jestreact-testing-library로 컴포넌트 이벤트 테스트를 하던 도중 theme context를 사용하고 있던 부분 때문에 다음과 같은 오류가 났다.

● button을 클릭하면 click 이벤트가 동작한다.

    TypeError: Cannot read properties of undefined (reading 'regular')

      3 | const Text = styled.div`
      4 |   font-style: normal;
    > 5 |   font-weight: ${({ theme }) => theme.fontWeight.regular};
        |                                                  ^
      6 | `;
      7 |
      8 | export const TextBodyTitle = styled(Text)`
import { render } from '@testing-library/react';
render(<SomeComponentWithStyledComponentTheme/>);

테스트환경에서는 Styled-Component ThemeProvider가 없기 때문에 theme context가 undefined였던 것이다.

storybook에서도 독립적인 컴포넌트 하나하나에 대한 styled-components 적용때문에

데코레이터를 사용해 ThemeProvider를 감싸줬던 것을 기억하며 jest 환경에서도 이를 적용해줘야 함을 알게 되었다


Styled-Components 사용하기

jest에서 styled-component 사용하기 위해 의존성 설치

yarn add -D jest-styled-components

jest config의 setupFilesAfterEnv 설정에 jest-styled-components 추가해 각 독립적인 테스트에 해당 라이브러리가 적용될 수 있게 해준다.

 setupFilesAfterEnv: ['...yours', 'jest-styled-components'],

ThemeProvider Wrapper를 적용한 custom jest render 함수를 만들어 사용할 수 있게 한다.

import 'jest-styled-components';
import { ThemeProvider } from 'styled-components';
import { render } from '@testing-library/react';
import themeMode from '../styles/theme';

const Wrapper = ({ children }) => <ThemeProvider theme={themeMode['light']}>{children}</ThemeProvider>;

const renderWithStyledComponent = (ui, options) => render(ui, { wrapper: Wrapper, ...options });

export * from '@testing-library/react';

export { renderWithStyledComponent as render };

어디에 선언하던 import해서 사용할 수 있겠지만 test환경에서만 사용하기 때문에

__test__ 폴더에 넣어주었다.

styled-component theme가 적용된 컴포넌트를 테스트할 때 이런 식으로 import하면 된다.

// 커스텀 render 위치
import { render } from '../utils';
// 원래 rtl의 render 위치
import { fireEvent } from '@testing-library/react';

테스트하기

import { render } from '../utils';
import Button from '@/components/atoms/Button';
import { COLOR } from '@/styles/constants';
import { fireEvent } from '@testing-library/react';

/** 이 테스트를 통과하면 Styled-Components ThemeProvider가 jest 환경에 잘 적용된 것입니다. */
it('primary theme 버튼은 primary color를 가지고 있다.', () => {
  const { getByRole } = render(
    <Button colorTheme="primary" onClick={jest.fn()}>
      hello
    </Button>,
  );
  expect(getByRole('button')).toHaveStyleRule('background-color', COLOR.brand1);
});

it('button을 클릭하면 click 이벤트가 동작한다.', () => {
  const mockOnClick = jest.fn();
  const { getByRole } = render(
    <Button colorTheme="primary" onClick={mockOnClick}>
      hello
    </Button>,
  );
  fireEvent.click(getByRole('button'));
  expect(mockOnClick).toHaveBeenCalled();
});

특히 이렇게 작은 컴포넌트는 어차피 UI나 사용자 이벤트 대부분은 스토리북으로 테스트하지만

그래도 Styled-components theme가 잘 적용된다는 것을 보여줄 수 있는 테스트인 것 같다

버튼 컴포넌트의 Styled 컴포넌트에는 다음과 같은 background-color 속성이 있었다.

background-color: ${(props) =>
    props.colorTheme === 'primary' ? props.theme.brandColor : buttonTheme[props.colorTheme][0]};

assertion 부분의 toHaveStyleRule 검증은 jest-styled-components 의 검증 메소드다.

toHaveStyle이 실제 컴포넌트에 해당 css 속성이 존재하는지를 검증한다면

toHaveStyleRule은 해당 컴포넌트에 해당 css 규칙이 존재하는지를 검증한다고 하는데

명확한 차이는 사용해봐야 좀 더 알 것 같다.

위에서 내려온 스타일인지 해당 컴포넌트에 명시되어있는 스타일인지에 대한 차이인 것 같긴 하다


jest에서는 최대한 외부적인 것과 독립적으로 컴포넌트 그 자체의 상호작용에 대해 테스트하고 싶은데

아무리 개별적인 컴포넌트더라 하더라도 styled-components가 전부 적용되어있을테니 저 커스텀 render 함수만 사용하게 될 것 같다

이런식으로 결국 전역상태관리도구나 api 상태관리 도구 provider들도 계속 들어가지 않을까 싶다..

profile
강해지고 싶은 주니어 프론트엔드 개발자

0개의 댓글