Slide 1

Slide 1 text

Web フロントエンドのための 実践「テスト」手法 CodeZine Night #1 @ Takepepe

Slide 2

Slide 2 text

自己紹介 ■ Takepepe(吉井 健文) ■ 社内横断開発組織に所属 ■ フロントエンド開発の横断サポート

Slide 3

Slide 3 text

【投票】「フロントエンド開発のためのテスト入門」は、もう読まれましたか? フロントエンド開発のためのテスト入門 ■ 2023.4/24 翔泳社より刊行 ■ フロントエンド開発におけるテスト手法を紹介 ■ 単体テストからE2Eテストまでを体系的に ■ 自動テストがはじめてという方にも

Slide 4

Slide 4 text

Agenda ■ 第1章:フロントエンドテストを書く目的 ■ 第2章:a11y の当たり前品質 ■ 第3章:テストがない状況からの脱却 本日は、書籍で紹介しきれなかった内容が中心です

Slide 5

Slide 5 text

第1章 フロントエンドテストを書く目的

Slide 6

Slide 6 text

第1章:フロントエンドテストを書く目的 テスト、書いていますか? 【投票】フロントエンドの自動テストを導入して「良かった」と思ったことはありますか? ■ なんとなく今後の運用が「不安」である ■ バックログに積みっぱなしの「テストを書く」というチケット ■ いつまでたっても優先度があがらない

Slide 7

Slide 7 text

第1章:フロントエンドテストを書く目的 テストの目的は何か? ■ 目的はサービスの「品質」を保ち続けること ■ 自動テストは「品質」を担保してくれる ■ 自動テストを書くことで「品質」があがる そもそも期待している「品質」って何だっけ?

Slide 8

Slide 8 text

第1章:フロントエンドテストを書く目的 テストに求める「品質」の定義 ■ 狩野モデルによると、品質は5つに分類される 当たり前品質 支障なくサービスが利用できること 一元的品質 充足するとプラス評価、不充足はマイナス評価となるもの 魅力的品質 競合にない付加価値で、プラス評価となるもの 無関心品質 顧客の評価に影響しない、サービス提供側都合の品質 逆品質 存在することで、サービスのマイナス評価となるもの

Slide 9

Slide 9 text

第1章:フロントエンドテストを書く目的 テストに求める「品質」の定義 ■ フロントエンド開発対象「UI」に置き換えると… 当たり前品質 ボタンが押せて、画面遷移できる(欠陥がない) 一元的品質 画面がサクサク遷移し、レスポンスが良い(非機能面が優良) 魅力的品質 競合にない UI で、作業効率化のために欠かせない(差別化) 無関心品質 顧客の評価に影響しない、サービス提供側都合の品質 逆品質 存在することで、サービスのマイナス評価となるもの

Slide 10

Slide 10 text

第1章:フロントエンドテストを書く目的 フロントエンド開発の自動テストスコープ ■ 機能テスト(リグレッションテスト) 日常的な開発で、故障に気づけるように 当たり前品質 一元的品質 魅力的品質 利用者 ✅ ー ー ??? ー ー ー

Slide 11

Slide 11 text

第1章:フロントエンドテストを書く目的 フロントエンド開発の自動テストスコープ ■ 非機能テスト(パフォーマンステスト・アクセシビリティテスト等) 非機能要件追求は「コストと相談のうえ」という実態 当たり前品質 一元的品質 魅力的品質 利用者 ✅ ✅ ー ??? ー ー ー

Slide 12

Slide 12 text

第1章:フロントエンドテストを書く目的 フロントエンド開発の自動テストスコープ ■ Web アクセシビリティに対する関心の高まり 支援技術利用者目線でも、品質を向上しよう 当たり前品質 一元的品質 魅力的品質 利用者 (障害無し) ✅ ✅ ー 利用者 (障害有り) ❌ ❌ ー

Slide 13

Slide 13 text

第1章:フロントエンドテストを書く目的 フロントエンド開発の自動テストスコープ ■ Web アクセシビリティに対する関心の高まり 【投票】普段 Web アクセシビリティを考慮できていますか? 当たり前品質 一元的品質 魅力的品質 利用者 (障害無し) ✅ ✅ ー 利用者 (障害有り) ❌ ❌ ー

Slide 14

Slide 14 text

第1章:フロントエンドテストを書く目的 フロントエンド開発の自動テストスコープ ■ フロントエンドテストツールでいま 注力されているもの 当たり前品質 一元的品質 魅力的品質 利用者 (障害無し) ✅ ✅ ー 利用者 (障害有り) ❌ ❌ ー Web アクセシビリティにも「当たり前品質」を

Slide 15

Slide 15 text

