(3) Storybook 으로 구축하는 Design System – UI 테스팅

시소·2024년 5월 19일
0

Design System

목록 보기
3/5
post-thumbnail

이 글은 Storybook의 공식 튜토리얼인 Design Systems for Developers를 학습하기 위해 작성한 시리즈의 일환으로, 오늘은 스토리북에서 지원하는 테스팅 종류와 방법 중 특히 시각적 / 상호작용 / 접근성 이라는 3가지 측면에서 테스트를 진행하는 방법에 대해 정리한 내용을 담아보았다.

들어가며

프론트엔드에서 UI 테스팅은 사용자 인터페이스가 예상대로 작동하는지, 사용자의 기대와 일치하는지 확인하기 위한 목적으로 수행된다. 이를 통해 버그를 조기에 발견하고 사용자 경험을 개선하는데도 필수적이라고 부를 수 있다.

UI에 대해 테스트를 진행하는 방법과 유형에도 단위 테스트, 통합 테스트, 회귀 테스트와 같이 다양한 종류와 각 유형에 맞는 도구도 여럿 존재하는데, 오늘은 스토리북으로 구축하는 디자인 시스템이라는 주제에 맞게

1. 스토리북에서 제공하는 다양한 테스트 기능 
2. 스토리북에서 테스트를 구성하는 법

을 중점으로 알아보고자 한다.


Design System과 테스팅

디자인 시스템을 구축하고 유지하는 과정에서, 발생할 수 있는 다양한 문제를 해결하기 위해 테스트를 적극 활용할 수 있다.

테스팅 목적

기본적으로 UI를 테스트하는 목적에는 코드 변경 시 발생할 수 있는 잠재적인 버그를 미리 감지하고 수정하기 위함 이라는 버그 예방의 측면이 있다.

디자인 시스템에서는 이에 더불어 컴포넌트의 시각적 상태, 상호작용, 접근성을 위주로 테스트를 진행하여 전체적으로 일관성을 유지하고 품질을 보장하도록 만들 수 있다.

또한 지속적인 통합을 위해, 반복적이고 시간이 많이 소요되는 수동 검토 과정을 자동화 하여 개발 속도를 향상하는 데도 도움이 될 수 있다.

테스트 자동화의 중요성

가능한 모든 케이스를 직접 검토하는 건 사실상 불가능에 가깝다

디자인 시스템에는 여러 가지 UI 컴포넌트들이 있다. 각 컴포넌트는 일련의 입력(props)에 대해 의도된 모습을 묘사하는 Story를 가지고 있으며, 최종 사용자의 브라우저나 각종 디바이스에서 렌더링된다.

하나의 컴포넌트만 놓고 보더라도 여러 가지 상태를 포함하고 있기 때문에, 이를 모두 관리한다는 건 '지속적이고 종종 비효율적인 노력이 필요함'을 뜻하는 Sisyphean task란 단어에 빗대어 지기도 한다.

특히나 디자인 시스템이 성장하면서 모든 경우를 직접 재현하고 리뷰하는 것을 지속해 나가기 어렵기 때문에, 앞으로 있을 작업들을 줄이기 위해서라도 자동화된 테스트 설계의 중요성이 커진다.

테스팅 대상

모든 UI 요소에 테스트를 거치도록 한다는 건 비효율적일 수 있으며, 오히려 개발 속도를 저하시킬 우려가 있다. 따라서 테스트가 필요한 부분만 선별해 우선적으로 테스트를 하는 것도 중요하다.

그렇다면 테스트가 필요한 UI 컴포넌트에는 어떤 특성이 있을까?
주로 테스트를 고려하게 되는 대상은 다음과 같다.

  • UI 컴포넌트: Button, Input, Modal 과 같은 개별 UI 요소가 시각적으로 제대로 렌더링 되는지?
  • 컴포넌트 상태 관리: 각 컴포넌트가 다양한 상태(활성화, 비활성화, 오류 등)에서 제대로 동작하는지?
  • 사용자 상호작용: 사용자 상호작용(클릭, 키 입력 등)에 대해 기대하는 대로 동작하는지?
  • 접근성 요구사항: 컴포넌트가 접근성 표준(WCAG 등)을 준수하는지?
  • 통합 상태: 여러 컴포넌트가 결합되어 동작할 때 올바르게 동작하는지?
  • 데이터 의존성: 외부 데이터에 의존하면서도 데이터를 정상적으로 표시하는지?

