はじめに
System Specでラジオボタンの状態を確認するときに詰まったので、対処法をまとめました。
ラジオボタンをマークアップする際デフォルトのラジオボタンではきれいなスタイルをあてにくいため、非表示にして:after
などで上からデザインを被せる手法がとられます。今回はその非表示にするところにどう対応するかがミソです。
検証環境
Ruby 2.5.1
Rails 5.2.2
RSpec 3.7
デフォルトラジオボタンの場合
上のようにデフォルトに近いラジオボタンの状態遷移はこのように書けます。
radio_spec.rb
RSpec.describe "test radio button", type: :system do
it "default radio button", focus: true do
visit new_project_path
expect(page).to have_checked_field 'アップル' # デフォルトでアップルがチェックされていることを検証
choose 'オレンジ' # オレンジをクリック
expect(page).to have_checked_field 'オレンジ' # オレンジがチェックされていることを検証
end
end
radio.html.erb
<h1>デフォルトのラジオボタン</h1>
<label for="apple"><input type="radio" name="fruits" value="apple" id="apple" checked>アップル</label>
<label for="pineapple"><input type="radio" name="fruits" value="pineapple" id="pineapple">パイナップル</label>
<label for="orange"><input type="radio" name="fruits" value="orange" id="orange">オレンジ</label>
カスタマイズしたラジオボタンの場合
先ほどと同じテストを走らせると、下のようにテストが失敗します。
➜ sample_app git:(master) ✗ bundle exec rspec spec/system/radio_spec.rb
Run options: include {:focus=>true}
Capybara starting Puma...
* Version 3.12.1 , codename: Llamas in Pajamas
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:61527
F.
Failures:
1) test radio button
Failure/Error: expect(page).to have_checked_field 'アップル'
expected to find visible field "アップル" that is not disabled but there were no matches. Also found "", which matched the selector but not all filters.
[Screenshot]: tmp/screenshots/failures_r_spec_example_groups_test_radio_button_default_radio_button_251.png
# ./spec/system/radio_spec.rb:27:in `block (2 levels) in <top (required)>'
Finished in 3.89 seconds (files took 2.94 seconds to load)
1 examples, 1 failure
Failed examples:
rspec ./spec/system/radio_spec.rb:25 # test radio button
html/cssは下記の通りで、デフォルトのラジオボタンをdisplay: none
で非表示にした上に別のスタイルをあてています。
radio.html.erb
<h1>カスタマイズしたラジオボタン</h1>
<input type="radio" name="order[fruits]" value="apple" id="apple" checked />
<label for="apple" class="sample_label">アップル</label>
<input type="radio" name="order[fruits]" value="pineapple" id="pineapple" />
<label for="pineapple" class="sample_label">パイナップル</label>
<input type="radio" name="order[fruits]" value="orange" id="orange" />
<label for="orange" class="sample_label">オレンジ</label>
<style>
input[type=radio] {
display: none; /* ここで元のラジオボタンが非表示になっている */
}
.sample_label {
position: relative;
padding: 0 0 0 42px;
}
.sample_label:after, .sample_label:before {
position: absolute;
content: "";
display: block;
top: 50%;
}
.sample_label:after {
left: 15px;
margin-top: -10px;
width: 16px;
height: 16px;
border: 2px solid #ccc;
border-radius: 50%;
}
.sample_label:before {
left: 20px;
margin-top: -5px;
width: 10px;
height: 10px;
background: #0171bd;
border-radius: 50%;
opacity: 0;
}
input[type=radio]:checked + .sample_label:before {
opacity: 1;
}
.sample_label:hover:after {
border-color: #0171bd;
}
</style>
ここでhave_checked_field
のオプション指定をします。
-
visible: false
:非表示の要素に対応 -
with: 'orange'
:見た目の指定からvalue値の指定に変更
radio_spec.rb
RSpec.describe "test radio button", type: :system do
it "customized radio button", focus: true do
visit new_project_path
expect(page).to have_checked_field with: 'apple', visible: false # デフォルトでアップルがチェックされていることを検証
find('label[for=orange]').click # オレンジをクリック(こちらも先程のテストから変更してます)
expect(page).to have_checked_field with: 'orange', visible: false # オレンジがチェックされていることを検証
end
end
テストが通るようになりました。
radio_spec.rb
➜ gatherer git:(master) ✗ bundle exec rspec spec/system/radio_spec.rb
Run options: include {:focus=>true}
Capybara starting Puma...
* Version 3.12.1 , codename: Llamas in Pajamas
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:62839
.
Finished in 4.07 seconds (files took 6.34 seconds to load)
1 example, 0 failures
まとめ
- 人間に見えていものとSpecに見えているものが同じとは限らないため、要素の状態に応じてオプションを使いわけましょう。
- 試す中で見つけたのですが、クリックする方の手法もいろいろあるのでこちらもうまく使いましょう。
参考
- CSSでラジオボタンをカスタマイズする方法 | サービス | プロエンジニア:html/cssのコードをお借りしました。
- 使えるRSpec入門・その4「どんなブラウザ操作も自由自在!逆引きCapybara大辞典 / ラジオボタンで特定の項目が選択されていることを検証する」 - Qiita:いつもありがとうございます。
- Rspec Capybaraで実際テストを書いて困ったシチュエーションの解消法 - Qiita:こちらもお世話になりました。