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

Capybaraで変更に強いE2Eテストを書く / TokyuRubyKaigi12

Capybaraで変更に強いE2Eテストを書く / TokyuRubyKaigi12

TokyuRuby会議12(2018/07/29)

B8e501d93b98a553abf0b5cee0c33503?s=128

yasaichi

July 29, 2018
Tweet

Transcript

  1. Capybaraで変更に
 強いE2Eテストを書く Yuichi Goto (@_yasaichi) July 29, 2018 @ TokyuRuby会議12

  2. self.inspect @_yasaichi yasaichi http://web-salad.hateblo.jp ピクスタ株式会社  技術推進チームリーダー !2 一般的には「技術基盤」と 言われるようなチーム

  3. https://pixta.co.jp/business !3 ピクスタは「クリエイティブプラットフォーム」を創る会社です 3つのサービス全てでRubyを利用。
 感謝のRubyKaigi協賛(過去5回)

  4. Agenda 変更に弱いE2Eテストとは   変更に強いE2Eテストを書く方法   残った小さな問題とその解決   まとめ !4

  5. 変更に弱いE2Eテストとは • Webアプリケーションでは、次のようなUI上の変更に 強く影響を受けるE2Eテストと定義できそう • HTMLタグの構造を変更する • コンポーネントのスタイリングを変更する • 画面内の文言を変更する

    !5
  6. 対応するCapybaraのコード例 • タグ名で指定: all("table > tr")[1] • 既存のクラス名で指定: find(".for-styling") •

    画面内の文言で指定: click_button("จݴ") !6 _人人人人人人人_ > 見たことある  <  ̄Y^Y^Y^Y^Y^Y^Y ̄
  7. 放置するとどうなるか 1. UI周りを数行変更したらなぜかCIが落ちた 2. エラーを見るとE2Eテストで落ちていることが判明 3. 該当のテストを手元のマシンでデバッグする # !7 じわじわと開発のボトルネックになってつらい

  8. Agenda   変更に弱いE2Eテストとは 変更に強いE2Eテストを書く方法   残った小さな問題とその解決   まとめ !8

  9. https://blog.kentcdodds.com/making-your-ui-tests-resilient-to-change-d37a6ee37269 !9 Kent C. Dodds氏(TC39の一員)の提案手法がおすすめ

  10. 要旨: テスト用のdata属性を使おう • スタイリングに使っているクラス名をテストで再利用 すると、UIの変更によってテストが壊れうる • テスト用のクラス名を用意すると既にスタイリングで 使っているそれと混ざってしまい、管理が大変 !10 data-testid

    のような見るからにテスト専用の
 カスタムdata属性をセレクタとして使えば解決!
  11. お題: ログインフォーム <h2>Sign in</h2> <%= form_with model: resource, url: session_path(resource_name)

    do |f| %> <%= field_set_tag nil, class: "form-group" do %> <%= f.email_field :email, placeholder: "Email", class: "form-control form-control-lg", "data-testid": "email" %> <% end %> <%= field_set_tag nil, class: "form-group" do %> <%= f.password_field :password, placeholder: "Password", class: "form-control form-control-lg", "data-testid": "password" %> <% end %> <%= f.submit "Sign in", class: "btn btn-lg btn-primary", "data-testid": "submit" %> <% end %> <%= render "users/shared/links" %> !11 テストで使う要素にdata属性を振っておく
  12. data属性を使って書くE2Eテストの例 require "rails_helper" RSpec.describe "User sign in", type: :system do

    let(:user) { FactoryBot.create(:user) } before do visit new_user_session_path end it "should allow users to sign in with their email and password" do find("[data-testid='email']").set(user.email) find("[data-testid='password']").set(user.password) find("[data-testid='submit']").click expect(page).to have_current_path(root_path) end end !12 タグ名、クラス名、画面内の文言に 依存していないのがポイント
  13. カスタムセレクタを使うと便利 • 毎回 find("[data-testid='email']") のように
 書かないといけないのは面倒くさい • Capybaraではカスタムセレクタを定義できるので
 これを使うとよい !13

    Capybara.add_selector(:test_id) do css { |val| %Q([data-testid="#{val}"]) } end find(:test_id, "email") # == find("[data-testid='email']")
  14. Agenda   変更に弱いE2Eテストとは ɹ 変更に強いE2Eテストを書く方法 残った小さな問題とその解決   まとめ !14

  15. そのdata属性、本番環境では不要では? • 本番環境に残っていても大きな問題ではない • 気になる人向けの解決策(Reactの場合) • babel-plugin-react-remove-properties • BabelでのJSXのトランスパイルに介入して、コン ポーネントに渡した任意のプロパティを取り除く

    !15
  16. Ruby on Rails向けにも作れないか? • Haml/Slim向けにならほぼ同じ方法で作れるが・・・ • テンプレートエンジンごとにgem作ることになる • 素のHTML +

    ERBで書いている人は使えない !16 Railsのヘルパー呼び出しに介入する方法なら
 制約はあるものの汎用的なものが作れるのでは?
  17. イケそうだったのでつい作ってしまった yasaichi / remove_data_attributes • RailsのViewヘルパーで生成されるHTMLタグから 任意のカスタムdata属性を取り除くgem • 設定ファイル(YAML)で取り除きたい属性名を指定 !17

    # Configure which data attributes should be removed. data_attributes: - data-testid
  18. data-testid を取り除く例 <form action="/users/sign_in" accept-charset="UTF-8" data-remote="true" method="post"> # (snip) <input

    type="submit" name="commit" value="Sign in" class="btn btn-lg btn-primary" data-disable-with="Sign in" /> </form> !18 <%= form_with model: resource, url: session_path(resource_name) do |f| %> # (snip) <%= f.submit "Sign in", class: "btn btn-lg btn-primary", "data-testid": "submit" %> <% end %> オプションとして渡したものが 取り除かれる
  19. 仕組み • Railsの link_to などのViewヘルパーは内部的ʹ tag_options というメソッドを呼び出している • このメソッドに渡されたオプションを書き換える !19

    # remove_data_attributes/lib/remove_data_attributes/ tag_options_filter.rb define_method(method_name) do |options, escape = true| options.is_a?(::Hash) ? super(processor.call(options), escape) : super(options, escape) end
  20. Agenda   変更に弱いE2Eテストとは ɹ 変更に強いE2Eテストを書く方法 ɹ 残った小さな問題とその解決 まとめ !20

  21. まとめ • UI上の変更に強いE2Eテストを書くために、各要素を 指定するためのよりよい方法を紹介した • data-testid のようなテスト用の属性を使う • Capybaraではカスタムセレクタを使うと便利 •

    本番環境では不要なこれらの属性を削除するために
 remove_data_attributesというgemを作った !21
  22. ご清聴ありがとうございました !22