第1章:フロントエンドテストを書く目的 ■ Testing Library の狙い ー アクセシビリティ由来のクエリー(セマンティッククエリー) ー 機能テストを書くと、a11y の「当たり前品質」を意識することに ー a11y の欠陥に、日常的に気づける フロントエンドテストツールの変化 Queries Accessible to Everyone: https://testing-library.com/docs/queries/about#priority

Slide 16

Slide 16 text

第1章:フロントエンドテストを書く目的 ■ Playwright も追従 ー v.1.27.0 で、Locator に新機能(書籍執筆中に発生) ー getByRole など、Testing Library にインスパイアされた API ー 公式として、この Locator を使用したコードを推奨 フロントエンドテストツールの変化 New APIs, inspired by Testing Library: https://github.com/microsoft/playwright/releases/tag/v1.27.0

Slide 17

Slide 17 text

第2章 a11y の当たり前品質

Slide 18

Slide 18 text

第2章:a11y の当たり前品質 a11y の「当たり前品質」とは? ■ リンクを押下すると画面遷移できるか ■ フォームが送信できるか ■ ドキュメントが意図どおり提供できているか ー 文章構造、CSS、a11y tree

Slide 19

Slide 19 text

第2章:a11y の当たり前品質 a11y tree とは? ■ アクションを実行できるアクセシビリティオブジェクトのツリー ■ DOMツリーから派生したもの ■ 支援技術が属性とプロパティを照会 ■ 支援技術にドキュメントがどう見えているか示すツリー

Slide 20

Slide 20 text

第2章:a11y の当たり前品質 Full accessibility tree とは? ■ Google Chrome の 実験的な機能 ■ Elements パネルから確認でき、日常のデバッグに便利 ■ Storybook では、UI コンポーネント単位でツリーが確認できる Full accessibility tree in Chrome DevTools: https://developer.chrome.com/blog/full-accessibility-tree

Slide 21

Slide 21 text

第2章:a11y の当たり前品質

Slide 22

Slide 22 text

第2章:a11y の当たり前品質

Slide 23

Slide 23 text

第2章:a11y の当たり前品質 a11y 欠陥の具体例 ■ 事例1:リンクにクリックログを仕込む ー onClick イベントにログ送信処理を追加 ー 画面遷移前にログを送信できている ー 画面遷移もきちんと出来ている ー 自動テストが失敗。原因は何だったか? 参考PR:https://github.com/frontend-testing-book/unittest/pull/5

Slide 24

Slide 24 text

第2章:a11y の当たり前品質 a11y 欠陥の具体例 ■ 事例1:リンクにクリックログを仕込む ー onClick イベントにログ送信処理を追加 ー 画面遷移前にログを送信できている ー 画面遷移もきちんと出来ている ー 自動テストが失敗。原因は何だったか? href 属性がなくなった影響で「 link」ロールが欠落 → 支援技術利用者は画面遷移できない

Slide 25

Slide 25 text

第2章:a11y の当たり前品質 ■ 事例2:独自デザインのチェックボックスを実装する ー チェックボックスコンポーネントに状態を保持 ー 状態に応じてデザインを切り替えて ー チェックができ、状態が参照できている ー 自動テストが失敗。原因は何だったか? 参考PR:https://github.com/frontend-testing-book/unittest/pull/3 a11y 欠陥の具体例

Slide 26

Slide 26 text

第2章:a11y の当たり前品質 a11y 欠陥の具体例 ■ 事例2:独自デザインのチェックボックスを実装する ー チェックボックスコンポーネントに状態を保持 ー 状態に応じてデザインを切り替えて ー チェックができ、状態が参照できている ー 自動テストが失敗。原因は何だったか?  display: none; 指定による a11y tree からの除外 → 支援技術利用者は操作継続できない

Slide 27

Slide 27 text

第2章:a11y の当たり前品質 a11y 欠陥の具体例 ■ 事例2:独自デザインのチェックボックスを実装する ー チェックボックスコンポーネントに状態を保持 ー 状態に応じてデザインを切り替えて ー チェックができ、状態が参照できている ー 自動テストが失敗。原因は何だったか? a11y tree の算出は CSS も関係する → jsdom のテストでは不十分な場合がある

Slide 28

Slide 28 text

第2章:a11y の当たり前品質 a11y 欠陥の具体例 ■ 事例2:独自デザインのチェックボックスを実装する ー チェックボックスコンポーネントに状態を保持 ー 状態に応じてデザインを切り替えて ー チェックができ、状態が参照できている ー 自動テストが失敗。原因は何だったか? jsdom のテストでは不十分な場合 → CSS Modules をモックしている場合など

Slide 29

Slide 29 text

第2章:a11y の当たり前品質 a11y 欠陥の具体例 ■ 事例3:デザインを調整する例 ー デザインシステムを導入した ー デザイントークンを使用し、見出しに統一をもたせた ー デザインデータ通りの実装になった ー 自動テストが失敗。原因は何だったか? 参考PR:https://github.com/frontend-testing-book/nextjs/pull/5

