Slide 1

Slide 1 text

্खʹ෇͖߹͏ ίϯϙʔωϯτςετ 2024.09.20 @Quramy

Slide 2

Slide 2 text

About me - id: @Quramy (GitHub / X ) - ͓࢓ࣄ: Web ϑϩϯτΤϯυΤϯδχΞ - React, Next.js, GraphQL - ՝֎׆ಈ: ςετࢧԉܥπʔϧͷ࡞੒ - Prisma ORM ؔ࿈: jest-prisma, prisma-fabbrica - Visual Testing ؔ࿈: reg-suit, Storycap

Slide 3

Slide 3 text

Visual Testing ಉ޷ձ https://speakerdeck.com/quramy/reg-viz-vrt-tools?slide=6

Slide 4

Slide 4 text

Agenda - ίϯϙʔωϯτςετͷಋೖ - ίϯϙʔωϯτςετͷӡ༻

Slide 5

Slide 5 text

ಋೖฤ

Slide 6

Slide 6 text

ࣗಈςετͷ໨త - εϐʔυΛଛͳΘͣʹ։ൃΛଓ͚ΔͨΊ - طଘͷػೳ͕໰୊ͳ͘ಈ࡞͚͍ͭͮͯ͠Δ͜ͱΛ୲อͯ͘͠ΕΔ - ϑϩϯτΤϯυͷ৔߹ʮݟͨ໨͕ͲͷΑ͏ʹมߋ͞ΕΔͷ͔ʯ͕Մࢹ Խ͞ΕΔͱɺϨϏϡΞଆͷ֬ೝίετ࡟ݮʹ΋ͭͳ͕Δ

Slide 7

Slide 7 text

උ͑͸େࣄ - ϓϩδΣΫτ্ཱͪ͛࣌͸ίϯϙʔωϯτςετಋೖΛݟૹΔͷ΋બ୒ ࢶͱͯ͠͸ΞϦͱࢥ͏ - ͨͩ͠ɺޙ͔ΒಋೖͰ͖ΔΑ͏ʹඋ͓͑ͯ͘͜ͱ͸ॏཁ - ϓϩδΣΫτ͕ҭ͔ͬͯΒಥવʮΑ͠ ίϯϙʔωϯτͷ Visual Testing ΍Ζ͏ʂʯͱٸʹࢥཱ͍ͬͯ΋ɺθϩ͔ΒςετέʔεΛॻ͘ͷ͸େม

Slide 8

Slide 8 text

ίϯϙʔωϯτςετͱ Storybook ίϯϙʔωϯτςετʹ Storybook Λ༻͍͍ͯΔཧ༝ - UI ίϯϙʔωϯτ։ൃج൫ͱͯ͠Չ઎ঢ়ଶ (ݸਓతʹ͸ଞͷπʔϧʹ΋ؤுͬͯ΄͍͕͠ɺStorybook ʹউͭͷ͕૬౰େมͳঢ়گʹͳ͍ͬͯ Δͱࢥ͏) - Story ͕ςετέʔεͱͯ͠ྲྀ༻ՄೳͰ͋ΔͨΊɺʮͱΓ͋͑ͣ Story ͚ͩॻ ͘Α͏ʹ͓ͯ͘͠ʯ͕ίϯϙʔωϯτςετͷඋ͑ͱͳΔ - Storybook ͕ࣗಈςετʹؔ͢ΔػೳڧԽʹྗΛೖΕ͍ͯΔ - Jest / Vitest ࿈ܞ (compositeStories), test-runner, Chromatic, etc...

Slide 9

Slide 9 text

ίϯϙʔωϯτςετ with Storybook Storybook ͱ࿈ܞ͢Δςετπʔϧ΍ςετϓϥοτϑΥʔϜ͸༷ʑͳ΋ͷ ͕͋Δɻओཁͳ΋ͷΛ঺հ (1/4) - Chromatic: https://www.chromatic.com/ Storybook ͷϗεςΟϯά΍ࣗಈςετΛ݉Ͷඋ͑ͨ all-in-one ͳαʔϏ εɻStorybook ΦϑΟγϟϧ - Lost Pixel: https://www.lost-pixel.com/ VRT πʔϧɻChromatic ͷΑ͏ͳ SaaS ͱͯ͠ͷఏڙܗଶͷଞɺࣗલͷ CI ʹηϧϑϗετ͢Δ͜ͱ΋Մೳͳπʔϧ

Slide 10

Slide 10 text

ίϯϙʔωϯτςετ with Storybook Storybook ͱ࿈ܞ͢Δςετπʔϧ΍ςετϓϥοτϑΥʔϜ͸༷ʑͳ΋ͷ ͕͋Δɻओཁͳ΋ͷΛ঺հ (2/4) - Storycap: https://github.com/reg-viz/storycap Storybook Λ Puppeteer ͰΫϩʔϧͯ͠ը૾Խ͢Δ CLI reg-suit ΍ reg-actions (͜ΕΒ΋ reg-vizͷπʔϧ) ͱ૊Έ߹ΘͤΔ͜ͱͰ ίϯϙʔωϯτ୯Ґͷ Visual Regression Test Λ࣮ݱ͢Δɻ Storybook x VRT ͱͯ͠͸࿝ฮͷ෦ྨ (2017 ೥͔Β͋Δ)

