$30 off During Our Annual Pro Sale. View Details »

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

    View Slide

  2. ࣗݾ঺հ
    Shingo Yamazaki


    • גࣜձࣾϩάϥε


    • ࡢ೥9݄͔Β University of the People Ͱ

    ίϯϐϡʔλʔαΠΤϯεษڧத
    zaki-yama zaki___yama

    View Slide

  3. ͸͡Ίʹ

    View Slide

  4. ϑϩϯτΤϯυͷςετʹର͢Δ೰Έ
    • ϑϩϯτΤϯυͷςετɺԿΛͲ͜·Ͱॻ͍ͨΒ͍͍΋ͷ͔…


    • Ͳ͏͍͏؍఺ͰςετΛॻ͍ͨΒ͍͍ͷ͔


    • ࠷ۙ͸Visual Regression Testingͱ͔Α͘ฉ͘ɻͦΕҎ֎͸…ʁ


    • ൺֱతมߋ͕ੜ͡΍͍͢UIͷςετΛͲ͜·Ͱॻ͘΂͖͔


    • Ͳ͏͍͏πʔϧʗϥΠϒϥϦΛ࢖͏ͷ͕͍͍ͷ͔


    • etc.
    🤔

    View Slide

  5. View Slide

  6. UI Testing Handbook
    • Storybook ͕ఏڙ͍ͯ͠ΔνϡʔτϦΞϧίϯςϯπͷͻͱͭ


    • ࡢ೥12݄ʹެ։͞Εͨ


    • Twilio, Adobe, Shopify ͳͲɺStorybookίϛϡχςΟͷ10ݸͷνʔϜ
    ΛϦαʔνͯ͠ಘΒΕͨ஌ݟΛ·ͱΊͨ΋ͷʢ”Introduction” ΑΓʣ

    View Slide

  7. Handbook ͷ಺༰Λ


    ͬ͘͟Γ঺հ͠·͢

    View Slide

  8. αϯϓϧΞϓϦέʔγϣϯ
    • Α͋͘ΔTodoΞϓϦ


    • ΞϓϦέʔγϣϯଆͷίʔυ͸

    ΄΅͍͡Βͣɺ

    Storybook΍ςετΛॻ͖ͳ͕Β

    ֶΜͰ͍͘ߏ੒

    View Slide

  9. Introduction
    • ݱࡏͷओཁͳJavaScriptϑϨʔϜϫʔΫ͸͍ͣΕ΋ίϯϙʔωϯτυϦϒϯ


    • Unit, Integration, E2E ͱ͍ͬͨ෼ྨͰ͸ͳ͘ɺUI͕࣋ͭಛ௃(characteristics)ʹϑΥʔΧε
    ͠·͠ΐ͏

    View Slide

  10. ςετ͢΂͖UIͷಛ௃
    • Visual


    • ݟͨ໨


    • Interaction


    • ΫϦοΫ΍ϢʔβʔೖྗͳͲͷΠϕϯτ͕ద੾ʹϋϯυϦϯά͞ΕΔ͔


    • Accessibility


    • ΞΫηγϏϦςΟ


    • User
    fl
    ow


    • ෳ਺ͷίϯϙʔωϯτʹ·͕ͨͬͯ׬݁͢ΔϢʔβʔૢ࡞͕ظ଴௨Γߦ͑Δ͔

    View Slide

  11. ͦΕͧΕΛ࣮ݱ͢ΔͨΊͷπʔϧʗϥΠϒϥϦ
    • Visual


    • ݟͨ໨ … Chromatic


    • Interaction … Jest & Testing Library


    • ΫϦοΫ΍ϢʔβʔೖྗͳͲͷΠϕϯτ͕ద੾ʹϋϯυϦϯά͞ΕΔ͔


    • Accessibility


    • ΞΫηγϏϦςΟ … Axe


    • User
    fl
    ow … Cypress (or Playwright, Selenium)


    • ෳ਺ͷίϯϙʔωϯτʹ·͕ͨͬͯ׬݁͢ΔϢʔβʔૢ࡞͕ظ଴௨Γߦ͑Δ͔

    View Slide

  12. Visual
    • Chromatic Λ࢖ͬͨ Visual Regression Testing ͷ঺հ


    • Storybook ͷ಺༰Λը૾ͰΩϟϓνϟ͠ɺίϛοτؒͰࠩ෼͕ͳ͍
    ͔νΣοΫ͢Δ

    View Slide

  13. Visual: Chromatic
    • Visual Regression TestingΛ؆୯ʹಋೖͰ͖ΔαʔϏε


    • ࣗલͰ΍Δͱreg-suit + AWS S3ͳͲͷετϨʔδαʔϏεͰߏங



    View Slide

  14. Interaction
    • Jest & Testing Library (@testing-library/react)


    • Storybook ͷ Story Λςετέʔεʹ΋࠶ར༻͠·͠ΐ͏

    View Slide

  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();


    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();


    });


    View Slide

  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();


    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ΛΠϯϙʔτ͠ɺ
    ͦͷ··ςετέʔεͱͯ͠ར༻͢Δ

    View Slide

  17. Accessibility
    • Axe ͱ͍͏ϥΠϒϥϦΛ࢖͏ͱΞΫηγϏϦςΟΛ͋Δఔ౓ػցతʹ
    νΣοΫͰ͖Δ


    • ͞ΒʹStorybook༻ͷΞυΦϯ΍JestͰAxeΛ࢖ͬͨνΣοΫΛ૸Β
    ͤΔͨΊͷ jest-axe ͱ͍͏ϥΠϒϥϦ͕͋Δ

    View Slide

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

    View Slide

  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();


    await waitFor(() => {


    expect(queryByText("You have no tasks")).not.toBeInTheDocument();


    });


    const results = await axe(container);


    expect(results).toHaveNoViolations();


    });
    UP)BWF/P7JPMBUJPOT
    Λݺͼग़͚ͩ͢

    View Slide

  20. User
    fl
    ow
    • ͍ΘΏΔE2Eςετ


    • 2ͭͷબ୒ࢶ͕ߟ͑ΒΕΔ


    1. όοΫΤϯυ·ͰؚΊͨ׬શͳςετ؀ڥΛ࢖͏ʢO’ReillyνʔϜ͸ͬͪ͜ʣ


    2. όοΫΤϯυ͸ϞοΫ͠ɺϑϩϯτΤϯυͷΈʢTwilioνʔϜ͸ͬͪ͜ʣ


    • νϡʔτϦΞϧͰ͸ޙऀɻCypress Λ࢖͏


    • “ϩάΠϯը໘Ͱਖ਼͍͠Ϣʔβʔ໊&ύεϫʔυΛೖྗͨ͠ΒɺλεΫҰཡ͕։͚Δ” ͱ͍͏ςετ
    έʔε


    • ͜͜Ͱ΋ Story Λςετέʔεͱͯ͠࠶ར༻

    View Slide

  21. ·ͱΊ

    View Slide

  22. ͜͏͍ͬͨ͜ͱֶ͕΂ͯΑ͔ͬͨ☺
    • ֤छςετ؍఺ͱͦΕΛ࣮ݱ͢ΔͨΊͷ۩ମతͳϥΠϒϥϦ


    • Chromatic, Axe, Cypress, etc.


    • StorybookΛத৺ʹஔ͍࣮ͨ༻తͳϫʔΫϑϩʔ


    • StoryΛJest΍Cypressͷςετʹ΋࠶ར༻͢Δɺͱ͍͏ߟ͑ํ


    • GitHub ActionsʹΑΔCIʹ͍ͭͯ΋঺հ͞Ε͍ͯΔʢ”Automate” ͷষʣ


    • ࣮ࡍʹίʔυॻ͍ͯಈ͘΋ͷΛݟͳ͕Βֶ΂ͨͷ΋ݸਓతʹ͸Α͔ͬͨ

    View Slide

  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ςετ͸ͳΜͱͳ͘த్൒୺ͳͷͰ͸…ͱ͍
    ͏ײ͡΋͢Δ

    View Slide

  24. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠
    ࣸܦͨ͠ίʔυ͸


    https://github.com/zaki-yama-labs/ui-testing-handbook


    ʹ͋Γ·͢

    View Slide