이를 참고해 테스트의 효과를 극대화 하고 개발 하는데 있어서도 효율성을 유지해 보자.


테스팅 진행 방법

디자인 시스템의 테스팅은 다양한 방법으로 진행될 수 있다. 다음은 주요 3가지 방법이다.

  • 시각적 테스트: 컴포넌트의 외관을 확인하고 시각적인 변화를 감지하기 위함
  • 상호작용 테스트: 사용자 상호작용에 대한 컴포넌트의 반응을 검증하기 위함
  • 접근성 테스트: 컴포넌트가 접근성 표준을 준수하는지 확인하기 위함

각각의 테스트가 서로 다른 측면을 다루기 때문에, 종합적으로 잘 활용해 앱의 품질과 신뢰성을 향상시킬 수 있다.


테스트 준비 시 모범사례와 주의사항

쉽고 포괄적인 테스트를 만들기 위한 스토리 작성의 모범사례 예시
  1. 지원되는 컴포넌트 상태를 각각 스토리로 명확히 표현하여, 어떤 입력 조합이 특정 상태를 유발하는지 분명히 해야 한다. (지원되지 않는 상태에 대해서는 과감하게 제외해 혼란을 줄이자)
  2. Math.random() 이나 Date.now() 와 같은 랜덤하거나 상대적인 입력으로 인해 발생할 수 있는 변동성을 줄이기 위해, 컴포넌트를 일관되게 렌더링한다.
  3. 가장 바람직한 스토리는 컴포넌트가 실제 상황에서 겪을 수 있는 모든 상태를 시각적으로 보여준다.

그럼 지금부터 스토리북으로 구현한 디자인 시스템에 각종 테스트 기법을 어떻게 통합시켰는지 알아보자.


Storybook에서 테스팅 방법

시각적 테스트 (Visual test)

UI의 렌더링된 외관을 확인하는 것에 중점을 두는 테스트

각 UI 컴포넌트의 스크린샷을 캡처하고, 이전에 저장된 스크린샷이 있다면 이와 비교해 차이가 발견되면 알림을 통해 개발자에게 알려준다. 여기에는 레이아웃, 색상, 크기, 대비와 같은 시각적인 측면이 포함된다.

시각적 테스트의 주요 단계

일반적으로 시각적 테스트 도구는 다음과 같은 기능을 제공한다.

  1. 일관된 브라우저 환경에서, 모든 UI 컴포넌트의 이미지를 캡처한다.
  2. 새로운 스크린샷은 기존 스크린샷(이전 테스트에서 올바르게 렌더링 된 이미지)과 자동으로 비교된다.
  3. 이전과 비교해 시각적으로 차이가 발견되면 해당 차이에 대한 알림을 통해 UI 컴포넌트가 예상과 다르게 변경되지는 않았는지 식별하는 데 도움이 된다.

Storybook + Chromatic 내장 도구 활용

크로매틱과 스토리북을 연동하면 기본적으로 시각적 테스트가 지원된다. 시각적 테스트가 활성화 되면 모든 스토리가 테스트 대상이 되어, Pull Request 생성 시 변경 사항에 대한 이미지가 캡처되고 이전 버전의 스크린샷과의 비교가 자동으로 수행된다.

크로매틱 UI를 통해 모든 변경 사항이 Accepted 되어야 Pull Request의 UI Tests가 체크로 넘어가게 된다.

이를 활용해 수동으로 UI를 검토하는 시간을 절약할 수 있고, 디자인이 의도치 않게 변경되지는 않았는지도 쉽게 확인할 수 있다.


상호작용 테스트 (Interaction test)

 사용자 입력과 상호작용을 시뮬레이션 하여, 사용자 행동을 검증하기 위한 테스트

UI가 사용자 상호작용(키보드, 마우스 등)에 제대로 반응하는지 확인하는 데 중점을 두는 테스트 패턴이다.
시각적 테스트보다는 특히 상태 관리나 데이터 페칭 등 단순한 UI 렌더링을 넘어서는 컴포넌트의 복잡한 동작이 있을 때 유용하다.