Slide 11

Slide 11 text

ίϯϙʔωϯτςετ with Storybook Storybook ͱ࿈ܞ͢Δςετπʔϧ΍ςετϓϥοτϑΥʔϜ͸༷ʑͳ΋ͷ ͕͋Δɻओཁͳ΋ͷΛ঺հ (3/4) - storybook/test-runner: https://storybook.js.org/docs/writing-tests/test-runner Storybook ެࣜͷςετϥϯφʔɻࣗલ CI Ͱ Story ͷϨϯμϦϯά΍ Play function Λ࣮ߦՄೳɻ jest-playwright Λ಺෦తʹར༻͍ͯ͠Δ - storycap-testrun: https://github.com/reg-viz/storycap-testrun storybook/test-runner Ͱར༻͢ΔεΫϦʔϯγϣοτϥΠϒϥϦɻ

Slide 12

Slide 12 text

ίϯϙʔωϯτςετ with Storybook Storybook ͱ࿈ܞ͢Δςετπʔϧ΍ςετϓϥοτϑΥʔϜ͸༷ʑͳ΋ͷ ͕͋Δɻओཁͳ΋ͷΛ঺հ (4/4) - Jest / Vitest: ୯ମςετͷπʔϧͰ͋Δ͕ɺStorybook ͕ఏڙ͢Δ composeStories ؔ਺ͱ૊Έ߹ΘͤΔ͜ͱͰ Story ͷςετ͕Մೳɻ https://storybook.js.org/docs/writing-tests/import-stories-in-tests/ stories-in-unit-tests

Slide 13

Slide 13 text

͓͜ͱΘΓ - චऀ͕࣮ࡍʹӡ༻ͨ͜͠ͱͷ͋Δίϯϙʔωϯτςετͷߏ੒͸ҎԼ: - Storybook + Storycap + reg-suit - Storybook + Jest + compositeStories - Ҏ߱Ͱ঺հ͢Δӡ༻ Tips ͸ɺπʔϧͷબ୒ͱಠཱͨ͠಺༰ͱͳΔΑ͏ۃ ྗ৺͕͚͍ͯ·͕͢ɺ্هΛཹҙͯ͠΋Β͑Δͱॿ͔Γ·͢

Slide 14

Slide 14 text

ӡ༻ฤ

Slide 15

Slide 15 text

ӡ༻ฤ ࡟Εʂ ࣮ߦ࣌ؒ

Slide 16

Slide 16 text

Կ෼·Ͱ଱͑ΒΕΔʁ - Pull Request ࣌ͷ CI ࣮ߦ࣌ؒɺͲΕ͘Β͍·ͰզຫͰ͖·͔͢ʁ - ݸਓࠩ͸͋Δ͕ɺࣗ෼ͷ؍ଌൣғͰ͸ 5෼ลΓʹᮢ஋͕͋Γͦ͏ - ίϯϙʔωϯτςετͷ࣮ߦ͕࣌ؒ௕͘ͳΕ͹ͳΔ΄ͲɺνʔϜͷϔΠ τ͕ཷ·͍ͬͯ͘

Slide 17

Slide 17 text

(ࢀߟ) ࣗಈςετ࣮ߦ࣌ؒਪҠ https://qiita.com/Quramy/items/46d0b09ae4d8887b0941 ߦ ίϯϙʔωϯτ έʔε $*࣮ߦ࣌ؒ

Slide 18

Slide 18 text

ฒྻ࣮ߦ (ϫʔΧʔϨϕϧ) - CI ͷ࣮ߦ؀ڥΛCPUΛ૿ڧͭͭ͠ɺ࣮ߦϒϥ΢β (worker) ਺Λ૿΍͢ - GitHub Actions Ͱ͋Ε͹ɺ Self Hosted Runner Ͱӡ༻͍ͯ͠Δਓ޲͚ - ίϯϙʔωϯτςετΛ࣮ߦ͢Δ CLI ͷΦϓγϣϯͰ worker ਺Λมߋ: - Storycap CLI: --parallel Φϓγϣϯ - storybook/test-runner CLI: --max-workers Φϓγϣϯ

Slide 19

Slide 19 text

ฒྻ࣮ߦ (δϣϒϨϕϧ) - CI ͷ࣮ߦ؀ڥ͝ͱฒྻԽ͢Δύλʔϯ - GitHub Actions Ͱ͋Ε͹ matrix ͳͲͰ ฒྻδϣϒ࣮ߦՄೳ ※ ίϯϙʔωϯτςετ͕૸Δ·Ͱͷεςοϓ (؀ڥࣗମͷηοτΞοϓ ΍ npm i ͢Δ෦෼ ͳͲ) ͕େ͖͍ͱɺฒྻԽޮ཰͕Լ͕ΔͨΊ޻෉͕ඞཁ - storybook/test-runner ΍ Storycap ͷ --shard ΦϓγϣϯΛར༻͢Δ

