이 글은 Storybook의 공식 튜토리얼인 Design Systems for Developers를 학습하기 위해 작성한 시리즈의 일환으로, 오늘은 스토리북에서 지원하는 테스팅 종류와 방법 중 특히
시각적
/상호작용
/접근성
이라는 3가지 측면에서 테스트를 진행하는 방법에 대해 정리한 내용을 담아보았다.
프론트엔드에서 UI 테스팅은 사용자 인터페이스가 예상대로 작동하는지, 사용자의 기대와 일치하는지 확인하기 위한 목적으로 수행된다. 이를 통해 버그를 조기에 발견하고 사용자 경험을 개선하는데도 필수적이라고 부를 수 있다.
UI에 대해 테스트를 진행하는 방법과 유형에도 단위 테스트, 통합 테스트, 회귀 테스트와 같이 다양한 종류와 각 유형에 맞는 도구도 여럿 존재하는데, 오늘은 스토리북으로 구축하는 디자인 시스템이라는 주제에 맞게
1. 스토리북에서 제공하는 다양한 테스트 기능
2. 스토리북에서 테스트를 구성하는 법
을 중점으로 알아보고자 한다.
디자인 시스템을 구축하고 유지하는 과정에서, 발생할 수 있는 다양한 문제를 해결하기 위해 테스트를 적극 활용할 수 있다.
기본적으로 UI를 테스트하는 목적에는 코드 변경 시 발생할 수 있는 잠재적인 버그를 미리 감지하고 수정하기 위함 이라는 버그 예방의 측면이 있다.
디자인 시스템에서는 이에 더불어 컴포넌트의 시각적 상태
, 상호작용
, 접근성
을 위주로 테스트를 진행하여 전체적으로 일관성을 유지하고 품질을 보장하도록 만들 수 있다.
또한 지속적인 통합을 위해, 반복적이고 시간이 많이 소요되는 수동 검토 과정을 자동화
하여 개발 속도를 향상하는 데도 도움이 될 수 있다.
가능한 모든 케이스를 직접 검토하는 건 사실상 불가능에 가깝다
디자인 시스템에는 여러 가지 UI 컴포넌트들이 있다. 각 컴포넌트는 일련의 입력(props)에 대해 의도된 모습을 묘사하는 Story를 가지고 있으며, 최종 사용자의 브라우저나 각종 디바이스에서 렌더링된다.
하나의 컴포넌트만 놓고 보더라도 여러 가지 상태를 포함하고 있기 때문에, 이를 모두 관리한다는 건 '지속적이고 종종 비효율적인 노력이 필요함'을 뜻하는 Sisyphean task
란 단어에 빗대어 지기도 한다.
특히나 디자인 시스템이 성장하면서 모든 경우를 직접 재현하고 리뷰하는 것을 지속해 나가기 어렵기 때문에, 앞으로 있을 작업들을 줄이기 위해서라도 자동화된 테스트 설계의 중요성이 커진다.
모든 UI 요소에 테스트를 거치도록 한다는 건 비효율적일 수 있으며, 오히려 개발 속도를 저하시킬 우려가 있다. 따라서 테스트가 필요한 부분만 선별해 우선적으로 테스트를 하는 것도 중요하다.
그렇다면 테스트가 필요한 UI 컴포넌트에는 어떤 특성이 있을까?
주로 테스트를 고려하게 되는 대상은 다음과 같다.
이를 참고해 테스트의 효과를 극대화 하고 개발 하는데 있어서도 효율성을 유지해 보자.
디자인 시스템의 테스팅은 다양한 방법으로 진행될 수 있다. 다음은 주요 3가지 방법이다.
각각의 테스트가 서로 다른 측면을 다루기 때문에, 종합적으로 잘 활용해 앱의 품질과 신뢰성을 향상시킬 수 있다.
쉽고 포괄적인 테스트를 만들기 위한 스토리 작성의 모범사례 예시
Math.random()
이나 Date.now()
와 같은 랜덤하거나 상대적인 입력으로 인해 발생할 수 있는 변동성을 줄이기 위해, 컴포넌트를 일관되게 렌더링한다.그럼 지금부터 스토리북으로 구현한 디자인 시스템에 각종 테스트 기법을 어떻게 통합시켰는지 알아보자.
UI의 렌더링된 외관을 확인하는 것에 중점을 두는 테스트
각 UI 컴포넌트의 스크린샷을 캡처하고, 이전에 저장된 스크린샷이 있다면 이와 비교해 차이가 발견되면 알림을 통해 개발자에게 알려준다. 여기에는 레이아웃, 색상, 크기, 대비와 같은 시각적인 측면이 포함된다.
일반적으로 시각적 테스트 도구는 다음과 같은 기능을 제공한다.
크로매틱과 스토리북을 연동하면 기본적으로 시각적 테스트가 지원된다. 시각적 테스트가 활성화 되면 모든 스토리가 테스트 대상이 되어, Pull Request 생성 시 변경 사항에 대한 이미지가 캡처되고 이전 버전의 스크린샷과의 비교가 자동으로 수행된다.
크로매틱 UI를 통해 모든 변경 사항이 Accepted 되어야 Pull Request의 UI Tests
가 체크로 넘어가게 된다.
이를 활용해 수동으로 UI를 검토하는 시간을 절약할 수 있고, 디자인이 의도치 않게 변경되지는 않았는지도 쉽게 확인할 수 있다.
사용자 입력과 상호작용을 시뮬레이션 하여, 사용자 행동을 검증하기 위한 테스트
UI가 사용자 상호작용(키보드, 마우스 등)에 제대로 반응하는지 확인하는 데 중점을 두는 테스트 패턴이다.
시각적 테스트보다는 특히 상태 관리나 데이터 페칭 등 단순한 UI 렌더링을 넘어서는 컴포넌트의 복잡한 동작이 있을 때 유용하다.
스토리북의 play
함수를 사용해 컴포넌트와의 상호작용을 설정할 수 있다.
스토리북 브라우저 환경에서 테스트가 진행되므로, 컴포넌트를 개발하면서 동일한 환경에서 쉽게 디버깅 할 수 있다는 장점이 있다.
다음 예시는 Button 컴포넌트에서 play
함수와 @storybook/addon-interactions 애드온을 사용해, UI가 버튼 클릭을 제대로 처리하는 지 확인하는 과정을 담았다.
import { expect, fn, userEvent, within } from "@storybook/test";
// Other stories..
export const WithInteractions: Story = {
args: {
label: "Click",
onClick: fn(),
},
play: async ({ args, canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.click(canvas.getByRole("button"));
expect(args.onClick).toHaveBeenCalled();
},
};
play
: 상호작용 테스트를 정의하기 위한 함수. 스토리북이 버튼을 렌더링한 후 실행됨canvasElement
: 버튼이 렌더링된 DOM 요소를 나타냄within
: canvasElement
내에서 버튼 요소를 찾는데 사용userEvent.click
: 버튼을 클릭하는 사용자 사용작용을 시뮬레이션expect
: 버튼이 클릭되었을 때 onClick
이 제대로 호출되었는지 확인play
함수 내부에 정의된 단계들을 실행한다.디자인 시스템이 발전함에 따라, 모든 변경 사항을 수동으로 확인한다는 게 사실상 불가능할 수 있다. Storybook Test runner를 활용하면, 테스트 프로세스를 자동화하여 모든 상호작용 테스트를 실행하고 테스트에 통과하지 못한 스토리를 포착하는 것이 가능하다.
테스트 러너를 CI 구성에서 어떻게 활용할 수 있을지 로컬에서 먼저 체험해 보았다.
스토리북의 테스트 러너는 모든 스토리를 실행 가능한 테스트로 바꿔준다. 스토리북과 병렬로 실행되는 standalone utility로써, 설정을 위해 아래 과정을 따라야 한다.
// package.json
"scripts": {
"test-storybook": "test-storybook" // 추가
}
npm i -D @storybook/test-runner
npx playwright install
npm run test-storybook --watch
이렇게 테스트 러너를 활용하면 모든 스토리가 오류 없이 렌더링되는지, 실행 중에 모든 Assertions가 통과하는지 간단하게 확인할 수 있다.
위 과정을 로컬에서 매번 실행하는 것은 여전히 시간이 오래 걸리고 반복적인 작업일 수 있다. 따라서 CI 환경에서 테스트를 실행시키도록 지침에 따라 테스트 러너를 설정할 수 있다.
# .github/workflows/chromatic.yml
name: "Chromatic CI"
on: push
jobs:
interaction-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 18
- name: Install dependencies
run: yarn
- name: Install Playwright
run: npx playwright install --with-deps
- name: Build Storybook
run: yarn build-storybook --quiet
- name: Run Storybook tests
run: |
npx concurrently -k -s first -n "SB,TEST" -c "magenta,blue" \
"npx http-server storybook-static --port 6006 --silent" \
"npx wait-on tcp:127.0.0.1:6006 && yarn test-storybook --url http://127.0.0.1:6006"
visual-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install dependencies
run: yarn
- name: Run Chromatic
uses: chromaui/action@latest
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
interaction-tests
Job: 스토리북을 빌드한 다음 테스트 러너를 실행해, 실패한 테스트가 있으면 알려준다.visual-tests
Job: Chromatic을 실행해 컴포넌트의 시각적 상태를 확인한다.이렇게 실제 사용자의 행동을 시뮬레이션 해서 컴포넌트의 동작을 검증할 수 있다. 각종 다양한 상호작용 방식에 따른 버그를 조기에 발견하는 데 도움이 될 것 같다.
모든 사람들이 앱을 이해하고 탐색하며 상호작용 할 수 있는지 확인하기 위한 테스트
접근성 테스트는 웹 컨텐츠 접근성 가이드라인(WCAG)과 같은 표준을 준수하며 앱이 다양한 사용자 요구를 충족하는지 평가하는 것과 같은 행위를 일컫는다.
Tab
키와 같이 키보드를 통해 사이트를 탐색할 수 있는지 확인한다. 모든 인터랙티브 요소들이 키보드로 접근 가능하고 순서가 논리적인지 확인한다.a11y 애드온을 사용해 스토리의 접근성에 대해 확인할 수 있다.
npm i -D @storybook/addon-a11y
// .storybook/main.ts
const config: StorybookConfig = {
addons: [
"@storybook/addon-a11y" /* 추가 */
],
};
export default config;
위와 같은 설정을 마친 뒤 스토리북에 접속해 보면, 애드온 패널에 "Accessibility" 라는 새로운 탭이 보인다. 해당 탭을 통해서 개발 중에 접근성 문제에 대해 포착하고 수정하기 위한 힌트를 얻을 수 있다.
사진에서 보이는 위반 사항(Violations)에서는 "Destructive" 버튼의 배경 색과 전경 색(일반적으로 텍스트 색상)이 가독성을 보장할 만큼 충분히 대비되지 않다는 내용을 알려주고 있다. (참고: MDN - Color contrast) 따라서 background-color를 적절히 조정하여 해당 문제를 해결할 수 있었다.
이처럼 a11y 애드온은 여러 접근성 문제에 대한 명확한 설명과 해결 지침을 제공하기 때문에, 이를 잘 지킨다면 모든 사람을 포용하는 웹사이트를 만드는 데 도움이 될 수 있다.
추가로, 접근성 테스트를 자동화 하기 위해 테스트 러너와 통합하는 지침을 따를 수 있다. 그런데 자동화된 테스트가 일반적인 접근성 문제 파악엔 도움이 되지만, 모든 접근성 문제를 잡아내지는 못할 수 있어 수동 검토가 필요해 질 수도 있어 주의해야 한다.
지금까지 스토리북을 활용한 다양한 UI 테스팅 방법(시각적, 상호작용, 접근성 테스트)에 대해 다뤄보았는데, 이를 통해 컴포넌트의 일관성을 유지하고 버그를 예방하며 접근성을 보장하기 위한 여러 방법에 대해 알 수 있었다. 그중에서도 상호작용 테스트에 대한 분량이 특히나 길었는데, 아무래도 애플리케이션에서 발생할 수 있는 다양한 상호작용 유형이 존재하고, 복잡한 로직과 상태 관리를 필요로 하는 부분이다 보니 그랬던 것 같다.
이제 다음 편에서는 문서화를 통해 디자인 시스템 채택을 가속화하는 방법에 대해 알아볼 예정이다. Storybook의 Docs를 제대로 활용해 다양한 이해관계자들에게 잘 테스트 된 디자인 시스템의 UI 컴포넌트들을 최대한 활용할 수 있도록 가르치는 방법에 대해 알아볼 것이다.