상호작용 테스트의 주요 단계

  1. Mock 데이터 제공: 테스트 환경에서 일관된 조건을 제공하기 위해, 테스트 설정에 필요한 데이터나 상태를 Mocking 한다.
  2. 사용자 상호작용 시뮬레이션: 실제 사용자의 상호작용을 자동으로 수행한다. (Ex: 버튼 클릭, 입력 필드에 텍스트 입력, 드롭다운 선택 등)
  3. UI 변경 검증: 사용자 상호작용 후, UI가 예상대로 변경되었는지 검증한다. (Ex: 버튼 클릭 이후 특정 텍스트가 나타나는지, 입력 필드에 입력한 값이 제대로 반영되는지 등)

Storybook 내장 도구 활용

스토리북의 play 함수를 사용해 컴포넌트와의 상호작용을 설정할 수 있다.
스토리북 브라우저 환경에서 테스트가 진행되므로, 컴포넌트를 개발하면서 동일한 환경에서 쉽게 디버깅 할 수 있다는 장점이 있다.

다음 예시는 Button 컴포넌트에서 play 함수와 @storybook/addon-interactions 애드온을 사용해, UI가 버튼 클릭을 제대로 처리하는 지 확인하는 과정을 담았다.

src/stories/Button.stories.tsx
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 함수 내부에 정의된 단계들을 실행한다.
  • "Interactions" 패널을 클릭해 각 상호작용에 대해 일지 중지, 재개, 되감기, 단계별 실행 등을 명령할 수 있다.

테스트 러너를 활용한 자동화

디자인 시스템이 발전함에 따라, 모든 변경 사항을 수동으로 확인한다는 게 사실상 불가능할 수 있다. Storybook Test runner를 활용하면, 테스트 프로세스를 자동화하여 모든 상호작용 테스트를 실행하고 테스트에 통과하지 못한 스토리를 포착하는 것이 가능하다.

Example in local

테스트 러너를 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가 통과하는지 간단하게 확인할 수 있다.

Set up for CI

위 과정을 로컬에서 매번 실행하는 것은 여전히 시간이 오래 걸리고 반복적인 작업일 수 있다. 따라서 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을 실행해 컴포넌트의 시각적 상태를 확인한다.
  • (참고: [Bug]: CI hangs on node 18)

이렇게 실제 사용자의 행동을 시뮬레이션 해서 컴포넌트의 동작을 검증할 수 있다. 각종 다양한 상호작용 방식에 따른 버그를 조기에 발견하는 데 도움이 될 것 같다.


접근성 테스트 (Accessibility test)

모든 사람들이 앱을 이해하고 탐색하며 상호작용 할 수 있는지 확인하기 위한 테스트

접근성 테스트는 웹 컨텐츠 접근성 가이드라인(WCAG)과 같은 표준을 준수하며 앱이 다양한 사용자 요구를 충족하는지 평가하는 것과 같은 행위를 일컫는다.

접근성 테스트가 중요한 이유

  • 포용성: 다양한 장애를 가진 사람들이 디지털 컨텐츠에 접근할 수 있도록 해 포용적인 사용자 경험을 제공할 수 있다.
  • 법적 준수: 여러 국가에서는 접근성 표준을 준수하는 것이 법적으로 요구되기도 한다.
  • 사용자 만족도: 접근성이 향상되면 모든 사용자가 더 쉽게 컨텐츠에 접근하고 상호작용 할 수 있게 되어 만족도가 향상된다.

접근성 테스트 기준 예시

  • 키보드 네비게이션 테스트: Tab 키와 같이 키보드를 통해 사이트를 탐색할 수 있는지 확인한다. 모든 인터랙티브 요소들이 키보드로 접근 가능하고 순서가 논리적인지 확인한다.
  • 스크린 리더 테스트: 스크린 리더를 사용해 컨텐츠를 읽을 수 있는지 확인한다.
  • 색상 대비 검사: 텍스트와 배경 색상의 대비를 검사해 시각 장애가 있는 사용자들도 쉽게 컨텐츠를 읽기 쉽도록 한다.

Storybook a11y 애드온 활용

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 컴포넌트들을 최대한 활용할 수 있도록 가르치는 방법에 대해 알아볼 것이다.

profile
배우고 익힌 것을 나만의 언어로 정리하는 공간 ..🛝

0개의 댓글