Slide 20

Slide 20 text

ϥϯφʔΛ࢖͍෼͚Δ - ࣮ϒϥ΢βΛ࢖ͬͨίϯϙʔωϯτςετ͸ͦ΋ͦ΋஗͍ - શͯͷίϯϙʔωϯτͷςετͰɺৗʹϒϥ΢β͕ඞཁͱ͍͏Θ͚Ͱ͸ ͳ͍͸ͣ (e.g. ϑΥʔϜόϦσʔγϣϯ΍ aria ଐੑͷ֬ೝ) - jsdom Ͱे෼ͳέʔεͰ͋Ε͹ɺJest / Vitest + compositeStories ͷςε τίʔυͱ࣮ͯ͠ߦͰ͖Ε͹ɺ஗͘ͳΓʹ͍͘ - Storycap (= Puppeteer): ਺100 msec / story - Jest + jsdom: ਺10 msec / story

Slide 21

Slide 21 text

࣮ફฤ ௵ͤʂ Flakiness

Slide 22

Slide 22 text

Flaky Test μϝθολΠ - Flaky ͳςετͱ͸ - ιʔείʔυʹมߋΛՃ͍͑ͯͳ͍ͷʹ ੒ޭ/ࣦഊ ͕҆ఆ͠ͳ͍ঢ়ଶ - ِཅੑ (False Positive) ͸ࣗಈςετͷఢ - ಛʹ Visual Testing ͸ݕূʹը૾Λ༻͍ΔͨΊ Flaky ςετʹؕΓ΍͍͢

Slide 23

Slide 23 text

VRT ʹ͓͚Δᮢ஋ͷௐ੔ - ϒϥ΢βʹίϯϙʔωϯτΛඳըͤ͞Δ౎߹্ɺ׬શͳ pixel by pixel ͷ Ұக͸೉͍͠ - e.g. CSS ͷ border-radius ΍ box-shadow ΍ ΞϯνΤΠϦΞε - [IMO] 100 ϐΫηϧ (ॎԣ 10px ͷਖ਼ํܗͷ໘ੵ) ఔ౓ͷࠩҟ͸ڐ༰ - 100 ఔ౓ͰِӄੑʹͳΔ͜ͱ͸໓ଟʹͳ͍ - [IMO] ը૾શମʹର͢Δൺ཰Ͱࢦఆ͢ΔͷͰ͋Ε͹ɺ 0.01% Λج४ʹ

Slide 24

Slide 24 text

෦෼తͳࠩ͠ସ͑ ίϯϙʔωϯτͷҰ෦͕ෆ҆ఆͳ৔߹ ( e.g. YouTube ຒࠐಈը, iframe) ɺ VRT ࣌ͷΈผ div ʹࠩ͠ସ͑ͯɺFlaky Test ʹͳΒͳ͍Α͏ʹ͢Δ export function MyComponent() { return (
{/* ͕͜͜ෆ҆ఆͳཁૉ */}
); } import { isScreenshot } from "storycap"; export function MyComponent() { return (
{process.env.NODE_ENV !== "production" && isScreenshot() ? (
) : ( )}
); }

Slide 25

Slide 25 text

ͦΕͰ΋μϝͳΒ skip - Ͳ͏ͯ͠΋ Flakiness Λ௵ͤͳ͍৔߹ɺͦͷέʔε(= Story) Λ ࣗಈςετର ৅֎ʹׂͯ͠Ε૭ԽΛ๷ࢭ͢Δ - ίʔυΛมߋͯ͠΋͍ͳ͍ͷʹ CI Ͱ VRT Λ૸ΒͤΔͨͼʹࠩ෼͕ग़ͯ͠· ͏ঢ়گΛ์ஔ͢ΔΑΓ͸Ϛγ export const MyStory = { args: {}, // storybook/test-runner ͷ৔߹ tags: ["skip"], parameters: { screenshot: { // Storycap ͷ৔߹ skip: true, }, }, } satisfies Story;

Slide 26

Slide 26 text

͓ΘΓʹ - ίϯϙʔωϯτςετӡ༻ͷίπ - Slow Test / Flakey Test ͸ݟա͝͞ͳ͍ - Off topics - Ұൠతͳࣗಈςετϊ΢ϋ΢ (e.g. ςετίʔυͷೝ஌ෛՙରࡦ) ΋׆ ༻ͯ͠ɺΑΓշదͳϑϩϯτΤϯυςετΛ໨ࢦ͠·͠ΐ͏ - e.g. https://gihyo.jp/list/group/αόϯφศΓ- ~ ιϑτ΢ΣΞ։ൃͷ ߥ໺Λੜ͖ൈ͘ ~

Slide 27

Slide 27 text

Thank you !