#3 React + Storybook + puppeteer + jest 개발환경 구축하기

Setup @storybook/addon-storyshots

vito

🔖 목차

⛳ 목표

@storybook/addon-storyshots 사용하기

@storybook/addon-storyshots
storybook에서 출력하는 html에 대해 이전 html과 비교하여 변경사항을 보여주는 storybook addon (storybook + jest + react-renderer)

1. Jest 설정

step 1. jest 설치

npm install --save-dev jest

위 명령어로 설치후 package.json의 script에 “test”: “jest” 를 추가해주세요.

step 2. jest에서 babel사용

babel-jest 를 사용하면 jest 실행시 babel을 사용하여 transform을 할수 있답니다.

npm install --save-dev babel-jest

babel-jest를 설치후 jest config 파일을 다음과 같이 추가합니다.

module.exports = {
transform: {
'^.+\\.jsx?$': 'babel-jest',
},
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.jsx?$',
};

step 3. jest 전용 babel 설정파일 사용하기

우리는 아래에서 이야기할 추가적인 이슈들로 babel.config.js 파일을 사용하지 않고 jest 전용 babel 설정파일을 사용하기 위해서, 아래와 같이 수정해야 합니다.

const path = require('path');module.exports = {
transform: {
'^.+\\.jsx?$': path.resolve(__dirname, './jest.config.babel.js'),
},
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.jsx?$',
};

그리고 jest.config.babel.js 파일을 아래와 같이 작성하고

const babelJest = require('babel-jest');
const babelConfigJest = require('./babel.config.jest');
module.exports = babelJest.createTransformer(babelConfigJest);

마지막으로 babel-merge을 설치하고 babel.config.jest 파일을 아래와 같이 작성하면 jest의 babel 설정파일을 따로 사용할수 있답니다.

npm install babel-merge

const mrege = require('babel-merge');
const babelConfig = require('./babel.config');
module.exports = mrege(babelConfig, {});

Jest의 babel 설정파일을 따로 사용하는데 필요이상의 파일과 내용을 추가하는 느낌인데요…
같은 생각을 하신 분들의 덕택으로 더 편리하게 설정 가능할 예정이랍니다 😆
https://github.com/facebook/jest/pull/7288

아직은 위와 같은 방법으로 설정할수 없지만, merge까지 되었으므로 곧 사용가능하겠지요? (19.07.14)

Typescript
babel7로 typescript를 사용중일때는 아래와 같이 설정하고, 이후 설정파일 수정시 확장자만 ts, tsx를 지원하도록 수정하면 됩니다.

const mrege = require('babel-merge');
const babelConfig = require('./babel.config');
module.exports = mrege(babelConfig, {
presets: [
[
'@babel/preset-env',{
useBuiltIns: false,
modules: 'cjs',
},
],
],
});

2. Storybook 코드를 Jest 에서 실행할때 이슈 처리

Storybook은 Webpack + babel 환경에서 돌아갑니다. 하지만 Jest는 Babel 만 사용하여 transfrom 하는데요. 이런 번들링 환경 차이는 webpack 에서 지원하지만 일반적인 babel 환경에서는 지원하지 않는 기능에 대한 이슈가 생기게 됩니다.

  • alias path
  • dynamic import(require.context)
  • javascript 파일 이외의 파일을 import 하기 (image, css)

일반적으로 위 세가지 이슈가 발생하게 되는데요. 아래에서 이 이슈들을 해결하는 방법을 적어두었습니다.

issue 01. Webpack alias path 를 babel에서 지원하기

babel-plugin-webpack-alias 를 사용하여 이슈를 해결합니다.

npm install --save-dev babel-plugin-webpack-alias

babel.config.jest.js 파일 수정하여 babel-plugin-webpack-alias 적용.

const path = require('path');
const mrege = require('babel-merge');
const babelConfig = require('./babel.config');
const webpackConfigPath =
path.resolve(__dirname, './webpack.config.common.js');
module.exports = mrege(babelConfig, {
plugins: [['babel-plugin-webpack-alias', {
config: webpackConfigPath
}]],
});

이제 babel(jest 환경) 에서 webpack alias path 를 사용할수 있네요! 🥰

issue 02. dynamic import(require.context)를 babel에서 지원하기

위와 비슷하게 plugin으로 해결이 가능합니다. babel-plugin-require-context-hook 을 설치해줍니다.

npm install --save-dev babel-plugin-require-context-hook

babel.config.jest.js 파일 수정하여 babel-plugin-require-context-hook를 적용.

// ...module.exports = mrege(babelConfig, {
plugins: ['require-context-hook', /* ... */],
});

jest.config.js 파일에서 setupFilesAfterEnv 설정.

// ...module.exports = {
// ...
setupFilesAfterEnv: [path.resolve(ROOT, './jest.setup.js')],
};

그리고 jest.setup.js 파일을 추가하고 require.context를 등록하는 코드를 작성합니다.

import registerRequireContextHook from 'babel-plugin-require-context-hook/register';registerRequireContextHook();

이제 babel(jest 환경)에서 context.require 문법을 사용할수 있답니다. 🥰

issue 03. jset에서 javascript 파일 이외의 파일을 mock import 하기

mock module 을 사용하는 방식으로 해결이 가능합니다 😮

jest.config.js 파일에서 이미지파일과 css 파일을 import 시 mock 파일을 가져오도록 설정합니다.

// ...const mockModulePath = 
path.resolve(ROOT, './__mocks__/fileMock.js');
module.exports = {
// ...
moduleNameMapper: {
'\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': mockModulePath,
'\\.(css|scss)$': path.resolve(ROOT, './__mocks__/fileMock.js'),
},
};

그리고 ./__mocks__/fileMock.js 파일을 아래 내용으로 추가합니다.

module.exports = '';

이제 이미지파일과 css, scss 파일을 import 할때는 mock module로 import 하여 code transfrom을 성공하게 됩니다. wow!! 🥰

추가로 css-modules 를 사용한다면 jest-css-modules 라는 것을 사용하는 방법도 있습니다만, 시도는 안해보았어요 😋 ㅎㅎ

3. @storybook/addon-storyshots 설정

@storybook/addon-storyshots 를 사용할 준비는 모두 끝났습니다.
마지막으로 @storybook/addon-storyshots 를 설정해보시죠,

npm install --save-dev @storybook/addon-storyshots

그리고 test 코드를 작성해줍니다. (test/storyshots.test.js)

import initStoryshots from '@storybook/addon-storyshots';initStoryshots();

🤗 Complete!

테스트 실행해보기!

이제 npm run test (jest) 를 실행하면 다음과 같이 storybook의 결과(html)물과 스냅샷(이전 html 결과)을 비교하는 테스트를 실행하게 됩니다. 처음 실행하므로 스냅샷만 생성하게 되겠지요.

다음은 Header 컴포넌트에 내용을 추가후 테스트 코드를 돌려보았습니다.

여기서 u 키를 누르면 스냅샷을 업데이트 하게 됩니다.

지금까지의 코드는 여기서 볼수 있어요!

마지막으로 Storybook의 결과물를 스크린샷하여 이전 스크린샷과 diff를 비교하는 환경을 다음 글에서 세팅해보시죠! 🏃‍♀️🏃‍

위에서 이슈를 다 해결했기 때문에 초기 설정만 하면 된답니다 😇

Setup @storybook/addon-storyshots-puppeteer

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade