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
webフロントエンドテストと自動化
Search
Cybozu
PRO
July 13, 2023
Technology
29k
43
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
webフロントエンドテストと自動化
Cybozu
PRO
July 13, 2023
More Decks by Cybozu
See All by Cybozu
サイボウズ 開発本部採用ピッチ / Cybozu Engineer Recruit
cybozuinsideout
PRO
12
89k
新卒1年目QAが リリース基準の"なぜ"をたどってみた
cybozuinsideout
PRO
1
830
kintone リサーチ副部/UXリサーチャー 業務紹介
cybozuinsideout
PRO
0
170
私たちが『JaSST協賛』から『外部コネクト』チームになった理由
cybozuinsideout
PRO
0
580
LLMでもいつものテスト技術〜意外と半分はこれまでのテストでした〜
cybozuinsideout
PRO
1
1.1k
kintone開発のプラットフォームエンジニアの紹介
cybozuinsideout
PRO
1
1.7k
LLMアプリの品質保証
cybozuinsideout
PRO
1
810
技術広報チームに丸投げしない!「一緒につくる」スポンサー活動
cybozuinsideout
PRO
0
300
テクニカルライター (グループウェア) について
cybozuinsideout
PRO
0
290
Other Decks in Technology
See All in Technology
Minecraft JavaのMODをSwiftで作る
1mash0
0
170
10Xに技術的負債をもたらした「2つの境界の歪み」その構造と解消への営み
10xinc
0
2k
Issue 駆動でスペシャリストの意図を届ける、AI 実装のアクセシビリティ向上
thkt
0
120
ユーザー価値を届け続けるためにウォンテッドリーが大切にしている文化
kotaminato
0
170
AI時代の「技術的負債」の変質ー概念の終焉と再解釈、エージェントと共に向かう先
nwiizo
1
2.8k
フルカイテン株式会社 エンジニア向け採用資料
fullkaiten
0
12k
Deployment の 先にある AI Agent 基盤 - kagent vNext、Agent Substrate、Hermes から読み解く Agent Runtime の現在地 / k8s-matsuri-2-ai-agent-platform-amsy810
masayaaoyama
4
630
ADKで始める業務改善 - AIエージェント開発時の考えと設計
harappa80
2
160
AIエージェントを最高のパートナーに育てる方法|評価と判断軸を育てる5つのステップ
koichiaoki
1
150
安心して変更できるWebフロントエンドの作り方
pirosikick
5
2.7k
空間オーディオで過去の 自分(ゴースト)と競うランニング 〜HealthKitのルートを足音に変える実装〜
nao_randd
0
220
aws-iot-platform-architecture-use-cases.pdf
ma2shita
0
250
Featured
See All Featured
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
520
KATA
mclloyd
PRO
35
15k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
500
Building Adaptive Systems
keathley
44
3.2k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
SEO for Brand Visibility & Recognition
aleyda
0
4.7k
Everyday Curiosity
cassininazir
0
320
Are puppies a ranking factor?
jonoalderson
2
3.9k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
330
Balancing Empowerment & Direction
lara
6
1.3k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
4.8k
Building Applications with DynamoDB
mza
96
7.2k
Transcript
webフロントエンドテスト ⾃動化 フロントエンドエキスパートチーム 左治⽊隆成
コンセプト 誰に • webフロントエンド開発に携わる⼈たちに なんと⾔ってほしい • 「フロントエンドテストの書き⽅にイメージがついた」 • 「最近のwebフロントエンドのテストの潮流をつかめた」 •
「フロントエンドのテスト書いてくぞー!!!!」
⽬次 1. テストコードについておさらい • テストコードの意義などを軽くおさらい 2. フロントエンドテストの⽬的と⼿法 • どういった種類のテストがあるのか •
何を保証したくてフロントエンドテストを書くのか 3. フロントエンドテストを⽀える技術 • どのようにフロントエンドテストを書いていけば良いのか • 具体的なライブラリの使い⽅を知る 4. テストを書いてみよう! • 実際にインテグレーションテストを書いてみる
テストコードについて 何のためにテストを書くのか? • サービスの信頼のため • コードに⾃信を持つため • 綺麗なコードを維持するため • コミュニケーションのため
• リファクタをしやすくするため • …etc
テストコードを書こう!
開発スピードが遅くなる? → そんなことはない!
品質とスピードはトレードオフではない • 「内部品質を犠牲にしているから遅い」 • “内部品質への投資の損益分岐点は 3年後とかではなく 1ヶ⽉以内に現 れる” • 参考)
3⽉に来ていただいた t-wadaさんの社内公演を聞くべし • (社内向けリンク)
テストコードの意義 • 数ヶ⽉先に⾃分が書いたコードが残っているはずならちゃんとテスト を書こう • 実際kintoneのClosureのコードは10年⽣きてます。 • そうでなくても数ヶ⽉前の⾃分は他⼈です • 実装している時でも、「テストコード書いたおかげでレビュー前に実
装が不⾜してる箇所を気づけた」といったことがある
テストコードを書こう!
でもどう書けばいいのさ
フロントエンドテストの ⽬的と⼿法
テスト範囲による分類 ⼀般的に4つの範囲に分けることが多い • 静的解析 • 単体テスト • 結合テスト • E2Eテスト
静的解析 • lintツール、型解析ツールと呼ばれるもの • モジュール間のインターフェース不整合やコードの表現の⼀貫性を保 証する
単体テスト • ⼀つのモジュールの機能を保証する • 複雑なモジュールのエッジケースなどを検証するのに有効 • ユニット(Unit)テストとも
結合テスト • 複数のモジュールを組み合わせた挙動・機能をテストする • ある程度広範囲なテストをカバーできる • インテグレーション(integration)テストとも
E2Eテスト • 本番相当の環境で、システム・アプリケーションが⼀貫して動作する ことを確認するテスト • フロントエンド〜バックエンドを⼀貫してテストする • よりユーザーの体験に近い形でテストができる
それぞれの特徴 静的解析 単体テスト 結合テスト E2Eテスト 実⾏コスト テスト範囲 不安定さ 低 ⾼
広 狭 不安定 安定
テストピラミッドモデルへ 静的解析→単体テスト→結合テスト→E2Eテストの順に • 👎 実⾏保守コストや開発・実⾏速度は⾼くなる • 👍 広範囲のテストが可能になっていく → テストの⽐率をピラミッド型にすればコストと保証する品質のバラ
ンスが取れるのでは?
テストピラミッド E2E 結合テスト 単体テスト $ $ $ ¢ 🏎 🐢
…ここまでが復習
フロントエンドにフォーカス するとどうなるか?
前提1 : 近年のフロントエンドの進化 • サーバーサイドとフロントエンドが別れた世界に • フロントエンドできること・やることが増える • 複雑な状態管理 •
SPA によるシームレスなUI更新 • ServiceWorkerによるキャッシュ管理やオフライン対応 • etc… → フロントエンド単体で複雑性が増している。
前提2 : フロントエンド特有なこと • ユーザーからのインタラクションを起点に動作する • ある程度単純なコンポーネントの挙動の組み合わせで複雑になりがち • ⽂書構造があり、それをブラウザや読み上げソフトが解釈する •
⾒た⽬・スタイルがある
フロントエンドにフォーカスすると⾒えてきたもの • フロントエンドの進化 • フロントエンドに閉じてても複雑な挙動が増える • フロントエンド特有の事情 • ⼀つのコンポーネントだけで成⽴する機能は少ない •
ユーザーからのインタラクションを起点に動作する • ⾒た⽬・⽂書構造がある
フロントエンドに特化するとどうなるか • Testing trophyモデルの提唱 • フロントエンド特有の事情を鑑みた新しいテストモデルの提唱 • VRT・a11yテストの普及 • ⾒た⽬・⽂書構造があるをテストする⼿段
Testing trophyモデル • kent.c.Dodds⽒が提唱するモデル • The Testing Trophy and Testing
Classifications • コード・ロジックのカバレッジではなく、 ユーザーからみたユースケースのカバレッ ジを重視すべきという考えに基づく
Testing trophyモデル • スピード・コストに加えて信頼度とのバランスをとる • 信頼度 = どれだけ動作に⾃信を得られるか。 • “The
more your tests resemble the way your software is used, the more confidence they can give you.” • ユーザーの操作を起点とした、複数のモジュール・コンポーネントを 跨ぐテストをコストを抑えつつ書いていきたい • 結合テストを充実させていくと良いのではないか • Write tests. Not too many. Mostly integration.
Testing trophy : 静的解析 • LintやTypeScriptが該当する • ⼀般的にカバレッジには含まれない • 適切なルールの運⽤と型を厳格にすること
でロジックのミスをかなり減らすことがで きる
Testing trophy : 単体テスト • オブジェクト・関数、hooks、単体コン ポーネントのテストなどが該当する • エッジケースの多いロジックなど⼀つのモ ジュール単位で複雑な挙動をもつものには
最適
Testing trophy : 結合テスト • コンポーネントや関数など複数のものが合 わさったもののテスト • ここを厚くすることでユースケースのカバ レッジをあげる
• 使われているコンポーネントや機能の結合 テストが通れば、動きが保証できる
Testing trophy : E2Eテスト • 信頼度が⼀番⾼く、コストもかかるもの • 重要なユーザー体験や最低限の動作を保証 するなどの利⽤することが多い
結合テストのコスト Q . 結合テストの実⾏コスト⾼くないの? A. 後述する「DOMをエミュレートする」タイプのテストツールだと以 下のような理由からE2Eテストより実⾏コストを低く抑えられる • ヘッドレスブラウザを介していない •
通信やIOを基本的にモックしている
VRTとa11yテスト
VRT : Visual Regression Test = ⾒た⽬の回帰テスト つまり「⾒た⽬変わっちゃってない?」を毎度確認するテスト
a11yテスト • Lintツールである程度チェック可能 • eslint-plugin-jsx-a11y など • コンポーネントの結合テストなどでもアクシブルな情報を利⽤した操 作などでテストが可能(後述) •
読み上げなど、⾃動化が難しいものは別途⼿動試験をしたりできると 良い
フロントエンドテスト を⽀える技術
各テストよく使われるライブラリ • 静的解析 • eslint : JavaScriptのリントツールとしてデファクトなライブラリ • Typescript :
型チェックを⾏える • 単体テスト • Jest : メジャーなJavaScriptテストフレームワーク • Vitest : Jest互換の⽐較的新しいJavaScriptテストフレームワーク
各テストよく使われるライブラリ • 結合テスト • Testing Library : Domをエミュレートして動作を実⾏確認できるツール • jest-dom
: jestのDOM⽤拡張。DOM⽤のマッチャーなどが追加される。 • E2Eテスト • Cypress : Selenium以降に台頭したE2Eテストフレームワーク • PlayWright : Microsoftが中⼼に開発する後発のOSS E2Eテストツール。
各テストよく使われる技術 VRTテスト • Chromatic (Storybook) • Storybook公式が提供するサービス。 • Storybookで表⽰するコンポーネントでそのままVRTが可能。 •
reg-suite × E2Eテストツールによるスクリーンショット • E2Eテストツール で撮ったスクリーンショットを元にVRTを実⾏する
実際にどんな感じ書くの?
実践編 Testing LibraryとJestを使った 結合テストの書き⽅ Write tests. Not too many. Mostly
integration.
結合テストの3要素 やりたいことは基本的に3つ 1. 要素を探して取ってきて 2. 何らかの操作をして 3. 結果を検証する
結合テストの3要素 それぞれの分担 • 要素を探して取ってきて : TestingLibrary • 何らかの操作をして : TestingLibrary
• 結果を検証する : Jest(の拡張) / TestingLibrary
要素を探す
要素の探し⽅ 以下のような感じで要素を取得する • TestingLibraryには⾊々な要素の探し⽅(=クエリ)がある。 • 適切なクエリを使って要素を取得することが⼤事 const addButton = await
screen.findByRole('button’)}
TestingLibraryのクエリ分類 get find query All (なし) ByRole ByLabelText ByPlaceholderText ByText
ByDisplayValue ByAltText ByTitle ByTestId
TestingLibraryのクエリ分類1 get〇〇 / query〇〇/ find〇〇 の違いと Allのあるなし ⾒つからない時 1つ⾒つかった場 合
2つ以上⾒つかっ た場合 ⾒つからない場合 にretry getBy◦◦ error 要素 error しない queryBy◦◦ nullを返す 要素 error しない findBy◦◦ error 要素 error する getAllBy◦◦ error 要素⼀つの配列 複数要素の配列 しない queryAllBy◦◦ 空配列を返す 要素⼀つの配列 複数要素の配列 しない findAllBy◦◦ error 要素⼀つの配列 複数要素の配列 する
TestingLibraryのクエリ分類2 どのような特徴で要素を探すか(By〇〇の部分) • 使うクエリには優先度がある • 適切なクエリを使って要素を取得することが⼤事(再掲) 原則 : ユーザーの操作に沿うこと ..「ユーザーの操作に沿う」ってなに?
よくありがちだけど🫤な取得⽅法 body → div[0] → ul → li[0] → …
→ button • みんな普段ページを操作するとき、DOM treeみて要素探してるの? getById("password-input") • みんなDOMのIdとかClassName⾒てページ操作してるの?
そんなわけない!
普段の操作を思い出してみる ユーザー名とパスワードを⼊⼒してログインしてください
普段の操作を思い出してみる どうして上のテキストボックスがログイン名だと分かった? • → プレイスホルダーにログイン名って書いてあったから どうして右下がログインボタンだと分かった? • → ログインと書いてあるボタンだから
優先されるべきクエリ 以下のような情報から要素を取得すべき • アクセシビリティロール • ラベル • placeholder • テキスト
これらは視覚的な認知とスクリーンリーダーなどによる機械的な解釈が ⼀致している(はず)から
視覚的認知できるのにうまく取得できない… = ⾒た⽬と⽂章の構造・解釈が⼀致していない = そもそもa11y上の問題を抱えている可能性が⾼い 可能な限り治しましょう! 誰でもアクセスできる情報をもとにしたクエリから要素を取得すること はa11yを確認することにもつながる!
具体的なTestingLibraryのクエリ 全ての⼈にとってアクセシブルなクエリ(なるべくこれを使おう) • ByRole : WAI-ARIAのrole属性から取得する • ByLabelText : フォームなどのラベルから取得する
• ByPlaceholderText : ⽂字⼊⼒のプレイスホルダーから取得する • ByText : ⼊⼒とかではない⽂書コンテンツなどを取得する • ByDisplayValue : フォームないの現在値から取得する。
具体的なTestingLibraryのクエリ HTML5 および ARIA 準拠ではあるものの挙動・解釈はブラウザ・⽀援 技術によって⼤きく異なるクエリ • ByAltText : 画像などををalt
text から取得する • ByTitle : title属性から要素を取得する。
具体的なTestingLibraryのクエリ どうしてもうまく要素が取れない時・要素が動的に⽣成される時などに 利⽤するクエリ • ByTestId : 要素につけた data-testid 属性か要素を取得する
結合テストの3要素 やりたいことは基本的に3つ 1. 要素を探して取ってきて 2. 何らかの操作をして 3. 結果を検証する
要素に対する操作 userEventオブジェクトを利⽤する クリック • userEvent.click([クリックしたい要素]) テキスト⼊⼒ • userEvent.type([⼊⼒したい要素],”打ちたい⽂字列”)
結合テストの3要素 やりたいことは基本的に3つ 1. 要素を探して取ってきて 2. 何らかの操作をして 3. 結果を検証する
よくある検証したいこと 特定の要素があるか?or 消えているか? 要素が特定の数あるか? 正しくリクエストが⾶んでいるか?
特定の要素があるか?or 消えているか? testing-library とjestを使う // 要素があるか? // → 要素を findBy
や getBy で取得する(⾒つからないとErrorになるので) const addButton = await screen.findByRole('button', { name: '追加' }); // 要素が消えているか? // → 要素を queryByで取得し、null であることを確かめる const addButton = screen.queryByRole('button', { name: '追加' }); expect(addButton).toBeNull();
要素が特定の数あるか? testing-library とjestを使う // 要素が特定の数あるか? // → 要素を findAllBy などで探し
const nameList = await screen.findAllByRole('listItem’,); // 個数を確かめる expect(nameList.length).toBe(3);
正しくリクエストが⾶んでいるか? ..の前にリクエストのモック(テストダブル)が必要
リクエストのモックについて 結合テストがカバーできるのはフロントエンドの範囲内 • = 通信はモックする(ダミーを作る)必要がある ServerSide FrontEnd request ?
通信のモック 最近では msw (mock service worker) というライブラリを使うことが 多い • service
worker上で通信を横取りする • リクエストに対応したレスポンスを設定しておくことで通信をモック Jestと併⽤するとリクエストの中⾝・呼ばれた回数・タイミングなどを 検査できる
通信のモック イメージ ServerSide FrontEnd request MSW response(mock) requestを⾒る & いい感じの
mockを返す
改 : 正しくリクエストが⾶んでいるか? リクエストのモックとjestのモック関数を使う 1. jest.fn() を利⽤してモック関数を作る • モック関数 =
どんな引数で呼ばれたか・何回呼ばれたかなどを検証可能 2. リクエストをモックする(※⽅法は後述) 3. 2.でリクエストが来たらモック関数にリクエストの中⾝を渡す 4. モック関数がどう呼び出されたか検証する
TestingLibraryを⽤いた結合テストだと難しいもの 1. ホバー時のスタイル確認 • DOMをエミュレートしてるだけなのでCSSの機能を確認するのは難しい 2. ドラッグ&ドロップのような操作 • ドラッグの位置情報などを計算することは基本できない 3.
スクロールの絡む操作 • そもそも画⾯のサイズによって変わるのものなので難しい
⻑々と話してきましたが…
講義だけだど眠くなっちゃう ので実際に書いてみよう!
演習
演習で使う環境について軽く説明 今回はStorybookを利⽤ • Storybookでコンポーネントのインタラクションテストが書ける • = Storybook上でJestやtesting-libraryが動いてるイメージ • メリット •
⽬で実⾏結果が確認できる • 環境構築が楽
演習をする前に 必要なもの • git 環境 • Node.js v18 以上の環境 •
(社内リンク) • お気に⼊りのエディタ • 宗教上の理由がなければ vscode が楽です。
演習準備 1. 以下のリポジトリをclone • https://github.com/sajikix/frontend-test-training-2023 2. README.mdを開く 3. READMEに従って storybookを起動
1. npm ci と npm run storybook を叩くだけ 4. うまく⾏くと https://localhost:6006 でstorybookが起動する。
Storybookの操作説明 画⾯共有して説明します。
コードの軽い説明 • src/page にテスト対象のコンポーネントがいる • 〇〇.stories.tsx ファイルがStorybookを表⽰するためのファイル • 〇〇.stories.tsx ファイルを開くと、Task1
みたいな名前のオブジェク トがある • この⼀つ⼀つがStorybookObjectと呼ばれるものでStorybook上の1 ページに対応してる
StorybookObjectの説明 • play関数の中に処理を書いていく • Storybook上で書かない場合と⼤まかには⼀緒! • セットアップとかcanvas取ってくるとこが微妙に違うくらい • 変更して保存すると⾃動的にStorybookがリロードされる
問題を解いてみよう! • 問題1~5を⽳埋めで書いてみよう • 書けたと思ったらStorybookのinteractionタブを確認! • うまく動いていればPASSEDになるよ! • 解答例は answers/
にあるので解けたら⾒てみよう • 質問あったら遠慮なくコメントください !
盛り込めなかった話 E2Eテストでの⾃動化⼿法について VRTテストの詳しい実装⽅法 単体テストとの細かい境界 キーボード操作など少し複雑な操作について
参考⽂献・学びたい⼈へ 参考⽂献 • https://kentcdodds.com/blog • https://testing-library.com/ • https://jestjs.io/ より詳しく学びたい⼈へ •
『フロントエンド開発のためのテスト⼊⾨ 今からでも知っておきたい ⾃動テスト戦略の必須知識』吉井 健⽂ (著) がおすすめです。