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

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

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

TokyuRuby会議12(2018/07/29)

Yuichi Goto

July 29, 2018
Tweet

More Decks by Yuichi Goto

Other Decks in Programming

Transcript

  1. Capybaraで変更に

    強いE2Eテストを書く
    Yuichi Goto (@_yasaichi)
    July 29, 2018 @ TokyuRuby会議12

    View full-size slide

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

    View full-size slide

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

    感謝のRubyKaigi協賛(過去5回)

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  6. 対応するCapybaraのコード例
    • タグ名で指定: all("table > tr")[1]
    • 既存のクラス名で指定: find(".for-styling")
    • 画面内の文言で指定: click_button("จݴ")
    !6
    _人人人人人人人_
    > 見たことある  <
     ̄Y^Y^Y^Y^Y^Y^Y ̄

    View full-size slide

  7. 放置するとどうなるか
    1. UI周りを数行変更したらなぜかCIが落ちた
    2. エラーを見るとE2Eテストで落ちていることが判明
    3. 該当のテストを手元のマシンでデバッグする #
    !7
    じわじわと開発のボトルネックになってつらい

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    カスタムdata属性をセレクタとして使えば解決!

    View full-size slide

  11. お題: ログインフォーム
    Sign in
    <%= 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属性を振っておく

    View full-size slide

  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
    タグ名、クラス名、画面内の文言に
    依存していないのがポイント

    View full-size slide

  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']")

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  16. Ruby on Rails向けにも作れないか?
    • Haml/Slim向けにならほぼ同じ方法で作れるが・・・
    • テンプレートエンジンごとにgem作ることになる
    • 素のHTML + ERBで書いている人は使えない
    !16
    Railsのヘルパー呼び出しに介入する方法なら

    制約はあるものの汎用的なものが作れるのでは?

    View full-size slide

  17. イケそうだったのでつい作ってしまった
    yasaichi / remove_data_attributes
    • RailsのViewヘルパーで生成されるHTMLタグから
    任意のカスタムdata属性を取り除くgem
    • 設定ファイル(YAML)で取り除きたい属性名を指定
    !17
    # Configure which data attributes should be removed.
    data_attributes:
    - data-testid

    View full-size slide

  18. data-testid を取り除く例
    method="post">
    # (snip)


    !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 %>
    オプションとして渡したものが
    取り除かれる

    View full-size slide

  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

    View full-size slide

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

    View full-size slide

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

    remove_data_attributesというgemを作った
    !21

    View full-size slide

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

    View full-size slide