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

退屈なブラウザテストはCodeceptJSにやらせよう

tsuemura
March 24, 2019

 退屈なブラウザテストはCodeceptJSにやらせよう

2019/3/24 SeleniumConf Tokyo 2019 事前勉強会

tsuemura

March 24, 2019
Tweet

More Decks by tsuemura

Other Decks in Technology

Transcript

  1. 退屈なブラウザテストは 退屈なブラウザテストは 退屈なブラウザテストは 退屈なブラウザテストは 退屈なブラウザテストは 退屈なブラウザテストは CodeceptJS にやらせよう CodeceptJS にやらせよう

    CodeceptJS にやらせよう CodeceptJS にやらせよう CodeceptJS にやらせよう CodeceptJS にやらせよう 末村 拓也 @ 株式会社オープンロジ 末村 拓也 @ 株式会社オープンロジ 末村 拓也 @ 株式会社オープンロジ 末村 拓也 @ 株式会社オープンロジ 末村 拓也 @ 株式会社オープンロジ 末村 拓也 @ 株式会社オープンロジ 1 / 72
  2. はじめまして はじめまして はじめまして はじめまして はじめまして はじめまして 末村 拓也(すえむら たくや) 末村

    拓也(すえむら たくや) 末村 拓也(すえむら たくや) 末村 拓也(すえむら たくや) 末村 拓也(すえむら たくや) 末村 拓也(すえむら たくや) 物流スタートアップ「OPENLOGI 」のQA エンジニア 物流スタートアップ「OPENLOGI 」のQA エンジニア 物流スタートアップ「OPENLOGI 」のQA エンジニア 物流スタートアップ「OPENLOGI 」のQA エンジニア 物流スタートアップ「OPENLOGI 」のQA エンジニア 物流スタートアップ「OPENLOGI 」のQA エンジニア です です です です です です まんがとヒトカラがすきです まんがとヒトカラがすきです まんがとヒトカラがすきです まんがとヒトカラがすきです まんがとヒトカラがすきです まんがとヒトカラがすきです                   2 / 72
  3. エンジニア歴短めです エンジニア歴短めです エンジニア歴短めです エンジニア歴短めです エンジニア歴短めです エンジニア歴短めです 新卒から5 年間ぐらいフォークリフト乗ってました 新卒から5 年間ぐらいフォークリフト乗ってました

    新卒から5 年間ぐらいフォークリフト乗ってました 新卒から5 年間ぐらいフォークリフト乗ってました 新卒から5 年間ぐらいフォークリフト乗ってました 新卒から5 年間ぐらいフォークリフト乗ってました エンジニアを名乗り始めたのはここ3 年ぐらい エンジニアを名乗り始めたのはここ3 年ぐらい エンジニアを名乗り始めたのはここ3 年ぐらい エンジニアを名乗り始めたのはここ3 年ぐらい エンジニアを名乗り始めたのはここ3 年ぐらい エンジニアを名乗り始めたのはここ3 年ぐらい 3 / 72
  4. 今日はこの記事で登場した技術を使って 今日はこの記事で登場した技術を使って 今日はこの記事で登場した技術を使って 今日はこの記事で登場した技術を使って 今日はこの記事で登場した技術を使って 今日はこの記事で登場した技術を使って ブラウザテスト自動化を ブラウザテスト自動化を ブラウザテスト自動化を ブラウザテスト自動化を

    ブラウザテスト自動化を ブラウザテスト自動化を 圧倒的に効率化していきます 圧倒的に効率化していきます 圧倒的に効率化していきます 圧倒的に効率化していきます 圧倒的に効率化していきます 圧倒的に効率化していきます (記事を読んでいない方もお楽しみいただけます) (記事を読んでいない方もお楽しみいただけます) (記事を読んでいない方もお楽しみいただけます) (記事を読んでいない方もお楽しみいただけます) (記事を読んでいない方もお楽しみいただけます) (記事を読んでいない方もお楽しみいただけます) 5 / 72
  5. 記事ではPuppeteer を使いましたが 記事ではPuppeteer を使いましたが 記事ではPuppeteer を使いましたが 記事ではPuppeteer を使いましたが 記事ではPuppeteer を使いましたが

    記事ではPuppeteer を使いましたが このセッションではSelenium を使います このセッションではSelenium を使います このセッションではSelenium を使います このセッションではSelenium を使います このセッションではSelenium を使います このセッションではSelenium を使います 6 / 72
  6. 皆さん 皆さん 皆さん 皆さん 皆さん 皆さん ブラウザテスト ブラウザテスト ブラウザテスト ブラウザテスト

    ブラウザテスト ブラウザテスト 自動化してますか? 自動化してますか? 自動化してますか? 自動化してますか? 自動化してますか? 自動化してますか? 8 / 72
  7. 言わなくても待ってて欲しいですね 言わなくても待ってて欲しいですね 言わなくても待ってて欲しいですね 言わなくても待ってて欲しいですね 言わなくても待ってて欲しいですね 言わなくても待ってて欲しいですね (Implicitly Wait でもいいんだけど有効範囲が限定的なイメージ) (Implicitly

    Wait でもいいんだけど有効範囲が限定的なイメージ) (Implicitly Wait でもいいんだけど有効範囲が限定的なイメージ) (Implicitly Wait でもいいんだけど有効範囲が限定的なイメージ) (Implicitly Wait でもいいんだけど有効範囲が限定的なイメージ) (Implicitly Wait でもいいんだけど有効範囲が限定的なイメージ) 19 / 72
  8. __.. - ―─ 、__ __.. - ―─ 、__ /` 三ミー

    ヘ、_ /` 三ミー ヘ、_ ゝ' ;; ,, , ,, ミミ , il ゙Z, ゝ' ;; ,, , ,, ミミ , il ゙Z, _ 〉,.. ////, , 彡ff ッィ彡从j 彡 _ 〉,.. ////, , 彡ff ッィ彡从j 彡 〉, ィiiif , ,, ' ノ川j ノ川; :. `フ公) 了 〉, ィiiif , ,, ' ノ川j ノ川; :. `フ公) 了 \.:.:.:i= 珍/二''= く、 ! ノ一ヾ゙;.;.; ) \.:.:.:i= 珍/二''= く、 ! ノ一ヾ゙;.;.; ) く:.:.:.:l ムj イ rf モテ〉゙} ij ィt ケ 1 イ'´ く:.:.:.:l ムj イ rf モテ〉゙} ij ィt ケ 1 イ'´ 〕:.:.|,Y!:! 、 ニ ' 、 ; | `ニ イj' 逆に考えるんだ 〕:.:.|,Y!:! 、 ニ ' 、 ; | `ニ イj' 逆に考えるんだ {:.:.:j {: :} ` 、_{__} / ノ {:.:.:j {: :} ` 、_{__} / ノ 〉イ 、゙! , ィ__ 三ー、 j ′ 「これらをやらなければテストは楽に書けるはずさ」 〉イ 、゙! , ィ__ 三ー、 j ′ 「これらをやらなければテストは楽に書けるはずさ」 ,{ \ ミ \ ゝ' ェェ' `' / ,{ \ ミ \ ゝ' ェェ' `' / -‐' \ \ ヽ\ 彡 イ- 、 と考えるんだ -‐' \ \ ヽ\ 彡 イ- 、 と考えるんだ \ \. ヽゝ‐‐‐ 升 ト、 ヽ、__ \ \. ヽゝ‐‐‐ 升 ト、 ヽ、__ \ ヽ- 、./ / j!:.} ` ー 、 \ ヽ- 、./ / j!:.} ` ー 、 ヽ\ 厶_r__ ハ/!:.{ ヽ\ 厶_r__ ハ/!:.{ ´ / ! ヽ ´ / ! ヽ 26 / 72
  9. 裏を返せば 裏を返せば 裏を返せば 裏を返せば 裏を返せば 裏を返せば これらをやらなければ これらをやらなければ これらをやらなければ これらをやらなければ

    これらをやらなければ これらをやらなければ テストは楽に書ける(はず) テストは楽に書ける(はず) テストは楽に書ける(はず) テストは楽に書ける(はず) テストは楽に書ける(はず) テストは楽に書ける(はず) 27 / 72
  10. ブラウザテストを楽に書くコツ ブラウザテストを楽に書くコツ ブラウザテストを楽に書くコツ ブラウザテストを楽に書くコツ ブラウザテストを楽に書くコツ ブラウザテストを楽に書くコツ CSS セレクタやXPath を(なるべく)使わない CSS

    セレクタやXPath を(なるべく)使わない CSS セレクタやXPath を(なるべく)使わない CSS セレクタやXPath を(なるべく)使わない CSS セレクタやXPath を(なるべく)使わない CSS セレクタやXPath を(なるべく)使わない 動かなかったら自動でリトライさせる 動かなかったら自動でリトライさせる 動かなかったら自動でリトライさせる 動かなかったら自動でリトライさせる 動かなかったら自動でリトライさせる 動かなかったら自動でリトライさせる 一行ずつ動かしながら書く 一行ずつ動かしながら書く 一行ずつ動かしながら書く 一行ずつ動かしながら書く 一行ずつ動かしながら書く 一行ずつ動かしながら書く                   28 / 72
  11. CodeceptJS ってなんなの? CodeceptJS ってなんなの? CodeceptJS ってなんなの? CodeceptJS ってなんなの? CodeceptJS ってなんなの?

    CodeceptJS ってなんなの? https://codecept.io https://codecept.io https://codecept.io https://codecept.io https://codecept.io https://codecept.io NodeJS 製のブラウザテストフレームワーク NodeJS 製のブラウザテストフレームワーク NodeJS 製のブラウザテストフレームワーク NodeJS 製のブラウザテストフレームワーク NodeJS 製のブラウザテストフレームワーク NodeJS 製のブラウザテストフレームワーク 他のブラウザ操作フレームワークと組み合わせる 他のブラウザ操作フレームワークと組み合わせる 他のブラウザ操作フレームワークと組み合わせる 他のブラウザ操作フレームワークと組み合わせる 他のブラウザ操作フレームワークと組み合わせる 他のブラウザ操作フレームワークと組み合わせる ことでブラウザやモバイル実機を操作できる ことでブラウザやモバイル実機を操作できる ことでブラウザやモバイル実機を操作できる ことでブラウザやモバイル実機を操作できる ことでブラウザやモバイル実機を操作できる ことでブラウザやモバイル実機を操作できる 受け入れテストを直感的に分かりやすく書くこと 受け入れテストを直感的に分かりやすく書くこと 受け入れテストを直感的に分かりやすく書くこと 受け入れテストを直感的に分かりやすく書くこと 受け入れテストを直感的に分かりやすく書くこと 受け入れテストを直感的に分かりやすく書くこと に注力している に注力している に注力している に注力している に注力している に注力している                   30 / 72
  12. CodeceptJS の様々な機能の中から CodeceptJS の様々な機能の中から CodeceptJS の様々な機能の中から CodeceptJS の様々な機能の中から CodeceptJS の様々な機能の中から

    CodeceptJS の様々な機能の中から ブラウザテスト記述を特に楽にしてくれる ブラウザテスト記述を特に楽にしてくれる ブラウザテスト記述を特に楽にしてくれる ブラウザテスト記述を特に楽にしてくれる ブラウザテスト記述を特に楽にしてくれる ブラウザテスト記述を特に楽にしてくれる 3 つの機能を紹介します 3 つの機能を紹介します 3 つの機能を紹介します 3 つの機能を紹介します 3 つの機能を紹介します 3 つの機能を紹介します Semantic Locator Semantic Locator Semantic Locator Semantic Locator Semantic Locator Semantic Locator retryFailedStep Plugin retryFailedStep Plugin retryFailedStep Plugin retryFailedStep Plugin retryFailedStep Plugin retryFailedStep Plugin Debugger Debugger Debugger Debugger Debugger Debugger                   32 / 72
  13. 必要なもの 必要なもの 必要なもの 必要なもの 必要なもの 必要なもの NodeJS v8.9 以上 NodeJS

    v8.9 以上 NodeJS v8.9 以上 NodeJS v8.9 以上 NodeJS v8.9 以上 NodeJS v8.9 以上 npm npm npm npm npm npm Javascript チョット デキル Javascript チョット デキル Javascript チョット デキル Javascript チョット デキル Javascript チョット デキル Javascript チョット デキル UNIX 系OS 前提で話しますが UNIX 系OS 前提で話しますが UNIX 系OS 前提で話しますが UNIX 系OS 前提で話しますが UNIX 系OS 前提で話しますが UNIX 系OS 前提で話しますが Windows でも普通に動く(はず) Windows でも普通に動く(はず) Windows でも普通に動く(はず) Windows でも普通に動く(はず) Windows でも普通に動く(はず) Windows でも普通に動く(はず)                   35 / 72
  14. インストールは簡単です インストールは簡単です インストールは簡単です インストールは簡単です インストールは簡単です インストールは簡単です $ $ mkdir mkdir

    sample sample && && cd cd sample sample $ $ npm npm init init # Enter 連打!!!!! # Enter 連打!!!!! $ $ npm npm install install codeceptjs webdriverio codeceptjs webdriverio $ npx codeceptjs init $ npx codeceptjs init # Enter 連打!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # Enter 連打!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 36 / 72
  15. Selenium Server Selenium Server Selenium Server Selenium Server Selenium Server

    Selenium Server 別途インストールし起動しておいてください 別途インストールし起動しておいてください 別途インストールし起動しておいてください 別途インストールし起動しておいてください 別途インストールし起動しておいてください 別途インストールし起動しておいてください やりかたがわからない方向け やりかたがわからない方向け やりかたがわからない方向け やりかたがわからない方向け やりかたがわからない方向け やりかたがわからない方向け $ $ sudo sudo npm npm install install -g selenium-standalone -g selenium-standalone $ selenium-standalone $ selenium-standalone install install $ selenium-standalone start $ selenium-standalone start 37 / 72
  16. ここでもういちどおさらい ここでもういちどおさらい ここでもういちどおさらい ここでもういちどおさらい ここでもういちどおさらい ここでもういちどおさらい ブラウザテストを楽に書くコツ ブラウザテストを楽に書くコツ ブラウザテストを楽に書くコツ ブラウザテストを楽に書くコツ

    ブラウザテストを楽に書くコツ ブラウザテストを楽に書くコツ CSS セレクタやXPath を(なるべく)使わない CSS セレクタやXPath を(なるべく)使わない CSS セレクタやXPath を(なるべく)使わない CSS セレクタやXPath を(なるべく)使わない CSS セレクタやXPath を(なるべく)使わない CSS セレクタやXPath を(なるべく)使わない 動かなかったら自動でリトライさせる 動かなかったら自動でリトライさせる 動かなかったら自動でリトライさせる 動かなかったら自動でリトライさせる 動かなかったら自動でリトライさせる 動かなかったら自動でリトライさせる 一行ずつ動かしながら書く 一行ずつ動かしながら書く 一行ずつ動かしながら書く 一行ずつ動かしながら書く 一行ずつ動かしながら書く 一行ずつ動かしながら書く                   39 / 72
  17. 書く時は 書く時は 書く時は 書く時は 書く時は 書く時は 一行ずつ動かしながら 一行ずつ動かしながら 一行ずつ動かしながら 一行ずつ動かしながら

    一行ずつ動かしながら 一行ずつ動かしながら CSS やXPath をなるべく使わず CSS やXPath をなるべく使わず CSS やXPath をなるべく使わず CSS やXPath をなるべく使わず CSS やXPath をなるべく使わず CSS やXPath をなるべく使わず 動かす時は 動かす時は 動かす時は 動かす時は 動かす時は 動かす時は 動かない時は適宜リトライさせる 動かない時は適宜リトライさせる 動かない時は適宜リトライさせる 動かない時は適宜リトライさせる 動かない時は適宜リトライさせる 動かない時は適宜リトライさせる という方針でやってみましょう という方針でやってみましょう という方針でやってみましょう という方針でやってみましょう という方針でやってみましょう という方針でやってみましょう                   40 / 72
  18. 例として 例として 例として 例として 例として 例として Github のユーザー登録フォームをテストします Github のユーザー登録フォームをテストします

    Github のユーザー登録フォームをテストします Github のユーザー登録フォームをテストします Github のユーザー登録フォームをテストします Github のユーザー登録フォームをテストします 41 / 72
  19. 一行ずつ動かしながら書く 一行ずつ動かしながら書く 一行ずつ動かしながら書く 一行ずつ動かしながら書く 一行ずつ動かしながら書く 一行ずつ動かしながら書く $ npx codeceptjs shell

    $ npx codeceptjs shell → 対話型コンソールが起動します → 対話型コンソールが起動します → 対話型コンソールが起動します → 対話型コンソールが起動します → 対話型コンソールが起動します → 対話型コンソールが起動します 42 / 72
  20. 次のコードを入力していきます 次のコードを入力していきます 次のコードを入力していきます 次のコードを入力していきます 次のコードを入力していきます 次のコードを入力していきます > > I I.

    .amOnPage amOnPage( ('https://github.com' 'https://github.com') ) > > I I. .fillField fillField( ('Username' 'Username', , 'shen-long1234' 'shen-long1234') ) > > I I. .fillField fillField( ('Email' 'Email', , '[email protected]' '[email protected]') ) > > I I. .fillField fillField( ('Password' 'Password', , 'P@ssword1234' 'P@ssword1234') ) > > I I. .click click( ('Sign up for GitHub' 'Sign up for GitHub') ) 43 / 72
  21. 動いたのでそのままコピペして 動いたのでそのままコピペして 動いたのでそのままコピペして 動いたのでそのままコピペして 動いたのでそのままコピペして 動いたのでそのままコピペして 再実行しましょう 再実行しましょう 再実行しましょう 再実行しましょう

    再実行しましょう 再実行しましょう Feature Feature( ('Github' 'Github') ) Scenario Scenario( ('Can Sign Up' 'Can Sign Up', , async async ( (I I) ) => => { { I I. .amOnPage amOnPage( ('https://github.com' 'https://github.com') ) I I. .fillField fillField( ('Username' 'Username', , 'shen-long1234' 'shen-long1234') ) I I. .fillField fillField( ('Email' 'Email', , '[email protected]' '[email protected]') ) I I. .fillField fillField( ('Password' 'Password', , 'P@ssword1234' 'P@ssword1234') ) I I. .click click( ('Sign up for GitHub' 'Sign up for GitHub') ) } }) ) → → → → → → github_test.js github_test.js github_test.js github_test.js github_test.js github_test.js として保存 として保存 として保存 として保存 として保存 として保存 45 / 72
  22. 実行 実行 実行 実行 実行 実行 $ npx codeceptjs run

    github_test.js --steps $ npx codeceptjs run github_test.js --steps Github -- Github -- Can Sign Up Can Sign Up I am on page "https://github.com" I am on page "https://github.com" I fill field "Username", "shen-long1234" I fill field "Username", "shen-long1234" I fill field "Email", "[email protected]" I fill field "Email", "[email protected]" I fill field "Password", "P@ssword1234" I fill field "Password", "P@ssword1234" I click "Sign up for GitHub" I click "Sign up for GitHub" ✔ OK in 5593ms ✔ OK in 5593ms 46 / 72
  23. ここでもう一度コードを見てみます ここでもう一度コードを見てみます ここでもう一度コードを見てみます ここでもう一度コードを見てみます ここでもう一度コードを見てみます ここでもう一度コードを見てみます Feature Feature( ('Github' 'Github')

    ) Scenario Scenario( ('Can Sign Up' 'Can Sign Up', , async async ( (I I) ) => => { { I I. .amOnPage amOnPage( ('https://github.com' 'https://github.com') ) I I. .fillField fillField( ('Username' 'Username', , 'shen-long1234' 'shen-long1234') ) I I. .fillField fillField( ('Email' 'Email', , '[email protected]' '[email protected]') ) I I. .fillField fillField( ('Password' 'Password', , 'P@ssword1234' 'P@ssword1234') ) I I. .click click( ('Sign up for GitHub' 'Sign up for GitHub') ) } }) ) CSS セレクタの類は全然出てきませんね CSS セレクタの類は全然出てきませんね CSS セレクタの類は全然出てきませんね CSS セレクタの類は全然出てきませんね CSS セレクタの類は全然出てきませんね CSS セレクタの類は全然出てきませんね 47 / 72
  24. Semantic Locator とは Semantic Locator とは Semantic Locator とは Semantic

    Locator とは Semantic Locator とは Semantic Locator とは アクションにCSS でもXPath でもない文字列を渡すと アクションにCSS でもXPath でもない文字列を渡すと アクションにCSS でもXPath でもない文字列を渡すと アクションにCSS でもXPath でもない文字列を渡すと アクションにCSS でもXPath でもない文字列を渡すと アクションにCSS でもXPath でもない文字列を渡すと なんか良い感じにその文字列を持つ要素を なんか良い感じにその文字列を持つ要素を なんか良い感じにその文字列を持つ要素を なんか良い感じにその文字列を持つ要素を なんか良い感じにその文字列を持つ要素を なんか良い感じにその文字列を持つ要素を 探索してくれる機能 探索してくれる機能 探索してくれる機能 探索してくれる機能 探索してくれる機能 探索してくれる機能 https://codecept.io/locators#semantic-locators https://codecept.io/locators#semantic-locators https://codecept.io/locators#semantic-locators https://codecept.io/locators#semantic-locators https://codecept.io/locators#semantic-locators https://codecept.io/locators#semantic-locators 49 / 72
  25. 例えば 例えば 例えば 例えば 例えば 例えば クリックなら クリックなら クリックなら クリックなら

    クリックなら クリックなら <a> <a> <a> <a> <a> <a> <button> <button> <button> <button> <button> <button> <input type="submit"> <input type="submit"> <input type="submit"> <input type="submit"> <input type="submit"> <input type="submit"> のうち指定されたテキストを持つものを探索します のうち指定されたテキストを持つものを探索します のうち指定されたテキストを持つものを探索します のうち指定されたテキストを持つものを探索します のうち指定されたテキストを持つものを探索します のうち指定されたテキストを持つものを探索します                   50 / 72
  26. 例えば 例えば 例えば 例えば 例えば 例えば 文字入力なら 文字入力なら 文字入力なら 文字入力なら

    文字入力なら 文字入力なら <input> <input> <input> <input> <input> <input> <textarea> <textarea> <textarea> <textarea> <textarea> <textarea> などのうち、 などのうち、 などのうち、 などのうち、 などのうち、 などのうち、 label label label label label label や や や や や や placeholder placeholder placeholder placeholder placeholder placeholder や や や や や や name name name name name name などに などに などに などに などに などに 指定されたテキストを含むものを 指定されたテキストを含むものを 指定されたテキストを含むものを 指定されたテキストを含むものを 指定されたテキストを含むものを 指定されたテキストを含むものを 自動的に探索します 自動的に探索します 自動的に探索します 自動的に探索します 自動的に探索します 自動的に探索します             51 / 72
  27. もちろんSemantic Locator で もちろんSemantic Locator で もちろんSemantic Locator で もちろんSemantic

    Locator で もちろんSemantic Locator で もちろんSemantic Locator で 対応できないケースはあります 対応できないケースはあります 対応できないケースはあります 対応できないケースはあります 対応できないケースはあります 対応できないケースはあります そういうときは割り切って そういうときは割り切って そういうときは割り切って そういうときは割り切って そういうときは割り切って そういうときは割り切って CSS セレクタとか使っていきましょう CSS セレクタとか使っていきましょう CSS セレクタとか使っていきましょう CSS セレクタとか使っていきましょう CSS セレクタとか使っていきましょう CSS セレクタとか使っていきましょう I I. .click click( ('#submit' '#submit') ) 53 / 72
  28. CSS セレクタやXPath を使わざるを得ない時も CSS セレクタやXPath を使わざるを得ない時も CSS セレクタやXPath を使わざるを得ない時も CSS

    セレクタやXPath を使わざるを得ない時も CSS セレクタやXPath を使わざるを得ない時も CSS セレクタやXPath を使わざるを得ない時も locate locate locate locate locate locate 関数を使えば可読性を保ったまま書けます 関数を使えば可読性を保ったまま書けます 関数を使えば可読性を保ったまま書けます 関数を使えば可読性を保ったまま書けます 関数を使えば可読性を保ったまま書けます 関数を使えば可読性を保ったまま書けます const const checkBox checkBox = = locate locate( ('input' 'input') ) . .withAttr withAttr( ({ {type type: : 'checkbox' 'checkbox'} }) ) . .inside inside( ('form#register' 'form#register') ) const const submit submit = = locate locate( ('button' 'button') ). .withText withText( (' 送信する' ' 送信する') ) I I. .checkOption checkOption( (checkBox checkBox) ) I I. .click click( (submit submit) ) withText() withText() withText() withText() withText() withText() を使えばSemantic Locator がなくても を使えばSemantic Locator がなくても を使えばSemantic Locator がなくても を使えばSemantic Locator がなくても を使えばSemantic Locator がなくても を使えばSemantic Locator がなくても 分かりやすく書けますね 分かりやすく書けますね 分かりやすく書けますね 分かりやすく書けますね 分かりやすく書けますね 分かりやすく書けますね 54 / 72
  29. locate locate locate locate locate locate を使う場合、 を使う場合、 を使う場合、 を使う場合、

    を使う場合、 を使う場合、as as as as as as メソッドを使うと メソッドを使うと メソッドを使うと メソッドを使うと メソッドを使うと メソッドを使うと ロケータに別名を持たせることができます ロケータに別名を持たせることができます ロケータに別名を持たせることができます ロケータに別名を持たせることができます ロケータに別名を持たせることができます ロケータに別名を持たせることができます const const submit submit = = locate locate( ('button' 'button') ) . .withText withText( (' 送信する' ' 送信する') ) . .as as( (' 送信ボタン' ' 送信ボタン') ) I I. .click click( (submit submit) ) // レポートでは `I click 送信ボタン` のように表示される // レポートでは `I click 送信ボタン` のように表示される 55 / 72
  30. 特定の要素の内側でのみ探索することもできます 特定の要素の内側でのみ探索することもできます 特定の要素の内側でのみ探索することもできます 特定の要素の内側でのみ探索することもできます 特定の要素の内側でのみ探索することもできます 特定の要素の内側でのみ探索することもできます const const dialog dialog

    = = locate locate( ('div' 'div') ) . .withText withText( (' 送信してよろしいですか?' ' 送信してよろしいですか?') ) . .as as( (' 送信確認ダイアログ' ' 送信確認ダイアログ') ) // 送信確認ダイアログの中のみを探索 // 送信確認ダイアログの中のみを探索 with with( (dialog dialog, , ( () ) => => { { I I. .click click( (' 送信' ' 送信') ) } }) ) 56 / 72
  31. locate locate locate locate locate locate の話は の話は の話は の話は

    の話は の話は 永遠に続けられるので 永遠に続けられるので 永遠に続けられるので 永遠に続けられるので 永遠に続けられるので 永遠に続けられるので いったんここまで! いったんここまで! いったんここまで! いったんここまで! いったんここまで! いったんここまで! (興味のある方は終了後 (興味のある方は終了後 (興味のある方は終了後 (興味のある方は終了後 (興味のある方は終了後 (興味のある方は終了後 またはTwitter 等でお声がけください) またはTwitter 等でお声がけください) またはTwitter 等でお声がけください) またはTwitter 等でお声がけください) またはTwitter 等でお声がけください) またはTwitter 等でお声がけください) 57 / 72
  32. ここまでの説明で ここまでの説明で ここまでの説明で ここまでの説明で ここまでの説明で ここまでの説明で 動かしながら書くのでデバッグ不要 動かしながら書くのでデバッグ不要 動かしながら書くのでデバッグ不要 動かしながら書くのでデバッグ不要

    動かしながら書くのでデバッグ不要 動かしながら書くのでデバッグ不要 CSS セレクタやXPath を考えずに記述できる CSS セレクタやXPath を考えずに記述できる CSS セレクタやXPath を考えずに記述できる CSS セレクタやXPath を考えずに記述できる CSS セレクタやXPath を考えずに記述できる CSS セレクタやXPath を考えずに記述できる ようになりました ようになりました ようになりました ようになりました ようになりました ようになりました             58 / 72
  33. 方針のおさらい 方針のおさらい 方針のおさらい 方針のおさらい 方針のおさらい 方針のおさらい 書く時は 書く時は 書く時は 書く時は

    書く時は 書く時は 一行ずつ動かしながら 一行ずつ動かしながら 一行ずつ動かしながら 一行ずつ動かしながら 一行ずつ動かしながら 一行ずつ動かしながら CSS やXPath をなるべく使わず CSS やXPath をなるべく使わず CSS やXPath をなるべく使わず CSS やXPath をなるべく使わず CSS やXPath をなるべく使わず CSS やXPath をなるべく使わず 動かす時は 動かす時は 動かす時は 動かす時は 動かす時は 動かす時は 動かない時は適宜リトライさせる ←未解決 動かない時は適宜リトライさせる ←未解決 動かない時は適宜リトライさせる ←未解決 動かない時は適宜リトライさせる ←未解決 動かない時は適宜リトライさせる ←未解決 動かない時は適宜リトライさせる ←未解決                   60 / 72
  34. 例えば 例えば 例えば 例えば 例えば 例えば Github のユーザー登録フォームで、 Github のユーザー登録フォームで、

    Github のユーザー登録フォームで、 Github のユーザー登録フォームで、 Github のユーザー登録フォームで、 Github のユーザー登録フォームで、 すでに登録済みのユーザー名を入れると すでに登録済みのユーザー名を入れると すでに登録済みのユーザー名を入れると すでに登録済みのユーザー名を入れると すでに登録済みのユーザー名を入れると すでに登録済みのユーザー名を入れると エラーが表示されます エラーが表示されます エラーが表示されます エラーが表示されます エラーが表示されます エラーが表示されます 「このエラーが表示されること」をテストします 「このエラーが表示されること」をテストします 「このエラーが表示されること」をテストします 「このエラーが表示されること」をテストします 「このエラーが表示されること」をテストします 「このエラーが表示されること」をテストします 61 / 72
  35. コンソールから書いてみます コンソールから書いてみます コンソールから書いてみます コンソールから書いてみます コンソールから書いてみます コンソールから書いてみます > I.amOnpage('https://github.com') > I.amOnpage('https://github.com')

    > I.fillField('Username', 'tsuemura') > I.fillField('Username', 'tsuemura') > I.see('Something went wrong') // エラーが表示されているこ > I.see('Something went wrong') // エラーが表示されているこ とを確認 とを確認 これは成功します これは成功します これは成功します これは成功します これは成功します これは成功します 62 / 72
  36. このコードを自動実行させてみます このコードを自動実行させてみます このコードを自動実行させてみます このコードを自動実行させてみます このコードを自動実行させてみます このコードを自動実行させてみます Feature Feature( ('Github' 'Github')

    ) Scenario Scenario( ('Username must be unique' 'Username must be unique', , async async ( (I I) ) => => { { I I. .amOnPage amOnPage( ('https://github.com' 'https://github.com') ) I I. .fillField fillField( ('Username' 'Username', , 'tsuemura' 'tsuemura') ) I I. .see see( ('Something went wrong' 'Something went wrong') ) } }) ) → → → → → → github2_test.js github2_test.js github2_test.js github2_test.js github2_test.js github2_test.js として保存 として保存 として保存 として保存 として保存 として保存 $ npx codeceptjs run github2_test.js --steps $ npx codeceptjs run github2_test.js --steps 63 / 72
  37. 失敗しました 失敗しました 失敗しました 失敗しました 失敗しました 失敗しました バリデーションメッセージが出る前に バリデーションメッセージが出る前に バリデーションメッセージが出る前に バリデーションメッセージが出る前に

    バリデーションメッセージが出る前に バリデーションメッセージが出る前に アサーションしてしまったからですね アサーションしてしまったからですね アサーションしてしまったからですね アサーションしてしまったからですね アサーションしてしまったからですね アサーションしてしまったからですね 64 / 72
  38. ここで登場するのが ここで登場するのが ここで登場するのが ここで登場するのが ここで登場するのが ここで登場するのが retryFailedStep retryFailedStep retryFailedStep retryFailedStep

    retryFailedStep retryFailedStep プラグイン プラグイン プラグイン プラグイン プラグイン プラグイン 文字通り「失敗したらリトライする」機能です 文字通り「失敗したらリトライする」機能です 文字通り「失敗したらリトライする」機能です 文字通り「失敗したらリトライする」機能です 文字通り「失敗したらリトライする」機能です 文字通り「失敗したらリトライする」機能です (デフォルトでは1 秒ごとに最大5 回リトライ) (デフォルトでは1 秒ごとに最大5 回リトライ) (デフォルトでは1 秒ごとに最大5 回リトライ) (デフォルトでは1 秒ごとに最大5 回リトライ) (デフォルトでは1 秒ごとに最大5 回リトライ) (デフォルトでは1 秒ごとに最大5 回リトライ) WebDriver の WebDriver の WebDriver の WebDriver の WebDriver の WebDriver の implicitly wait implicitly wait implicitly wait implicitly wait implicitly wait implicitly wait に似てますが に似てますが に似てますが に似てますが に似てますが に似てますが implicitly wait implicitly wait implicitly wait implicitly wait implicitly wait implicitly wait が要素の表示待ちにのみ適用されるのに対し が要素の表示待ちにのみ適用されるのに対し が要素の表示待ちにのみ適用されるのに対し が要素の表示待ちにのみ適用されるのに対し が要素の表示待ちにのみ適用されるのに対し が要素の表示待ちにのみ適用されるのに対し こちらはアサーション含め全アクションにも適用されます こちらはアサーション含め全アクションにも適用されます こちらはアサーション含め全アクションにも適用されます こちらはアサーション含め全アクションにも適用されます こちらはアサーション含め全アクションにも適用されます こちらはアサーション含め全アクションにも適用されます 65 / 72
  39. インストールは超簡単 インストールは超簡単 インストールは超簡単 インストールは超簡単 インストールは超簡単 インストールは超簡単 codecept.conf.js codecept.conf.js codecept.conf.js codecept.conf.js

    codecept.conf.js codecept.conf.js に以下を追記 に以下を追記 に以下を追記 に以下を追記 に以下を追記 に以下を追記 plugins plugins: : { { retryFailedStep retryFailedStep: : { { enabled enabled: : true true, , } }, , } }, , 66 / 72
  40. 改めて実行してみます 改めて実行してみます 改めて実行してみます 改めて実行してみます 改めて実行してみます 改めて実行してみます $ npx codeceptjs run

    github2_test.js $ npx codeceptjs run github2_test.js Github -- Github -- Can Sign Up Can Sign Up I am on page "https://github.com" I am on page "https://github.com" I fill field "Username", "tsuemura" I fill field "Username", "tsuemura" I see "Something went wrong" I see "Something went wrong" ✔ OK in 4039ms ✔ OK in 4039ms 今度は成功! 今度は成功! 今度は成功! 今度は成功! 今度は成功! 今度は成功! 67 / 72
  41. 設定ファイルにたった5 行追加するだけで 設定ファイルにたった5 行追加するだけで 設定ファイルにたった5 行追加するだけで 設定ファイルにたった5 行追加するだけで 設定ファイルにたった5 行追加するだけで

    設定ファイルにたった5 行追加するだけで テストコードが テストコードが テストコードが テストコードが テストコードが テストコードが SPA 対応になってしまいました!!!! SPA 対応になってしまいました!!!! SPA 対応になってしまいました!!!! SPA 対応になってしまいました!!!! SPA 対応になってしまいました!!!! SPA 対応になってしまいました!!!! 68 / 72
  42. 他にもいろんな機能が盛り沢山 他にもいろんな機能が盛り沢山 他にもいろんな機能が盛り沢山 他にもいろんな機能が盛り沢山 他にもいろんな機能が盛り沢山 他にもいろんな機能が盛り沢山 ビジュアルテスト(画像比較) ビジュアルテスト(画像比較) ビジュアルテスト(画像比較) ビジュアルテスト(画像比較)

    ビジュアルテスト(画像比較) ビジュアルテスト(画像比較) テスト失敗時に自動でスクリーンショット撮影 テスト失敗時に自動でスクリーンショット撮影 テスト失敗時に自動でスクリーンショット撮影 テスト失敗時に自動でスクリーンショット撮影 テスト失敗時に自動でスクリーンショット撮影 テスト失敗時に自動でスクリーンショット撮影 Allure Reporter によるキレイなレポート Allure Reporter によるキレイなレポート Allure Reporter によるキレイなレポート Allure Reporter によるキレイなレポート Allure Reporter によるキレイなレポート Allure Reporter によるキレイなレポート テストコードとレポートの翻訳 テストコードとレポートの翻訳 テストコードとレポートの翻訳 テストコードとレポートの翻訳 テストコードとレポートの翻訳 テストコードとレポートの翻訳 Appium によるネイティブアプリのテスト Appium によるネイティブアプリのテスト Appium によるネイティブアプリのテスト Appium によるネイティブアプリのテスト Appium によるネイティブアプリのテスト Appium によるネイティブアプリのテスト BDD(Gherkin) 記法のサポート BDD(Gherkin) 記法のサポート BDD(Gherkin) 記法のサポート BDD(Gherkin) 記法のサポート BDD(Gherkin) 記法のサポート BDD(Gherkin) 記法のサポート ...etc ...etc ...etc ...etc ...etc ...etc                                     70 / 72
  43. 質問等あれば遠慮なくどうぞ! 質問等あれば遠慮なくどうぞ! 質問等あれば遠慮なくどうぞ! 質問等あれば遠慮なくどうぞ! 質問等あれば遠慮なくどうぞ! 質問等あれば遠慮なくどうぞ! Twitter: @tsueeemura Twitter: @tsueeemura

    Twitter: @tsueeemura Twitter: @tsueeemura Twitter: @tsueeemura Twitter: @tsueeemura Teratail: @tsuemura Teratail: @tsuemura Teratail: @tsuemura Teratail: @tsuemura Teratail: @tsuemura Teratail: @tsuemura 71 / 72