React.kyoto v0.3.0 ( https://react-kyoto.connpass.com/event/137847/ )でStorybookとStoryshotsを使ったコンポーネントのUIテストについて話しました。 質問・不備・マサカリ等はTwitterにてメンションつけてもらえると嬉しいです。 Twitter: https://twitter.com/shisama_
Βͳ͍UIςετͷͨΊͷStorybook + Storyshotsreact.kyoto v0.3.0ฏণ࢜ @shisama
View Slide
ฏ ণ࢜ / Masashi Hirano@shisama_@shisamaNode.js Core CollaboratorؔNodeֶԂOrganizer
એ
Agenda• ίϯϙʔωϯτҰཡΛ֬ೝ͢Δ(Storybook)• ίϯϙʔωϯτͷڍಈΛ֬ೝ͢Δ(Storybook)• εφοϓγϣοτςετΛߦ͏(Storyshots)• ϝϯςφϯεҡ࣋ՄೳͳUIςετΛ Storybook + StoryshotsͰ࣮ݱ͢Δ
Ұࢥͬͨ͜ͱ͕ͳ͍Ͱ͔͢…?• ૿͑͗ͨ͢ίϯϙʔωϯτΛҰཡͰݟ͍ͨ• ͢propsʹԠͨ͡දࣔΛνΣοΫ͍ͨ͠• ݸʑͷίϯϙʔωϯτͷදࣔΛνΣοΫ͠ͳ͕ΒϨϏϡʔ͕͍ͨ͠
https://storybook.js.org/
Storybook• ίϯϙʔωϯτΛҰཡදࣔ͢Δπʔϧ• ݸʑͷίϯϙʔωϯτͷද͕ࣔݟΕΔ• ͢propsʹԠͨ͡ද͕ࣔݟΕΔ• React, Vue, AngularʹରԠ
ίϯϙʔωϯτ͕Ұཡදࣔ͞ΕΔ֤ίϯϙʔωϯτͷςετέʔείϯϙʔωϯτͷදࣔ݁Ռ
import React from 'react';import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';import { faHeart } from '@fortawesome/free-regular-svg-icons';type Props = {count: number;onClick: React.MouseEventHandler;};export const Like = ({ count, onClick }: Props) => {return (<>{count}>);};e.g. Likeίϯϙʔωϯτ
Storybookಋೖ• @storybook/cliΛ͏• BabelͷઃఆΛߦ͏• Storybook༻ͷwebpack.config.jsΛ࡞• StorybookͷઃఆϑΝΠϧΛฤू
@storybook/cli• npx -p @storybook/cli sb init --type react• StorybookͷઃఆΛࣗಈͰߦͬͯ͘ΕΔCLI• npm-scriptsՃ• StorybookͷઃఆϑΝΠϧ࡞• Storybookͷαϯϓϧίʔυ࡞
@storybook/cliTUPSZCPPLͷઃఆϑΝΠϧTUPSZCPPLͷίʔυJOEFYTUPSJFTKTαϯϓϧ
Babelͷઃఆ• StorybookBabelΛ͍ͬͯΔ• TypeScriptReact༻ʹpresetͳͲ͕ඞཁ• @babel/core• @babel/preset-typescript• @babel/preset-react
module.exports = ({ config }) => {config.module.rules.push({test: /\.tsx?$/,use: [{loader: require.resolve('ts-loader')},{loader: require.resolve('react-docgen-typescript-loader')}]});config.resolve.extensions.push('.ts', '.tsx');return config;};.storybook/webpack.config.jsOQNJ%UTMPBEFSOQNJ%SFBDUEPDHFOUZQFTDSJQU
import { configure } from '@storybook/react';// ͜ͷrequire.contextͰಡΈࠐΉରͷ֦ுࢠΛ.js͔Β.tsxʹฤू// const req = require.context('../stories', true, /\.stories\.js?$/);const req = require.context('../stories', true, /\.stories\.tsx?$/);function loadStories() {req.keys().forEach(filename => req(filename));}configure(loadStories, module);.storybook/config.jsॳظͰKTΛࢦఆ͍ͯ͠ΔͷͰUTY ͳͲʹมߋ
import React from "react";import { storiesOf } from "@storybook/react";import { Like } from "../src/components/Like";storiesOf("Like", module).add("0", () => ( {}} />)).add("1", () => ( {}} />));Storybook༻ͷίʔυΛॻ͘FHDPVOU͕AAͱAAͷ߹ͷTUPSJFTΛՃ͢Δ
࣮ߦ (npm run storybook)
Storybook՝• ίϯϙʔωϯτΛमਖ਼ͨ͠ͱ͖ʹStorybookͷίʔυޙճ͠͞Εϝϯς͞Εͳ͘ͳ͍ͬͯ͘• ࣗಈςετ͢ΔͷͰͳ͍ͨΊࢹͷνΣοΫ͕ඞཁ
https://github.com/storybookjs/storybook/tree/master/addons/storyshots/storyshots-core
Storyshots• StorybookͷίʔυΛ͍ࣗಈςετ(εφοϓγϣοτςετ)Λߦ͏• ίϯϙʔωϯτΛमਖ਼࣌ʹStorybookͷίʔυमਖ਼͠ͳ͍ͱεφοϓγϣοτςετ͕ࣦഊ͢Δ
Storyshotsಋೖ• StoryshotsΠϯετʔϧ• JestΠϯετʔϧ• Jestͷઃఆ• Babelͷઃఆ
StoryshotsΠϯετʔϧ• StoryshotsΛΠϯετʔϧ• @storybook/addon-storyshots• Storyshotsͷ࣮ߦʹඞཁͳύοέʔδΛΠϯετʔϧ• babel-plugin-require-context-hook• react-test-renderer
JestΠϯετʔϧ• jestͱbabel-jestΛΠϯετʔϧ• babel-jestͰͳ͘ts-jestΛ͏ͱ࣮ߦ࣌ʹܕνΣοΫͯ͘͠ΕΔ• babel-jestͷํ͕ಋೖ؆୯• ܕνΣοΫtscͰߦ͏• λεΫࡉԽͯ͠ฒྻॲཧͰ͖ΔΑ͏ʹ
Jestͷઃఆ• Jest࣮ߦʹඞཁͳsetupFilesΛ࡞• εφοϓγϣοτςετͷίʔυΛ࡞• jest.config.jsΛ࡞
Jestͷઃఆ - setupFiles࡞// .jest/register-context.tsimport registerRequireContextHook from “babel-plugin-require-context-hook/register";registerRequireContextHook();
Jestͷઃఆ - ςετϑΝΠϧ࡞// stories/__tests__/Like.test.tsimport initStoryshots from "@storybook/addon-storyshots";initStoryshots();
Jestͷઃఆ - jest.config.js࡞module.exports = {setupFiles: ["/.jest/register-context.ts"],testMatch: ["/stories/__tests__/*.test.ts"]};ϑΝΠϧͷॴҙ
Babelͷઃఆ{"presets": [["@babel/preset-env",{"targets": {"node": "current"}}],"@babel/preset-typescript","@babel/preset-react"],"env": {"test": {"plugins": ["require-context-hook"]}}}KFTUDPOpHKTͷઃఆϑΝΠϧͷͨΊʹQSFTFUFOWΛΠϯετʔϧUFTUͷͱ͖͚ͩSFRVJSFDPOUFYUIPPL͕ݺΕΔΑ͏ʹ͓ͯ͘͠
࣮ߦ (npx jest)4OBQTIPUϑΝΠϧ͕࡞͞Εͨ
࣮ߦ݁Ռ (εφοϓγϣοτϑΝΠϧ)4OBQTIPUϑΝΠϧ͕࡞͞Εͨ
࣮ߦ݁Ռ (εφοϓγϣοτϑΝΠϧ)
ίϯϙʔωϯτΛमਖ਼ͨ͠ͱ͖ྫ͑ɺQSPQTͷ໊લ͕มΘͬͨͱ͖
࣮ߦ (npx jest)લճςετ͔࣌Β݁Ռ͕มΘͬͨͨΊςετࣦഊ
Storybook՝͕ղܾ • ίϯϙʔωϯτΛमਖ਼ͨ͠ͱ͖ʹStorybookͷίʔυޙճ͠͞Εϝϯς͞Εͳ͘ͳ͍ͬͯ͘ ⇛Storybookͷίʔυม͑ͳ͍ͱςετ͕௨Βͳ͍ͷͰϝϯςඞਢͱͳΔ • ࣗಈςετ͢ΔͷͰͳ͍ͨΊࢹͷνΣοΫ͕ඞཁ ⇛テスト自動化
·ͱΊ• StorybookͰίϯϙʔωϯτ͝ͱͷUIΛνΣοΫͰ͖Δ• StoryshotsͰςετࣗಈԽ͠ɺStorybookΛΒ͞ͳ͍Α͏ʹ͢Δ
https://github.com/shisama/react-storybook-storyshots-exampleࠓճͷσϞ
Thanks.@shisama_shisama