[RSpec] System Specでおしゃれラジオボタンをチェックできないときの対処法

# はじめに
System Specでラジオボタンの状態を確認するときに詰まったので、対処法をまとめました。

ラジオボタンをマークアップする際デフォルトのラジオボタンではきれいなスタイルをあてにくいため、非表示にして`:after`などで上からデザインを被せる手法がとられます。今回はその**非表示**にするところにどう対応するかがミソです。

# 検証環境
Ruby 2.5.1
Rails 5.2.2
RSpec 3.7


# デフォルトラジオボタンの場合

まずはシンプルな例で見ていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168594/e3661b28-6207-2fd6-dce0-149f34b38186.png)

上のようにデフォルトに近いラジオボタンの状態遷移はこのように書けます。

```ruby: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
```

```html: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>
```
# カスタマイズしたラジオボタンの場合
次はカスタマイズしたラジオボタンで見てみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168594/dc4eb41f-e270-5d31-19d3-d030890114ef.png)

先ほどと同じテストを走らせると、下のようにテストが失敗します。

```shell
➜  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`で非表示にした上に別のスタイルをあてています。

```html: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値の指定に変更

```ruby: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
```

テストが通るようになりました。

```ruby: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でラジオボタンをカスタマイズする方法 | サービス | プロエンジニア](https://proengineer.internous.co.jp/content/columnfeature/6492)：html/cssのコードをお借りしました。 
- [使えるRSpec入門・その4「どんなブラウザ操作も自由自在！逆引きCapybara大辞典 / ラジオボタンで特定の項目が選択されていることを検証する」 - Qiita](https://qiita.com/jnchito/items/607f956263c38a5fec24#%E3%83%A9%E3%82%B8%E3%82%AA%E3%83%9C%E3%82%BF%E3%83%B3%E3%81%A7%E7%89%B9%E5%AE%9A%E3%81%AE%E9%A0%85%E7%9B%AE%E3%81%8C%E9%81%B8%E6%8A%9E%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E3%81%93%E3%81%A8%E3%82%92%E6%A4%9C%E8%A8%BC%E3%81%99%E3%82%8B)：いつもありがとうございます。
- [Rspec Capybaraで実際テストを書いて困ったシチュエーションの解消法 - Qiita](https://qiita.com/kon_yu/items/52a0f5f0016564486061)：こちらもお世話になりました。