본문 바로가기
공부/React

React 에서 테스트 코드 작성하기 A to Z

by nr2p 2023. 9. 23.
반응형

 

테스트 코드? Jest 만 설치해서 바로 사용하면 되는거 아니였나..?

 

UI 테스트와 테스트코드에도 타입스크립트를 사용하기 위해서는 추가적인 설정이 필요했다.


1. 타입 스크립트 적용을 위한 설정 (링크)

- 테스트 코드 내에서 타입스크립트를 사용하기 위해선 세가지 방법( babel, ts-jest, @jest/globals ) 중 하나를 선택해야한다.

 

babel
장: 실제 프로젝트 환경과 동일, 타입스크립트 관련해서는 추가적인 설정 파일이 필요하지 않음
단: esm 관련 추가적인 설정이 필요함
ts-jest
장: 환경 설정 편함, esm 관련 옵션 존재
단: 추가 설정 필요, 실제 프로젝트 환경과 다를 수 있음
@jest/globals
장: 환경 설정 편함
단: 매번 import 해서 사용해야함

 

최종적으로 babel 을 사용한 방법을 선택했다.

우리 프로젝트도 babel 을 사용하고 있으니 추가적인 설정 없이 프로젝트의 설정을 따라가야된다고 판단하여 babel 을 사용하게 되었다.

 

// babel.config.js
module.exports = {
  presets: [
    '@babel/preset-env',
    '@babel/preset-typescript',
  ],
};

// jest.config.js
transform: {
  '\\.[jt]sx?$': ["babel-jest", { rootMode: 'upward' }],
}, --> 최상단의 babel 설정을 따라가겠다는 의미

 

babel 로 ts-> js 로 트랜스파일링을 진행하게끔 하였고

eslint-plugin-jest-dom, eslint-plugin-testing-library 를 사용하여 테스트코드 맞춤 린트를 사용할 수 있게끔 세팅했다.

@types/jest 를 설치하여 매번 import 하지 않아도 타입체킹이 되게 했다.

 

2. UI 테스트를 위한 설정

 

설치한 플러그인
- @testing-library/jest-dom, @testing-library/react, @testing-library/user-event, @testing-library/react-hooks

 

테스트 유틸 함수

- 전역에서 사용하는 컨텍스트들을 테스트코드 내에서도 동일하게 사용하게끔 환경 설정이 필요했다.

 

createWrapper

  • customRender 와 customRenderHook의 중복되는 부분을 공용화한 함수
const createWrapper = ({
  storeOptions,
  historyOptions,
  wrapper: Wrapper, // 지역 컨텍스트
}) => {
  const { preloadedState } = storeOptions || {};
  const store = configure(preloadedState); // redux 세팅
  const history = createMemoryHistory(historyOptions); // react-router 세팅

  if (Wrapper) {
    const WrapperWithProps = ({ children, ...rest }: wrapperPropsType<IState, TAppAction>) => (
      <AllTheProviders store={store} history={history} {...rest}>
        {Wrapper(children)}
      </AllTheProviders>
    );

    return { wrapper: WrapperWithProps, store, history };
  }

  const WrapperWithProps = (props) => (
    <AllTheProviders store={store} history={history} {...props} />
  );

  return { wrapper: WrapperWithProps, store, history };
};

 

AllTheProviders

  • UI 테스트 중 redux store, react Router 등의 값을 사용하기 위한 래퍼 컴포넌트

CustomRender

  • AllTheProvider 및 store history 를 테스트 파일에서 사용하기위해 만든 함수 (렌더용)
  • createWrapper 함수를 한 번 더 래핑하여 만들었다.

CustomRenderHook

  • AllTheProvider 및 store history 를 테스트 파일에서 사용하기위해 만든 함수 (hook 용)
  • createWrapper 함수를 한 번 더 래핑하여 만들었다.

 

 

3. 리덕스, 리덕스 사가 테스트를 위한 설정

 

testWithApiSaga

  • apiSaga(회사의 saga 유틸) 전체 플로우와 함께 단순 테스트를 하고 싶은 경우 사용

 

4. 테스트 프로세스

 

개발 중일 때

  • yarn test:watch 를 통해 수정한 파일에 대해서만 테스트

PR 올리거나 변경사항이 있을 때

  • github workflow 를 통해 모든 테스트 실행 -> 실패/성공에 따른 결과는 코멘트에 표시

 

5. 트러블 슈팅

 

모노레포 전환과 디자인시스템 추가로 인한 문제

- 디자인 시스템의 path 가 실제 path 와 다르게 사용되었기 때문에 디자인 시스템을 사용중인 모든 테스트에 에러가 발생

> moduleNameMapper 를 사용하여 path 를 올바르게 잡아주었다.

moduleNameMapper: {
   "^@wingeat/wis/(.*)$": "<rootDir>/packages/wingeat-wis/build/$1",
},

 

테스트 관련 라이브러리들간 버전 호환성

- 테스트 환경 구성 시점에 jest 는 29.3x 버전이였는데 types/jest 는 29.2x 가 최신이여서 맞춰서 설치를 했다.

 

코멘트 노이징

- 깃헙 액션으로 테스트 결과를 코멘트로 달게끔 해놓았는데 테스트를 실행할 때마다 코멘트가 생성되었기 때문에 노이지 하다는 의견을 들었다.

> 레이블을 추가하는 것으로 수정하였다.

 

Esm 모듈

- hackle 과 같은 esm 모듈을 읽지 못하는 에러가 발생

 const esModules = ['@hackler/javascript-sdk'].join('|')
 
 /** esModules 를 제외한 모든 node_modules 를 transform 할 때 무시 */
 transformIgnorePatterns: [`<rootDir>/node_modules/(?!${esModules})`],

 

반응형

'공부 > React' 카테고리의 다른 글

Context 와 렌더링 이슈  (0) 2023.08.24