Slide 30

Slide 30 text

第2章:a11y の当たり前品質 a11y 欠陥の具体例 ■ 事例3:デザインを調整する例 ー デザインシステムを導入した ー デザイントークンを使用し、見出しに統一をもたせた ー デザインデータ通りの実装になった ー 自動テストが失敗。原因は何だったか? コントラスト比が不十分 → 色覚障害のある利用者に見えない

Slide 31

Slide 31 text

第2章:a11y の当たり前品質 a11y 欠陥の具体例 axe-playwright を使用した、Story 毎のアクセシビリティ違反チェック ■ 事例3:デザインを調整する例 await checkA11y(page, "#root", { includedImpacts: ["critical", "serious"], detailedReport: false, detailedReportOptions: { html: true }, axeOptions: storyContext.parameters?.a11y?.options, });

Slide 32

Slide 32 text

第2章:a11y の当たり前品質 a11y 欠陥の具体例 "critical", "serious", "moderate", "minor" の検証レベル指定(コントラスト比は "serious") ■ 事例3:デザインを調整する例 await checkA11y(page, "#root", { includedImpacts: ["critical", "serious"], detailedReport: false, detailedReportOptions: { html: true }, axeOptions: storyContext.parameters?.a11y?.options, });

Slide 33

Slide 33 text

第2章:a11y の当たり前品質 a11y 欠陥の具体例 ■ 事例4:E2E テストで見つかった a11y 欠陥 ー Storybook では a11y 違反は検出されなかった ー 自動テストが失敗。原因は何だったか? 参考PR:https://github.com/frontend-testing-book/nextjs/pull/6

Slide 34

Slide 34 text

第2章:a11y の当たり前品質 a11y 欠陥の具体例 axe-playwright を使用した、ページ毎のアクセシビリティ違反チェック ■ 事例4:E2E テストで見つかった a11y 欠陥 test("アクセシビリティ検証 ", async ({ page }) => { await page.goto(url(path)); await injectAxe(page); await checkA11y(page); });

Slide 35

Slide 35 text

第2章:a11y の当たり前品質 a11y 欠陥の具体例 a11y 欠陥は E2E テスト時に発覚することも ■ 事例4:E2E テストで見つかった a11y 欠陥 test("アクセシビリティ検証 ", async ({ page }) => { await page.goto(url(path)); await injectAxe(page); await checkA11y(page); });

Slide 36

Slide 36 text

第2章:a11y の当たり前品質 axe について ■ Web アクセシビリティのための自動テストツール ー ブラウザで利用する a11y 検証ツール(ブラウザ固有のテスト) ー Testing Library は DOM から算出した a11y tree 検証にとどまる ー Storybook test runner でしか検出できない欠陥 → コントラスト比等 ー ブラウザE2Eテストフレームワークでしか検出できない欠陥 ブラウザで実行されるため、忠実性の高い a11y 検証ができる

Slide 37

Slide 37 text

第2章:a11y の当たり前品質 a11y とテスト、どう向き合うか ■ ARIA の誤用に気をつけよう ー テストのための符号として ARIA 属性を付与しがち ー テスト・デバッグツールの解釈と、支援技術には差がある ー テストついでに a11y 改善を行う場合、正しい用法か確認を ー テストで要素取得できているからといってアクセシブルとは限らない No ARIA is better than Bad ARIA:https://www.w3.org/WAI/ARIA/apg/practices/read-me-first

Slide 38

Slide 38 text

第2章:a11y の当たり前品質 a11y とテスト、どう向き合うか ■ 自動テストを書く日常の一環として ー a11y の「当たり前品質」を担保するリグレッションテストとして ー できれば UI コンポーネント作成段階で a11y 品質を考慮しよう ー できれば支援技術(スクリーンリーダーなど)で確認を ー まず自動テストを書く事が目的なら、 data-testid 属性から始めて良い 自動テストで、アクセシビリティの「当たり前品質」を担保

Slide 39

Slide 39 text

第3章 テストがない状況からの脱却

Slide 40

Slide 40 text

第3章:テストがない状況からの脱却 フロントエンド品質に a11y が関連するのは理解したけれど… ■ フロントエンドテストを書く動機 ー リファクタリングしたいけれど、大丈夫 …? ー ライブラリをアップデートしたいけれど、大丈夫 …? ー 新機能の追加、既存機能に影響でていない …?

Slide 41

Slide 41 text

第3章:テストがない状況からの脱却 フロントエンド品質に a11y が関連するのは理解したけれど… ■ フロントエンドテストを書く動機 ー a11y 考慮が十分じゃないとテストは書けない? → No ー 最低限の「当たり前品質」を担保することが目的 気負わず出来るところから着手しよう

Slide 42

Slide 42 text

