Upgrade to Pro — share decks privately, control downloads, hide ads and more …

StorybookのUI Testing Handbookを読んだ

StorybookのUI Testing Handbookを読んだ

フロントエンドLT会 - vol.5 #frontendlt の登壇資料です。
https://rakus.connpass.com/event/232039/

UI Testing Handbook
https://storybook.js.org/tutorials/ui-testing-handbook/

サンプルリポジトリ
https://github.com/zaki-yama-labs/ui-testing-handbook

Shingo Yamazaki

January 19, 2022
Tweet

More Decks by Shingo Yamazaki

Other Decks in Technology

Transcript

  1. Storybook ͷ UI Testing Handbook ΛಡΜͩ 2022-01-19 ϑϩϯτΤϯυLTձ - vol.5ɹ#frontendlt

  2. ࣗݾ঺հ Shingo Yamazaki • גࣜձࣾϩάϥε • ࡢ೥9݄͔Β University of the

    People Ͱ 
 ίϯϐϡʔλʔαΠΤϯεษڧத zaki-yama zaki___yama
  3. ͸͡Ίʹ

  4. ϑϩϯτΤϯυͷςετʹର͢Δ೰Έ • ϑϩϯτΤϯυͷςετɺԿΛͲ͜·Ͱॻ͍ͨΒ͍͍΋ͷ͔… • Ͳ͏͍͏؍఺ͰςετΛॻ͍ͨΒ͍͍ͷ͔ • ࠷ۙ͸Visual Regression Testingͱ͔Α͘ฉ͘ɻͦΕҎ֎͸…ʁ •

    ൺֱతมߋ͕ੜ͡΍͍͢UIͷςετΛͲ͜·Ͱॻ͘΂͖͔ • Ͳ͏͍͏πʔϧʗϥΠϒϥϦΛ࢖͏ͷ͕͍͍ͷ͔ • etc. 🤔
  5. None
  6. UI Testing Handbook • Storybook ͕ఏڙ͍ͯ͠ΔνϡʔτϦΞϧίϯςϯπͷͻͱͭ • ࡢ೥12݄ʹެ։͞Εͨ • Twilio,

    Adobe, Shopify ͳͲɺStorybookίϛϡχςΟͷ10ݸͷνʔϜ ΛϦαʔνͯ͠ಘΒΕͨ஌ݟΛ·ͱΊͨ΋ͷʢ”Introduction” ΑΓʣ
  7. Handbook ͷ಺༰Λ ͬ͘͟Γ঺հ͠·͢

  8. αϯϓϧΞϓϦέʔγϣϯ • Α͋͘ΔTodoΞϓϦ • ΞϓϦέʔγϣϯଆͷίʔυ͸ 
 ΄΅͍͡Βͣɺ 
 Storybook΍ςετΛॻ͖ͳ͕Β 


    ֶΜͰ͍͘ߏ੒
  9. Introduction • ݱࡏͷओཁͳJavaScriptϑϨʔϜϫʔΫ͸͍ͣΕ΋ίϯϙʔωϯτυϦϒϯ • Unit, Integration, E2E ͱ͍ͬͨ෼ྨͰ͸ͳ͘ɺUI͕࣋ͭಛ௃(characteristics)ʹϑΥʔΧε ͠·͠ΐ͏

  10. ςετ͢΂͖UIͷಛ௃ • Visual • ݟͨ໨ • Interaction • ΫϦοΫ΍ϢʔβʔೖྗͳͲͷΠϕϯτ͕ద੾ʹϋϯυϦϯά͞ΕΔ͔ •

    Accessibility • ΞΫηγϏϦςΟ • User fl ow • ෳ਺ͷίϯϙʔωϯτʹ·͕ͨͬͯ׬݁͢ΔϢʔβʔૢ࡞͕ظ଴௨Γߦ͑Δ͔
  11. ͦΕͧΕΛ࣮ݱ͢ΔͨΊͷπʔϧʗϥΠϒϥϦ • Visual • ݟͨ໨ … Chromatic • Interaction …

    Jest & Testing Library • ΫϦοΫ΍ϢʔβʔೖྗͳͲͷΠϕϯτ͕ద੾ʹϋϯυϦϯά͞ΕΔ͔ • Accessibility • ΞΫηγϏϦςΟ … Axe • User fl ow … Cypress (or Playwright, Selenium) • ෳ਺ͷίϯϙʔωϯτʹ·͕ͨͬͯ׬݁͢ΔϢʔβʔૢ࡞͕ظ଴௨Γߦ͑Δ͔
  12. Visual • Chromatic Λ࢖ͬͨ Visual Regression Testing ͷ঺հ • Storybook

    ͷ಺༰Λը૾ͰΩϟϓνϟ͠ɺίϛοτؒͰࠩ෼͕ͳ͍ ͔νΣοΫ͢Δ
  13. Visual: Chromatic • Visual Regression TestingΛ؆୯ʹಋೖͰ͖ΔαʔϏε • ࣗલͰ΍Δͱreg-suit + AWS

    S3ͳͲͷετϨʔδαʔϏεͰߏங •
  14. Interaction • Jest & Testing Library (@testing-library/react) • Storybook ͷ

    Story Λςετέʔεʹ΋࠶ར༻͠·͠ΐ͏
  15. Interaction import { render, waitFor, cleanup, within, fireEvent, } from

    "@testing-library/react"; import { composeStories } from "@storybook/testing-react"; import * as stories from "./InboxScreen.stories"; describe("InboxScreen", () => { const { Default } = composeStories(stories); it("should pin a task", async () => { const { queryByText, getByRole } = render(<Default />); await waitFor(() => { expect(queryByText("You have no tasks")).not.toBeInTheDocument(); }); const getTask = () => getByRole("listitem", { name: "Export logo" }); const pinButton = within(getTask()).getByRole("button", { name: "pin" }); fireEvent.click(pinButton); const unpinButton = within(getTask()).getByRole("button", { name: "unpin", }); expect(unpinButton).toBeInTheDocument(); });
  16. Interaction import { render, waitFor, cleanup, within, fireEvent, } from

    "@testing-library/react"; import { composeStories } from "@storybook/testing-react"; import * as stories from "./InboxScreen.stories"; describe("InboxScreen", () => { const { Default } = composeStories(stories); it("should pin a task", async () => { const { queryByText, getByRole } = render(<Default />); await waitFor(() => { expect(queryByText("You have no tasks")).not.toBeInTheDocument(); }); const getTask = () => getByRole("listitem", { name: "Export logo" }); const pinButton = within(getTask()).getByRole("button", { name: "pin" }); fireEvent.click(pinButton); const unpinButton = within(getTask()).getByRole("button", { name: "unpin", }); expect(unpinButton).toBeInTheDocument(); }); 4UPSZΛΠϯϙʔτ͠ɺ ͦͷ··ςετέʔεͱͯ͠ར༻͢Δ
  17. Accessibility • Axe ͱ͍͏ϥΠϒϥϦΛ࢖͏ͱΞΫηγϏϦςΟΛ͋Δఔ౓ػցతʹ νΣοΫͰ͖Δ • ͞ΒʹStorybook༻ͷΞυΦϯ΍JestͰAxeΛ࢖ͬͨνΣοΫΛ૸Β ͤΔͨΊͷ jest-axe ͱ͍͏ϥΠϒϥϦ͕͋Δ

  18. Accessibility: storybook-addon-a11y ΞΫηγϏϦςΟҧ൓Օॴ͕ 4UPSZCPPL্Ͱ֬ೝͰ͖Δ ʢ✅ೖΕΔͱ֘౰Օॴ͕ϋΠϥΠτʣ

  19. Accessibility: jest-axe import { axe, toHaveNoViolations } from "jest-axe"; import

    { composeStories } from "@storybook/testing-react"; import * as stories from "./InboxScreen.stories"; expect.extend(toHaveNoViolations); describe("InboxScreen", () => { ... const { Default } = composeStories(stories); // Run axe it("should have no accessibility violations", async () => { const { container, queryByText } = render(<Default />); await waitFor(() => { expect(queryByText("You have no tasks")).not.toBeInTheDocument(); }); const results = await axe(container); expect(results).toHaveNoViolations(); }); UP)BWF/P7JPMBUJPOT Λݺͼग़͚ͩ͢
  20. User fl ow • ͍ΘΏΔE2Eςετ • 2ͭͷબ୒ࢶ͕ߟ͑ΒΕΔ 1. όοΫΤϯυ·ͰؚΊͨ׬શͳςετ؀ڥΛ࢖͏ʢO’ReillyνʔϜ͸ͬͪ͜ʣ 2.

    όοΫΤϯυ͸ϞοΫ͠ɺϑϩϯτΤϯυͷΈʢTwilioνʔϜ͸ͬͪ͜ʣ • νϡʔτϦΞϧͰ͸ޙऀɻCypress Λ࢖͏ • “ϩάΠϯը໘Ͱਖ਼͍͠Ϣʔβʔ໊&ύεϫʔυΛೖྗͨ͠ΒɺλεΫҰཡ͕։͚Δ” ͱ͍͏ςετ έʔε • ͜͜Ͱ΋ Story Λςετέʔεͱͯ͠࠶ར༻
  21. ·ͱΊ

  22. ͜͏͍ͬͨ͜ͱֶ͕΂ͯΑ͔ͬͨ☺ • ֤छςετ؍఺ͱͦΕΛ࣮ݱ͢ΔͨΊͷ۩ମతͳϥΠϒϥϦ • Chromatic, Axe, Cypress, etc. • StorybookΛத৺ʹஔ͍࣮ͨ༻తͳϫʔΫϑϩʔ

    • StoryΛJest΍Cypressͷςετʹ΋࠶ར༻͢Δɺͱ͍͏ߟ͑ํ • GitHub ActionsʹΑΔCIʹ͍ͭͯ΋঺հ͞Ε͍ͯΔʢ”Automate” ͷষʣ • ࣮ࡍʹίʔυॻ͍ͯಈ͘΋ͷΛݟͳ͕Βֶ΂ͨͷ΋ݸਓతʹ͸Α͔ͬͨ
  23. Ҿ͖ଓ͖Θ͔ΒΜ😭 • ͦΕͧΕͷςετΛͲ͏͍͏ج४Ͱ૊Έ߹ΘͤͯɺΞϓϦέʔγϣϯશମͱ ͯ͠ͷ඼࣭Λ୲อ͢Δ͔ • ಛʹ Interaction ͱ User fl

    ow (E2E) ͷ੗Έ෼͚ • “Given this trade-off, most teams use a hybrid approach to balance effort and value. E2E tests are limited to only critical user fl ows and interaction tests are used to verify all other behavior.” • όοΫΤϯυΛϞοΫͨ͠E2Eςετ͸ͳΜͱͳ͘த్൒୺ͳͷͰ͸…ͱ͍ ͏ײ͡΋͢Δ
  24. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ ࣸܦͨ͠ίʔυ͸ https://github.com/zaki-yama-labs/ui-testing-handbook ʹ͋Γ·͢