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

60分で学ぶE2Eテスト(実装編)

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

 60分で学ぶE2Eテスト(実装編)

Avatar for tsuemura

tsuemura

March 10, 2022
Tweet

More Decks by tsuemura

Other Decks in Programming

Transcript

  1. テストケース 1. 非会員で予約 2. 会員登録→ 予約→ ログアウト 3. プレミアム会員でログイン→ 予約→

    ログアウト 4. 一般会員でログイン→ 予約→ ログアウト 5. 一般会員の画面にプレミアム会員限定プランが表示されないこと 6. 非会員の画面に一般・プレミアム会員限定プランが表示されないこと
  2. 非会員で予約するシナリオの手順 (1/2) 1. https://hotel.testplanisphere.dev/ja/ を開く 2. メニューから「宿泊予約」を選択 3. 宿泊プラン一覧から「お得な特典付きプラン」の「このプランで予約」を選 択

    4. 宿泊日を翌月1 日に設定 5. 宿泊数を7 泊に設定 6. 人数を2 に設定 7. 朝食バイキング、昼からチェックインプラン、お得な観光プランを選択 8. 氏名に「テスト太郎」を入力
  3. 非会員で予約するシナリオの手順 (2/2) 9. 確認のご連絡をメールに設定 10. メールアドレスに[email protected] を設定 11. ご要望・ご連絡事項に「テスト」と入力 12.

    予約内容を確認するボタンを選択 13. 宿泊予約確認画面で、以下を確認 i. 合計金額が121,000 円であること ii. 期間、人数、追加プラン、お名前、確認のご連絡、ご要望・ご連絡が 入力通りになっていること 14. この内容で予約するボタンを選択し、以下を確認 i. 予約が完了しましたダイアログが表示されること
  4. テストコードを書いてみよう cypress/integration/smoke_test.js を作成 describe(' スモークテスト', () => { it(' 非会員で予約',

    () => { // ここにテストコードを書く }) }) describe 〜 it は「何をテストするのか」を書く部分
  5. 設計したテスト手順をそのままコメントとして書いちゃえ describe(' スモークテスト', () => { it(' 非会員で予約', () =>

    { // 1. https://hotel.testplanisphere.dev/ja/ を開く // 2. メニューから「宿泊予約」を選択 // 3. 宿泊プラン一覧から「お得な特典付きプラン」の「このプランで予約」を選択 // 4. 宿泊日を翌月1 日に設定 // 5. 宿泊数を7 泊に設定 // 6. 人数を2 に設定 // 7. 朝食バイキング、昼からチェックインプラン、お得な観光プランを選択 // 8. 氏名に「テスト太郎」を入力 // 9. 確認のご連絡をメールに設定 // 10. メールアドレスに[email protected] を設定 // 11. ご要望・ご連絡事項に「テスト」と入力 // 12. 予約内容を確認するボタンを選択 // 13. 宿泊予約確認画面で、以下を確認 // 1. 合計金額が123,000 円であること // 2. 期間、人数、追加プラン、お名前、確認のご連絡、ご要望・ご連絡が入力通りになっていること // 14. この内容で予約するボタンを選択し、以下を確認 // 1. 予約が完了しましたダイアログが表示されること }) })
  6. テストコードを書いてみよう テスト対象のサイトにアクセス describe(' スモークテスト', () => { it(' 非会員で予約', ()

    => { // 1. https://hotel.testplanisphere.dev/ja/ を開く cy.visit("https://hotel.testplanisphere.dev/ja/index.html"); }) }) コマンドは(一部の例外を除き) cy から始まる cy.visit() は指定したURL に移動するコマンド
  7. テストコードを書いてみよう describe(' スモークテスト', () => { it(' 非会員で予約', () =>

    { // テスト対象のサイトにアクセス cy.visit("https://hotel.testplanisphere.dev/ja/index.html"); // 2. メニューから「宿泊予約」を選択 ← イマココ cy.▪▪▪▪▪▪.click() }) }) クリックは click() でOK 宿泊予約、というリンクを どうやって指定する?
  8. 現在のテストコード describe(' スモークテスト', () => { it(' 非会員で予約', () =>

    { // テスト対象のサイトにアクセス cy.visit("https://hotel.testplanisphere.dev/ja/index.html"); // 2. メニューから「宿泊予約」を選択 cy.contain(' 宿泊予約').click() }) })
  9. 続けて書いていきましょう 宿泊プランの選択 describe(' スモークテスト', () => { it(' 非会員で予約', ()

    => { // テスト対象のサイトにアクセス cy.visit("https://hotel.testplanisphere.dev/ja/index.html"); // 2. メニューから「宿泊予約」を選択 cy.contain(' 宿泊予約').click() // 3. 宿泊プラン一覧から「お得な特典付きプラン」の「このプランで予約」を選択 ← イマココ }) })
  10. 現在のテストコード describe(' スモークテスト', () => { it(' 非会員で予約', () =>

    { // 1. https://hotel.testplanisphere.dev/ja/ を開く cy.visit("https://hotel.testplanisphere.dev/ja/index.html"); // 2. メニューから「宿泊予約」を選択 cy.contain(' 宿泊予約').click() // 3. 宿泊プラン一覧から「お得な特典付きプラン」の「このプランで予約」を選択 cy.contains('div.card-body', ' お得な特典付きプラン') .contains(' このプランで予約').click() }) })
  11. カスタムコマンドを追加する cypress/support/commands.js に以下を追加する Cypress.Commands.add("getCardByText", (text) => { const selector =

    'div.card-body' cy.contains(selector, text) }); こう書けるようになった // before cy.contains('div.card-body', ' お得な特典付きプラン') .contains(' このプランで予約').click() // after cy.getCardByText(' お得な特典付きプラン').contains(' このプランで予約').click()
  12. 新たなカスタムコマンドを定義しよう 予約プランを開く カスタムコマンドを定義する Cypress.Commands.add("openReservationPlan", (planName) => { const buttonText =

    " このプランで予約" cy .getCardByText(planName) .contains(buttonText) .invoke("removeAttr", "target") .click() }) テストコードはこう書ける // before cy.getCardByText(' お得な特典付きプラン').contains(' このプランで予約').click() // after cy.openReservationPlan(' お得な特典付きプラン')
  13. 続けて書いていきましょう 4. 宿泊日を翌月1 日に設定 5. 宿泊数を7 泊に設定 6. 人数を2 に設定

    7. 朝食バイキング、昼からチェックインプラン、お得な観光プランを選択 8. 氏名に「テスト太郎」を入力 9. 確認のご連絡をメールに設定 10. メールアドレスに[email protected] を設定 11. ご要望・ご連絡事項に「テスト」と入力 12. 予約内容を確認するボタンを選択
  14. HTML のフォームの仕組みについておさらい <label for="name"> お名前</label> <input id="name" type="text" /> label

    と input で出来ていることが多い label に for 属性を付けると label と input が紐付けられる label をクリックすると input にフォーカスが移る
  15. Cypress ではどう扱われるか <label for="name"> お名前</label> <input id="name" type="text" /> //

    label が返ってくる cy.contains(" お名前") contains で取得できる要素は厳密には label 要素なので フォームに対する操作の場合、 contains では上手く動かない場合がある 普通の入力フォームへの入力はOK セレクトボックスやチェックボックスはNG Clickable な要素として扱われない
  16. 宿泊予約 cy.getByLabel(' 宿泊日').type('2022-02-12') cy.getByLabel(' 宿泊数').type('7') cy.getByLabel(' 人数').type('1') cy.getByLabel(' 朝食バイキング').check() cy.getByLabel('

    氏名').type(' ジャスト 太郎') cy.getByLabel(' 確認のご連絡').select(' 希望しない') cy.contains(' 予約内容を確認する').click()
  17. これもカスタムコマンドにしてしまえ 値を一度削除してから入力する fill メソッドを定義する Cypress.Commands.add("fill", { prevSubject: 'element' }, (subject,

    text) => { subject.clear(); subject.type(text) }) テストコードはこうなる cy.getByLabel(' 宿泊日').fill('2022/02/21{esc}')
  18. 宿泊日を翌月 1 日に設定 日付処理をする dayjs というライブラリを使う $ npm install dayjs

    describe(" スモークテスト", () => { const dayjs = require("dayjs"); const checkInDate = dayjs().add(1, "month").startOf("month"); it(" 会員登録して予約してログアウト", () => { // ... // 4. 宿泊日を翌月1 日に設定 cy.getByLabel(" 宿泊日").fill(`${checkInDate.format("YYYY/MM/DD")}{esc}`);
  19. この日付が表す意味を表現する context はテストコードに「文脈」を与える describe(" スモークテスト", () => { context(" 翌月1

    日から7 日間予約する", () => { const dayjs = require("dayjs"); const checkInDate = dayjs().add(1, "month").startOf("month"); const checkOutDate = checkInDate.add(7, "day"); it(" 会員登録して予約してログアウト", () => {
  20. 現在のテストコード describe(" スモークテスト", () => { context(" 翌月1 日から7 日間予約する",

    () => { const dayjs = require("dayjs"); const checkInDate = dayjs().add(1, "month").startOf("month"); const checkOutDate = checkInDate.add(7, "day"); it(" 会員登録して予約してログアウト", () => { // 1. https://hotel.testplanisphere.dev/ja/ を開く cy.visit("https://hotel.testplanisphere.dev/ja/index.html"); // 2. メニューから「宿泊予約」を選択 cy.contains(" 宿泊予約").click(); // 3. 宿泊プラン一覧から「お得な特典付きプラン」の「このプランで予約」を選択 cy.openReservationPlan(" お得な特典付きプラン"); cy.wait(1000); // 4. 宿泊日を翌月1 日に設定 cy.getByLabel(" 宿泊日").fill(`${checkInDate.format("YYYY/MM/DD")}{esc}`); // 5. 宿泊数を7 泊に設定 cy.getByLabel(" 宿泊数").fill("7"); // 6. 人数を2 に設定 cy.getByLabel(" 人数").fill("2");
  21. // 7. 朝食バイキング、昼からチェックインプラン、お得な観光プランを選択 cy.getByLabel(" 朝食バイキング").check(); cy.getByLabel(" 昼からチェックインプラン").check(); cy.getByLabel(" お得な観光プラン").check(); //

    8. 氏名に「テスト太郎」を入力 cy.getByLabel(" 氏名").fill(" テスト 太郎"); // 9. 確認のご連絡をメールに設定 cy.getByLabel(" 確認のご連絡").select(" メールでのご連絡"); // 10. メールアドレスに[email protected] を設定 cy.getByLabel(" メールアドレス").fill("[email protected]"); // 11. ご要望・ご連絡事項に「テスト」と入力 cy.getByLabel(" ご要望・ご連絡事項等ありましたらご記入ください").fill( " テスト" ); // 12. 予約内容を確認するボタンを選択 cy.contains(" 予約内容を確認する").click(); }); }); });
  22. テストコード // 13. 宿泊予約確認画面で、以下を確認 // 1. 合計金額が123,000 円であること // 2.

    期間、人数、追加プラン、お名前、確認のご連絡、ご要望・ご連絡が入力通りになっていること cy.contains(" 合計").should("contain", "123,000 円"); cy.contains(" お得な特典付きプラン"); cy.contains(" 期間") .next() .should( "contain", `${checkInDate.format("YYYY 年M 月D 日")} 〜 ${checkOutDate.format("YYYY 年M 月D 日")} 7 泊` ); cy.contains(" 人数").next().should("contain", "2 名様"); cy.contains(" 追加プラン").next().should("contain", " 朝食バイキング"); cy.contains(" 追加プラン").next().should("contain", " 昼からチェックインプラン"); cy.contains(" お名前").next().should("contain", " テスト 太郎様"); cy.contains(" 追加プラン").next().should("contain", " お得な観光プラン"); cy.contains(" お名前").next().should("contain", " テスト 太郎様"); cy.contains(" 確認のご連絡")next().should("contain", " メール:[email protected]"); cy.contains(" ご要望・ご連絡事項等").next().should("contain", " テスト"); // 14. この内容で予約するボタンを選択し、以下を確認 // 1. 予約が完了しましたダイアログが表示されること cy.contains(" この内容で予約する").click(); cy.wait(2000); cy.contains(" 予約を完了しました");
  23. おさらい : わかりやすいテストコードを書くコツ 1. ユーザー目線の表記を心がける サイトの内部構造を使わず、表示されたテキストで選択する 2. あいまいな部分を減らす 「xx の中のyy

    」というように指定して、要素探索の範囲を絞り込む 3. 「何をテストしているのか」と「どうテストするのか」を分ける テストコードから不要な情報を出来るだけ省いて シンプルなコードを保つ