第3章:テストがない状況からの脱却 フロントエンドテストを導入したいけれど… ■ 現場に障壁があって… ー 運用コスト・学習コストが高い ー テストを書く時間がない ー テストを書く文化がない 【投票】自動テスト導入の一番の障壁は何ですか?

Slide 43

Slide 43 text

第3章:テストがない状況からの脱却 テストがない状況における目的 ■ 最低限の「当たり前品質」担保 当たり前品質 一元的品質 魅力的品質 利用者 (障害無し) ❌ ー ー 利用者 (障害有り) ー ー ー これを最短距離で達成するテストは何か?

Slide 44

Slide 44 text

第3章:テストがない状況からの脱却 テストツールの守備範囲 ■ テストツールには得意・不得意がある ✅:優良(詳細・速い)/  🟠:守備範囲 / ❌:守備範囲外 snapshot (DOM) 機能テスト VRT axe (a11y) E2E jsdom + RTL ✅ ✅ ❌ ❌ ❌ Storybook 🟠 🟠 ✅ ✅ ❌ Playwright ❌ 🟠 🟠 🟠 🟠

Slide 45

Slide 45 text

第3章:テストがない状況からの脱却 テストツールの守備範囲 ■ Story はテストケースとして import し、jsdom で検証できる composeStories は Storybook v7 に標準機能として統合 snapshot (DOM) 機能テスト VRT axe (a11y) E2E jsdom + RTL ✅ ✅ ❌ ❌ ❌ Storybook ✅ ✅ ✅ ✅ ❌ Playwright ❌ 🟠 🟠 🟠 🟠 import import

Slide 46

Slide 46 text

第3章:テストがない状況からの脱却 はじめの自動テストとして ■  Storybook をお薦めする理由 ー  jsdom のテストケースとして Story を再利用 (composeStories) ー VRT (ビジュアルリグレッションテスト) や axe (a11y ) も ー テスト対象が細分化されているめ、欠陥を突き止めやすい ー テストケースの状態 (UI) が目視で確認できる ー MSW も使える その時のニーズにあわせて取捨選択できる

Slide 47

Slide 47 text

第3章:テストがない状況からの脱却 MSW って何だっけ? ■ Mock Service Worker ー モックサーバー(HTTP リクエストをインターセプトできる) ー UI コンポーネントに必要な、データ取得・更新 API を再現 ー Jest だけでなく、Web API 依存の Story が表現できる ー 例えば 「Web API 取得失敗した場合表示はこうなる」という Story MSW Storybook Addon:https://storybook.js.org/addons/msw-storybook-addon

Slide 48

Slide 48 text

第3章:テストがない状況からの脱却 MSW って何だっけ? ■ Mock Service Worker ー モックサーバー(HTTP リクエストをインターセプトできる) ー UI コンポーネントに必要な、データ取得・更新 API を再現 ー Jest だけでなく、Web API 依存の Story が表現できる ー 例えば 「Web API 取得失敗した場合表示はこうなる」という Story MSW を使った技術記事をいくつか投稿しています :https://zenn.dev/takepepe

Slide 49

Slide 49 text

第3章:テストがない状況からの脱却 段階的に自動テストを導入しよう ■ 自動テスト拡充のロードマップ(例) ー 1)ページ相当のコンポーネントを Story 登録 ー 2)MSW Storybook Addon を活用し、ページの Story を複数登録 ー 3)Storybook Play function を活用し、機能テストを追加する ー 4)Storybook Test runner が CI で実行されるよう設定 この段階で VRT(ビジュアルリグレッションテスト)があると尚良い

Slide 50

Slide 50 text

第3章:テストがない状況からの脱却 段階的に自動テストを導入しよう ■ 自動テスト拡充のロードマップ(例) リファクタリングに取り組める状態になった 当たり前品質 一元的品質 魅力的品質 利用者 (障害無し) ✅ ー ー 利用者 (障害有り) ❌ ー ー

Slide 51

Slide 51 text

第3章:テストがない状況からの脱却 段階的に自動テストを導入しよう ■ 自動テスト拡充のロードマップ(例) ー 5)コンポーネントを細分化していく ー 6)コンポーネントから処理を切り出す(関数・ Hooks) ー 7)切り出した処理の単体テストを拡充する ー 8)切り出したコンポーネントの a11y を当たり前品質に 「リファクタリング -> a11y 改善」を段階的に進める

Slide 52

Slide 52 text

第3章:テストがない状況からの脱却 段階的に自動テストを導入しよう ■ 自動テスト拡充のロードマップ(例) 自動テスト導入を機に「 a11y の当たり前品質」も満たしていきましょう 当たり前品質 一元的品質 魅力的品質 利用者 (障害無し) ✅ ー ー 利用者 (障害有り) ✅ ー ー

Slide 53

Slide 53 text

ご清聴ありがとうございました