이제 프로젝트는 앱 런칭을 앞두고 QA를 진행하고있다.
이렇게 QA를 진행하다보니 알게된 것은 생각보다 다양한 기기에서 테스트하다보니 UI가 깨지는게 많다는 점이었다.
그러나 의외로 UI 깨지는 것을 쉽게 해결하기가 쉽지않았다.
아래와 같은 이유들 때문이었다.
특정 사이즈에서만 깨진다.
아래와 같이 화면이 좁아지면 UI가 깨진 다던가... 문제가 있었다.
반응형 사이즈 테스트를 해볼 수가 없다.
서버 API호출을 줄여 운영 비용을 줄이기 위해 네이티브 DB를 사용하기로 결정했었다.
사용자가 쓴 글, 좋아요 누른 글 등을 앱 내부 DB에 저장하게 하고, 로그인시 서버와 1회 통신을 통해 동기화하는 형태로 서비스를 구성했다.
이렇게 앱 내부 DB를 사용하는 곳이 늘어나다보니 이제는 브라우저로 배포된 서비스 URL을 열었을때는 제대로 앱이 기능하지 않았다.
사실 애초에 로그인시 들어오는 토큰을 webview로 전송해주기때문에 배포 URL로 접근하면 로딩화면만 보이게 된다.
이러면 아예 디버그가 안된다는 문제가 있다. 이는 chrome://inspect를 통해 해결했다.
USB디버깅을 통해 안드로이드에서 열린 chrome 화면을 분석할 수 있다.
하지만 이게 정말 모바일 뷰를 미러링하는 기능에 가까워서 화면 리사이징은 되지않는다.
따라서 반응형 UI 테스트를 해볼 방법이 없었다.
디버깅을 위한 대기시간이 매우 매우 길다.
안드로이드 기기에서 로컬 웹서버를 웹뷰로 열고, 이걸 테스트하려면 아래와 같은 과정을 거쳐야한다.
- 모노레포에 접근해서 npm run dev를 통해 4가지 프로젝트에 대한 로컬 서버를 띄운다.
- reactNative 프로젝트에 접근해서 WebView uri를 열린 로컬 서버 주소로 변경한다.
- usb를 안드로이드 기기에 연결한다.
- npm run start를 통해 reactNative를 실행시킨다.
위의 일련의 과정을 수행하는데에 매우 많은 시간이 소모되었다.
특히 4번은 첫 빌드하는데 10분가량의 시간이 걸린다. 위 과정을 매 디버그마다 겪으며 우리 팀 프론트엔드 개발자는 피로감을 느끼게 되었다.
StoryBook
그래서 어떻게 위의 과정을 거치지 않고 컴포넌트를 시각화하고 테스트해볼까 고민하다가 이쪽으로 가장 유명하다는 홍박사님을 storybook의 도입을 고려하게 되었다.
이전까지는 항상 " 뭐 이렇게 까지 해야해? " 라는 생각이 있었는데, 이렇게 직접 UI문제를 마주하고, 일관된 사용자 경험을 제공할 수 없겠다는 문제가 예상되자 스토리북이 절실해졌다.
시작하기
프로젝트 루트 경로에 가서 아래 명령어를 실행시키면 알아서 기본 세팅을 다해준다.
npx sb init
추가 세팅하기
storybook을 도입하자 생긴 가장 큰 문제점이 우리 프로젝트는 디자인시스템이 따로 없고, 아토믹 디자인도 사용하지 않았다. 그래서 각 컴포넌트에서 외부 라이브러리의 훅을 사용하는 경우가 빈번했고, 이에 따라 추가 설정이 필요해졌다.
Context Provider 세팅하기
Context Provider로 감싸진 상태에서 렌더링 되는 경우에 문제가 발생했다.
대표적인 예시로 우리 프로젝트는 react프로젝트라 react-router-dom을 사용했다.
이 라이브러리는 Provider를 통해 구현되었기때문에 useNavigate, useLocation등 이 라이브러리에서 제공되는 훅들을 사용하려면 RouterProvider로 감싸주어야한다.
이는 decorators라는 옵션을 통해 설정할 수 있다.
예를들어 ToastProvider를 사용하고 싶은 경우 SomeComponent.storeis.ts에 아래와 같이 작성하면된다.
const meta = {
...
decorators: [
(Story) => (
<ToastProvider>
<Story />
</ToastProvider>
),
],
...
} satisfies Meta<typeof Person>;
export default meta;
그런데 react-router-dom 의 Provider는 라우팅 설정이 된 객체를 router value로 주어야한다.
이걸 매번 설정하기 귀찮고, 컴포넌트 하나를 테스트하자고 이걸 다 설정할 필요도 없다.
내가 필요한건 그냥 문제없이 라이브러리 내부의 훅이 수행되는 것이다.
storybook-addon-remix-react-router
내부 훅이 잘 작동하게 해주는 addon이 있다. storybook-addon-remix-react-router이다.
이걸 사용하면 복잡하게 설정해줄 필요없이 해당 라이브러리의 withRouter만 적어주면된다.
import { withRouter } from 'storybook-addon-remix-react-router';
const meta = {
...
decorators: [withRouter],
...
}
배포하기
우리는 turborepo를 활용하여 4개의 react 프로젝트를 구성했다.
물론 내부 package를 통해 공통 컴포넌트를 구성하긴했지만, 스토리북을 도입한 이유는 네이티브 기기없이 UI테스팅을 하기 위함이었으므로 각 프로젝트마다 storybook을 구성해주었다.
이제는 이 storybook을 배포해서 디자이너/기획자분들도 어렵지 않게 컴포넌트를 직접 보고, UI 엣지 케이스를 테스팅할 수 있게 있게 만들고 싶었다.
배포 자체는 아래 url을 참고하면 된다.
https://storybook.js.org/tutorials/intro-to-storybook/react/ko/deploy/
CI구성에서 생긴 문제점 (secrets 변수를 가져오지 못하는 문제점)
pull request시에 storybook을 빌드해서 배포하고, chromui를 통해 이전 빌드와 시각적으로 달라진 부분을 확인하는 형태로 세팅을 하려고 했다.
하지만 이게 죽었다 깨어나도 secrets의 변수를 가져오지 못하는것이었다.
그러다가 엄청난걸 찾았다.
upstream 레포지토리에 pull_request를 fork된 레포지토리에서 쓴 경우 github actions은 untrusted mode로 돌아가서 secrets를 못 가져온다는 것이다.
나의 4시간은 날아갔다.
push이벤트로 변경했고, merge시에 비교할 수 있도록 변경했다.
이제 네이티브 기기 없이도 시각적 테스트를 할 수 있고, 더불어 dev에 머지될때마다 자동으로 배포되어 팀과 함께 UI를 확인할 수있다!