카카오스타일 파트너센터가 스토리북 기반 테스트를 실제로 돌릴 환경을 구성한 기록이다. 실행 도구를 storybook/test-runner 와 jest, vitest 중에서 고르고, jest 로 스토리북 파일을 그대로 테스트로 변환하는 transformer 까지 만들었다. 로컬에서 2분이던 테스트가 GitHub Actions 에서는 30분이 걸려 샤딩과 matrix 로 5분까지 줄인 과정도 담는다.
핵심 포인트- 프론트엔드 테스트 프레임워크는 둘로 갈린다. jsdom 으로 브라우저를 흉내 내는 JS 프레임워크는 빠르지만 빌드 환경 구성과 브라우저 API 모킹이 따로 필요하고, E2E 프레임워크는 구성이 쉽지만 느리다.
- storybook/test-runner 는 스토리북 설정을 그대로 써 설정이 가장 간단하지만 브라우저를 실제로 띄워 CPU 와 메모리를 크게 쓴다. 메모리를 32GB 넘게 쓰는 일도 있어 동시 실행 개수 제한이 필요하다.
- 파트너센터는 테스트 코드가 많아 test-runner 로는 로컬에서 10분에서 15분이 걸려, 성능이 가장 좋은 jest 를 골랐다. vitest 는 설정이 간편하고 jest 의 버그도 없지만 3배가량 느렸다.
- jest 로 스토리북 파일을 자동 테스트로 바꾸기 위해 testMatch 에 stories 패턴을 추가하고 transformer 로 변환 코드를 주입했다.
- CI 는 jest 의 shard 와 GitHub Actions 의 matrix 를 조합해 8병렬로 돌려 30분을 5분으로 줄였다. 8대를 3분씩 쓰는 비용과 1대를 24분 쓰는 비용이 같아 쪼개도 손해가 없다고 판단했다.
상세 정리- jest 설정은 webpack 과 개념이 달라 난이도가 있다. alias 는 ts-jest 헬퍼가 tsconfig 를 읽어 자동 생성하고, png 나 css 같은 파일 import 는 moduleNameMapper 로 fileMock 이 대신 로딩되게 한다.
- JSX 와 import 문법 변환은 swc 가 babel 보다 훨씬 빠르지만 emotion 플러그인을 쓰면 ARM 기반 맥에서 오류가 나 분기 처리를 뒀다.
- jsdom 이 채우지 못하는 브라우저 API 는 setupFilesAfterEnv 로 보충한다. jsdom-testing-mocks, jest-canvas-mock, fake-indexeddb 를 설치해 붙였다.
- act 경고는 스토리북 내부가 비동기 API 를 전제하므로 제거했고, i18next 를 쓴다면 번역 데이터에 영향받지 않도록 CI 모드로 바꾸길 권한다.
- webpack 의 require.context 는 jest 에 없어 분기 처리가 필요하다. 다만 webpack 이 require 호출을 전부 감지해 프로젝트 전체를 번들링해버리므로, Node.js 에서만 실행될 코드는 eval 로 감싸 webpack 이 건드리지 못하게 했다.
- Node.js 16.10 이후 jest 메모리 누수 문제가 있어 워커 메모리 상한을 걸어 재시작시키는 옵션을 썼다. 2024년 7월 기준 Node.js 20.10.0 에서 수정됐다는 후기가 붙어 있다.
- transformer 방식의 함정도 적는다. 스토리북 파일이 테스트로 바뀌면 다른 곳에서 그 stories 를 import 하기만 해도 스토리들이 테스트로 등록된다.
- 스토리북은 react-docgen-typescript-plugin 이라는 webpack 플러그인으로 컴포넌트 타입 정보를 얻어 onClose 같은 prop 에 mock 함수를 자동으로 넣는데, jest 에서는 이 플러그인을 못 써 mock 이 누락된다. mock 이 빠지면 스토리가 정상 실행되지 않는 경우가 많다.
- 해결책은 argTypes 에 action 을 명시해 그 prop 이 콜백임을 나타내는 것이고, 테스트가 불가능한 스토리는 parameters 에 skipTest 를 넣어 건너뛰게 했다.
- 이렇게 구성하니 로컬에서 전체 테스트가 2분 내외로 끝났고, watch 모드를 쓰면 수정된 부분과 관련된 테스트만 다시 돌릴 수 있다.
- GitHub Actions 기본 러너는 CPU 를 2스레드만 주기 때문에 로컬 2분짜리가 30분이 된다. 카카오스타일은 이후 자체 러너를 쓰게 됐지만 한계는 여전히 남는다고 덧붙인다.
- 커버리지는 코드의 어느 부분이 몇 번 실행됐는지까지 추적해 누락 지점을 짚어준다. PR 에 커버리지를 댓글로 남기는 액션도 쓸 수 있지만 샤딩과 함께 쓰면 설정이 복잡해진다.
왜 읽나스토리북은 있는데 자동 실행 환경이 없어 테스트가 방치된 프론트엔드 팀에게, jest 설정 항목과 CI 병렬화까지 매뉴얼처럼 따라갈 수 있게 정리한 글.