React | Vue | Angular | Web Components | 그 외(More)
스토리북은 Cypress나 Playwright 같은 외부 테스트 프레임워크와도 아주 매끄럽게 연결됩니다. 덕분에 포괄적이고 든든한 테스트 환경을 구축할 수 있죠. 컴포넌트 스토리 포맷(CSF)을 활용하면, 개발자들은 스토리북 환경 안에 있는 개별 컴포넌트들에 대해 사용자의 행동을 시뮬레이션하고 동작을 검증하는 테스트 케이스를 쉽게 작성할 수 있습니다. 결과적으로 다양한 시나리오에 맞춰 컴포넌트의 기능, 반응성, 시각적 요소들을 철저하게 테스트할 수 있어 훨씬 더 튼튼하고 믿을 수 있는 애플리케이션을 만들 수 있게 됩니다.
Cypress는 사용자의 행동을 그대로 시뮬레이션해서 애플리케이션 전체를 훑어볼 수 있게 해주는 아주 강력한 E2E(End-to-End) 테스트 프레임워크입니다. 스토리들이 컴포넌트 스토리 포맷(CSF)으로 작성되어 있다면, 이 스토리들을 Cypress 환경 안에서도 렌더링하고 재사용할 수 있어요!
Cypress와 스토리북을 함께 써서 로그인 컴포넌트의 입력값 유효성을 검증하는 E2E 테스트를 작성해 보겠습니다. 예를 들어, 아래와 같은 스토리가 준비되어 있다고 가정해 볼게요:
// Replace your-framework with the framework you are using, e.g. react-vite, nextjs, nextjs-vite, etc.
import type { Meta, StoryObj } from '@storybook/your-framework';
import { expect } from 'storybook/test';
import { LoginForm } from './LoginForm';
const meta = {
component: LoginForm,
} satisfies Meta<typeof LoginForm>;
export default meta;
type Story = StoryObj<typeof meta>;
export const EmptyForm: Story = {};
export const FilledForm: Story = {
play: async ({ canvas, userEvent }) => {
// 👇 컴포넌트와의 상호작용(interactions)을 시뮬레이션합니다.
await userEvent.type(canvas.getByTestId('email'), 'email@provider.com');
await userEvent.type(canvas.getByTestId('password'), 'a-random-password');
// Actions 패널에 로그를 남기는 방법이 궁금하시다면 아래 링크를 참고하세요:
// [https://storybook.js.org/docs/essentials/actions#automatically-matching-args](https://storybook.js.org/docs/essentials/actions#automatically-matching-args)
await userEvent.click(canvas.getByRole('button'));
// 👇 DOM 구조가 예상대로인지 검증(Assert)합니다.
await expect(
canvas.getByText(
'Everything is perfect. Your account is ready and we should probably get you started!',
),
).toBeInTheDocument();
},
};
💡 잠깐! 여기서 play 함수는 스토리가 화면에 렌더링된 직후에 실행되는 작은 코드 조각들입니다. 이걸 활용하면 스토리 안에서 일어나는 여러 상호작용들을 순차적으로 실행해 볼 수 있죠.
자, 이제 Cypress를 열고 이 스토리를 활용하는 테스트 코드를 작성해 볼까요?
// tests/login-form/login.spec.js
/// <reference types="cypress" />
describe('Login Form', () => {
it('Should contain valid login information', () => {
// 스토리북의 격리된 iframe 주소로 바로 접속합니다!
cy.visit('/iframe.html?id=components-login-form--example');
cy.get('#login-form').within(() => {
cy.log('**enter the email**');
cy.get('#email').should('have.value', 'email@provider.com');
cy.log('**enter password**');
cy.get('#password').should('have.value', 'a-random-password');
});
});
});
Cypress가 이 테스트를 실행하면, 먼저 스토리북의 격리된 iframe을 엽니다. 그리고 스토리에서 시뮬레이션했던 입력값들이 실제로 화면에 잘 채워져 있는지 꼼꼼하게 확인(check)하게 됩니다.
Playwright는 마이크로소프트에서 만든 브라우저 자동화 도구이자 E2E 테스트 프레임워크입니다. 다양한 브라우저 동시 지원(cross-browser), 모바일 디바이스 에뮬레이션을 통한 모바일 환경 테스트, 그리고 화면을 띄우지 않고 빠르게 테스트하는 헤드리스(headless) 테스트까지 지원하는 만능 도구죠. Cypress와 마찬가지로, 컴포넌트 스토리 포맷(CSF)으로 작성된 스토리의 개별 export(즉, 각각의 스토리)들을 Playwright 테스트 환경에서도 불러와 렌더링할 수 있습니다.
이번에도 로그인 폼의 유효성을 검사하는 실제 사용자 흐름(user flow)을 Playwright로 테스트해 보겠습니다. 위에서 작성한 LoginForm 스토리를 이번엔 Playwright에 넘겨볼게요:
// tests/login-form/login.spec.js
import { test, expect } from '@playwright/test';
test('Login Form inputs', async ({ page }) => {
// 스토리북의 격리된 iframe URL로 이동합니다.
await page.goto('http://localhost:6006/iframe.html?id=components-login-form--example');
// 입력된 값들을 가져옵니다.
const email = await page.inputValue('#email');
const password = await page.inputValue('#password');
// 값이 우리가 스토리에 적어둔 것과 일치하는지 검증합니다.
await expect(email).toBe('email@provider.com');
await expect(password).toBe('a-random-password');
});
Playwright를 훅! 하고 실행하면, 새로운 브라우저 창이 열리면서 스토리북의 격리된 iframe 페이지로 접속합니다. 그런 다음 입력칸의 값들이 우리가 지정한 값과 정확히 일치하는지 확인하고, 그 결과를 터미널 창에 멋지게 띄워줍니다.
더 유용한 테스팅 관련 자료들