React+Cypress+StorybookでVisualRegressionTestする
はじめに
React+CypressでVisualRegressionを実現するのにやったこと
環境構築
react/storybook導入
npx create-react-app my-app npx -p @storybook/cli sb init
Cypress導入
yarn add cypress @testing-library/cypress -D // 不要なテストを削除 rm -rf cypress/integration/examples
Storybookのpreview-iframeを取得
Storybookのiframeを取得する
cypress/support/command.js
import '@testing-library/cypress/add-commands'; Cypress.Commands.add('getIframeBody', () => { cy.log('getIframeBody'); return cy .get('#storybook-preview-iframe') .its('0.contentDocument.body').should('not.be.empty') .then((body) => cy.wrap(body)) });
Cypress-VisualRegressionモジュールを追加
良さげだったのでこちらを利用させていただいた https://www.npmjs.com/package/cypress-visual-regression
yarn add cypress-visual-regression -D
設定を追加する
cypress/support/command.js
const compareSnapshotCommand = require('cypress-visual-regression/dist/command'); compareSnapshotCommand();
cypress/plugin/index.js
const getCompareSnapshotsPlugin = require('cypress-visual-regression/dist/plugin'); module.exports = (on) => { getCompareSnapshotsPlugin(on); };
cypress.json
{ "screenshotsFolder": "./cypress/snapshots/actual", "trashAssetsBeforeRuns": true }
テスト用コンポーネント準備
Storyookのデフォルトコンポーネントを利用
src/stories/Button.js
export const Button = ({ primary, backgroundColor, size, label, ...props }) => { const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary'; const [buttonLabel, setLabel] = React.useState(label); const onClick = () => { setLabel("hoge"); } return ( <button type="button" className={['storybook-button', `storybook-button--${size}`, mode].join(' ')} style={backgroundColor && { backgroundColor }} data-testid="button" {...props} onClick={onClick} > {buttonLabel} </button> ); };
buttonのテストを追加
cypress/integration/button_spec.js
describe('Button Component', () => { beforeEach(() => { cy.visit('http://localhost:6006/?path=/story/example-button--primary'); }); it('Button Click', () => { cy.getIframeBody().findByTestId('button').should('have.text', 'Button'); cy.getIframeBody().findByTestId('button').click().should('have.text', 'hoge'); }); it('should display the Button correctly', () => { cy.getIframeBody().findByTestId('button').contains('Button'); cy.compareSnapshot('button'); }); });
PackageにScriptを追加
package.json
"scripts" : { "cypress:base": "cypress run --env type=base --config screenshotsFolder=cypress/snapshots/base", "cypress:run": "cypress run --env type=actual", "cypress:open": "cypress open" }
テストの実行
// Baseの作成 yarn cypress:base // テストを実行 yarn cypress:run
結果
Base Actual Diff
TestをTypeScriptで実行する
ルートのtscofing.jsonに下記を追加
"include": [ "node_modules/cypress/types/*.ts", "cypress/*/*.ts" ]