Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
上手に付き合うコンポーネントテスト
Search
Yosuke Kurami
September 20, 2024
Programming
2.4k
6
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
上手に付き合うコンポーネントテスト
Yosuke Kurami
September 20, 2024
More Decks by Yosuke Kurami
See All by Yosuke Kurami
GraphQL の onError と Nullability のこれから
quramy
0
190
TypeScript LSP の今までとこれから
quramy
1
2.3k
フロントエンドテストの育て方
quramy
12
3.9k
App Router 悲喜交々
quramy
8
780
Patched fetch did not work
quramy
6
820
GraphQL あるいは React における自律的なデータ取得について
quramy
18
6k
Next.js App Router
quramy
15
4k
Fragment Composition of GraphQL
quramy
17
5k
reg-viz VRT tools
quramy
4
1.8k
Other Decks in Programming
See All in Programming
Atomic Design, Enforced: Scaling Mobile Design Systems (next.app devCon / droidCon Berlin 2026)
steliosf
PRO
0
180
AmebaブログはKMPから卒業します
kmars0605
0
250
動画プレイヤーはなぜカクつくのか 〜Flutterのレンダリングとネイティブの境界を解剖する〜
naruogram
0
140
No More NoSuchMethodError
exoego
1
120
月間100万人のサービス刷新で、 技術選定をHonoに振り切った話
yutobara
8
7k
R8 の設定見直しでアプリサイズ削減
andpad
0
230
Inertia Rails: The One-Person Framework with React & Friends
skryukov
0
130
Performance Optimization With LLMs
xleitix
0
210
Compiling a real-world CLI tool to native with Static Hermes
tmikov2023
0
130
コードで差別化できない時代の ソフトウェアエンジニアリング / Software Engineering in an Era Where Code Doesn’t Differentiate
kishida
2
200
あなたの await、OS まで届いてる? strace で覗く JavaScript の非同期
hasutosasaki
1
1.5k
sbt 2.0: takeoff
eed3si9n
0
170
Featured
See All Featured
Raft: Consensus for Rubyists
vanstee
143
7.8k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
2
410
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
2
2.9k
[RailsConf 2023] Rails as a piece of cake
palkan
59
7.1k
Technical Leadership for Architectural Decision Making
baasie
3
610
Deep Space Network (abreviated)
tonyrice
0
380
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
710
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.2k
Embracing the Ebb and Flow
colly
88
5.2k
We Are The Robots
honzajavorek
0
410
Claude Code のすすめ
schroneko
67
230k
Transcript
্खʹ͖߹͏ ίϯϙʔωϯτςετ 2024.09.20 @Quramy
About me - id: @Quramy (GitHub / X ) -
͓ࣄ: Web ϑϩϯτΤϯυΤϯδχΞ - React, Next.js, GraphQL - ՝֎׆ಈ: ςετࢧԉܥπʔϧͷ࡞ - Prisma ORM ؔ࿈: jest-prisma, prisma-fabbrica - Visual Testing ؔ࿈: reg-suit, Storycap
Visual Testing ಉձ https://speakerdeck.com/quramy/reg-viz-vrt-tools?slide=6
Agenda - ίϯϙʔωϯτςετͷಋೖ - ίϯϙʔωϯτςετͷӡ༻
ಋೖฤ
ࣗಈςετͷత - εϐʔυΛଛͳΘͣʹ։ൃΛଓ͚ΔͨΊ - طଘͷػೳ͕ͳ͘ಈ࡞͚͍ͭͮͯ͠Δ͜ͱΛ୲อͯ͘͠ΕΔ - ϑϩϯτΤϯυͷ߹ʮݟ͕ͨͲͷΑ͏ʹมߋ͞ΕΔͷ͔ʯ͕Մࢹ Խ͞ΕΔͱɺϨϏϡΞଆͷ֬ೝίετݮʹͭͳ͕Δ
උ͑େࣄ - ϓϩδΣΫτ্ཱͪ͛࣌ίϯϙʔωϯτςετಋೖΛݟૹΔͷબ ࢶͱͯ͠ΞϦͱࢥ͏ - ͨͩ͠ɺޙ͔ΒಋೖͰ͖ΔΑ͏ʹඋ͓͑ͯ͘͜ͱॏཁ - ϓϩδΣΫτ͕ҭ͔ͬͯΒಥવʮΑ͠ ίϯϙʔωϯτͷ Visual
Testing Ζ͏ʂʯͱٸʹࢥཱ͍ͬͯɺθϩ͔ΒςετέʔεΛॻ͘ͷେม
ίϯϙʔωϯτςετͱ Storybook ίϯϙʔωϯτςετʹ Storybook Λ༻͍͍ͯΔཧ༝ - UI ίϯϙʔωϯτ։ൃج൫ͱͯ͠Չঢ়ଶ (ݸਓతʹଞͷπʔϧʹؤுͬͯ΄͍͕͠ɺStorybook ʹউͭͷ͕૬େมͳঢ়گʹͳ͍ͬͯ
Δͱࢥ͏) - Story ͕ςετέʔεͱͯ͠ྲྀ༻ՄೳͰ͋ΔͨΊɺʮͱΓ͋͑ͣ Story ͚ͩॻ ͘Α͏ʹ͓ͯ͘͠ʯ͕ίϯϙʔωϯτςετͷඋ͑ͱͳΔ - Storybook ͕ࣗಈςετʹؔ͢ΔػೳڧԽʹྗΛೖΕ͍ͯΔ - Jest / Vitest ࿈ܞ (compositeStories), test-runner, Chromatic, etc...
ίϯϙʔωϯτςετ 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 ʹηϧϑϗετ͢Δ͜ͱՄೳͳπʔϧ
ίϯϙʔωϯτςετ 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 ͔Β͋Δ)
ίϯϙʔωϯτςετ 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 Ͱར༻͢ΔεΫϦʔϯγϣοτϥΠϒϥϦɻ
ίϯϙʔωϯτςετ 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
͓͜ͱΘΓ - චऀ͕࣮ࡍʹӡ༻ͨ͜͠ͱͷ͋ΔίϯϙʔωϯτςετͷߏҎԼ: - Storybook + Storycap + reg-suit -
Storybook + Jest + compositeStories - Ҏ߱Ͱհ͢Δӡ༻ Tips ɺπʔϧͷબͱಠཱͨ͠༰ͱͳΔΑ͏ۃ ྗ৺͕͚͍ͯ·͕͢ɺ্هΛཹҙͯ͠Β͑Δͱॿ͔Γ·͢
ӡ༻ฤ
ӡ༻ฤ Εʂ ࣮ߦ࣌ؒ
Կ·Ͱ͑ΒΕΔʁ - Pull Request ࣌ͷ CI ࣮ߦ࣌ؒɺͲΕ͘Β͍·ͰզຫͰ͖·͔͢ʁ - ݸਓࠩ͋Δ͕ɺࣗͷ؍ଌൣғͰ 5ลΓʹᮢ͕͋Γͦ͏
- ίϯϙʔωϯτςετͷ࣮ߦ͕࣌ؒ͘ͳΕͳΔ΄ͲɺνʔϜͷϔΠ τ͕ཷ·͍ͬͯ͘
(ࢀߟ) ࣗಈςετ࣮ߦ࣌ؒਪҠ https://qiita.com/Quramy/items/46d0b09ae4d8887b0941 ߦ ίϯϙʔωϯτ έʔε $*࣮ߦ࣌ؒ
ฒྻ࣮ߦ (ϫʔΧʔϨϕϧ) - CI ͷ࣮ߦڥΛCPUΛ૿ڧͭͭ͠ɺ࣮ߦϒϥβ (worker) Λ૿͢ - GitHub Actions
Ͱ͋Εɺ Self Hosted Runner Ͱӡ༻͍ͯ͠Δਓ͚ - ίϯϙʔωϯτςετΛ࣮ߦ͢Δ CLI ͷΦϓγϣϯͰ worker Λมߋ: - Storycap CLI: --parallel Φϓγϣϯ - storybook/test-runner CLI: --max-workers Φϓγϣϯ
ฒྻ࣮ߦ (δϣϒϨϕϧ) - CI ͷ࣮ߦڥ͝ͱฒྻԽ͢Δύλʔϯ - GitHub Actions Ͱ͋Ε matrix
ͳͲͰ ฒྻδϣϒ࣮ߦՄೳ ※ ίϯϙʔωϯτςετ͕Δ·Ͱͷεςοϓ (ڥࣗମͷηοτΞοϓ npm i ͢Δ෦ ͳͲ) ͕େ͖͍ͱɺฒྻԽޮ͕Լ͕ΔͨΊ͕ඞཁ - storybook/test-runner Storycap ͷ --shard ΦϓγϣϯΛར༻͢Δ
ϥϯφʔΛ͍͚Δ - ࣮ϒϥβΛͬͨίϯϙʔωϯτςετ͍ͦͦ - શͯͷίϯϙʔωϯτͷςετͰɺৗʹϒϥβ͕ඞཁͱ͍͏Θ͚Ͱ ͳ͍ͣ (e.g. ϑΥʔϜόϦσʔγϣϯ aria ଐੑͷ֬ೝ)
- jsdom ͰेͳέʔεͰ͋ΕɺJest / Vitest + compositeStories ͷςε τίʔυͱ࣮ͯ͠ߦͰ͖Εɺ͘ͳΓʹ͍͘ - Storycap (= Puppeteer): 100 msec / story - Jest + jsdom: 10 msec / story
࣮ફฤ ௵ͤʂ Flakiness
Flaky Test μϝθολΠ - Flaky ͳςετͱ - ιʔείʔυʹมߋΛՃ͍͑ͯͳ͍ͷʹ ޭ/ࣦഊ ͕҆ఆ͠ͳ͍ঢ়ଶ
- ِཅੑ (False Positive) ࣗಈςετͷఢ - ಛʹ Visual Testing ݕূʹը૾Λ༻͍ΔͨΊ Flaky ςετʹؕΓ͍͢
VRT ʹ͓͚Δᮢͷௐ - ϒϥβʹίϯϙʔωϯτΛඳըͤ͞Δ߹্ɺશͳ pixel by pixel ͷ Ұக͍͠ -
e.g. CSS ͷ border-radius box-shadow ΞϯνΤΠϦΞε - [IMO] 100 ϐΫηϧ (ॎԣ 10px ͷਖ਼ํܗͷ໘ੵ) ఔͷࠩҟڐ༰ - 100 ఔͰِӄੑʹͳΔ͜ͱ໓ଟʹͳ͍ - [IMO] ը૾શମʹର͢ΔൺͰࢦఆ͢ΔͷͰ͋Εɺ 0.01% Λج४ʹ
෦తͳࠩ͠ସ͑ ίϯϙʔωϯτͷҰ෦͕ෆ҆ఆͳ߹ ( e.g. YouTube ຒࠐಈը, iframe) ɺ VRT ࣌ͷΈผ
div ʹࠩ͠ସ͑ͯɺFlaky Test ʹͳΒͳ͍Α͏ʹ͢Δ export function MyComponent() { return ( <div> {/* ͕͜͜ෆ҆ఆͳཁૉ */} <iframe style={{ height: 400, width: "100%" }} src="https://example.com/hogehoge" /> </div> ); } import { isScreenshot } from "storycap"; export function MyComponent() { return ( <div> {process.env.NODE_ENV !== "production" && isScreenshot() ? ( <div style={{ height: 400, background: "#888" }} /> ) : ( <iframe style={{ height: 400, width: "100%" }} src="https://example.com/hogehoge" /> )} </div> ); }
ͦΕͰμϝͳΒ skip - Ͳ͏ͯ͠ Flakiness Λ௵ͤͳ͍߹ɺͦͷέʔε(= Story) Λ ࣗಈςετର ֎ʹׂͯ͠Ε૭ԽΛࢭ͢Δ
- ίʔυΛมߋ͍ͯ͠ͳ͍ͷʹ CI Ͱ VRT ΛΒͤΔͨͼʹ͕ࠩग़ͯ͠· ͏ঢ়گΛ์ஔ͢ΔΑΓϚγ export const MyStory = { args: {}, // storybook/test-runner ͷ߹ tags: ["skip"], parameters: { screenshot: { // Storycap ͷ߹ skip: true, }, }, } satisfies Story;
͓ΘΓʹ - ίϯϙʔωϯτςετӡ༻ͷίπ - Slow Test / Flakey Test ݟա͝͞ͳ͍
- Off topics - Ұൠతͳࣗಈςετϊϋ (e.g. ςετίʔυͷೝෛՙରࡦ) ׆ ༻ͯ͠ɺΑΓշదͳϑϩϯτΤϯυςετΛࢦ͠·͠ΐ͏ - e.g. https://gihyo.jp/list/group/αόϯφศΓ- ~ ιϑτΣΞ։ൃͷ ߥΛੜ͖ൈ͘ ~
Thank you !