Capybara 2 にアップグレード

Capybaraのアップグレードは想像したよりは楽だった

* gemのアップグレード
* featuresフォルダ
* :type => :request → :type => :feature
* Ambiguous match の修正
  * within の追加
  * find -> first
  * within自体のエラーの修正
  * 正規表現で対応
* 他
  * inputのエラー (hiddenで失敗している場合がある)
  * wait_until
  * optionがマッチしない
  * テキストで無理矢理マッチ (click_onとか)
  * 随時追加

## gemのアップグレード

必要に応じて`Gemfile`の`gem 'capybara'`のバージョンを変更

```sh:
$ bundle update capybara
```

## featuresフォルダ (複数形)

`acceptance, integration` など必要に応じて`features`にリネーム

※フォルダは複数形（これを単数形にして少しはまった）

## :type => :feature (単数形) に変更
 
```ruby:
config.include Capybara::SomeModule, :type => :request
# ↓
config.include Capybara::SomeModule, :type => :feature
```

フォルダ名と違ってこちらは[単数](https://github.com/jnicklas/capybara/pull/809)

`config.before/after`などでも使ってたりする

基本`:request`のシンボルで検索すれば良いはず

## Ambiguous match の修正

### within の追加

ボタンとかリンクでAmbiguous match errorが起きやすい

`click_on '編集'`などは

```ruby:
within('#hoge') do
  click_on '編集'
end
```

idなどが無くて `within` が利用できない場合は、最初の要素で良ければ `first('.edit_link').click` などを検討する

### find -> first

`find('.hoge').click` などをversion1で使っていたならそれは `first` なので`first('.hoge').click` にする

### within自体のエラー修正

within自体が複数マッチでエラーになることも多い。その場合は

* withinを分解してパスを追加

```ruby:
within('.hoge') do
  first('.button').click
end
# ↓
first('.hoge .button').click
```

* firstなどをチェーンする

```ruby:
first('.hoge').first('.button').click
```

### 正規表現で対応

```ruby:
page.should have_content("2")
page.should have_content("Password")
# ↓
page.should have_content(/^2$/)
page.should have_content(/^Password$/)
```

※ 場合によっては `first('.hoge').text.should match('aaa')` とかも使えるかも

## 他

### inputのエラー (hiddenで失敗している場合がある)

`first('.hoge input').set('Hello')` などうまくいっていたものが失敗することがある
input type=hiddenにマッチしていることが原因だったりする

またこれは使用しているjavascript_driverによって挙動が異なる可能性もある

デバッグ

```ruby:
debugger> all('.hoge input').map{|e| e[:type] }
# => ["hidden", "number", "text", "submit"]
```

※ input type="number, email"などもあるが、非対応ブラウザでは"text"になることもある

`first('.hoge input', :visible => true).set('Hello')` でうまく行く場合もある

### wait_until

`wait_until` はなくなったので `have_selector(selector, visible: true)` とか試してみる

### optionがマッチしない

checkbox, radio, selectなどのラベルマッチは完全一致になった模様

### テキストで無理矢理マッチ (click_onとか)

`all()` からselect, detectとか

```ruby
first('.some_form').all('input').detect{|e| e[:type] == "number" }.set(3)
first('.some_form').all('input').detect{|e| ["text", "number"].include?(e[:type]) }.set(3)
all("#hoge a.btn").detect{|b| b.text == 'キャンセル' }.click
```

※ `all()` の一致element数が数百とかあるとパフォーマンスの影響がでるかも
※ `click_on`が失敗している時などの最終手段かと

## メモ

[Capybara 2.0 Upgrade Guide](http://techblog.fundinggates.com/blog/2012/08/capybara-2-0-upgrade-guide/)を見てみる

* Ruby 1.8.7 互換はなくす予定
* Password/Password Confirmation みたいのは基本id使え
  * なければclassでも追加してくれ
* `find(:my_id)` 使ってたら `find('#my_id')` に変える
* `has_content?` はsubstringsのチェックになった
* `select/unselect` は完全一致
* `Capybara.timeout` と `wait_until` は削除された

#### New feature

* `find(:field, '...')`
* [add_selectorをチェック](https://github.com/jnicklas/capybara/blob/master/lib/capybara/selector.rb)
* `has_content?`で正規表現使える

#### 他気付いた点

* capybara-webkitは一応自分でやったのは動いた
* webkitはseleniumの2倍くらい速い
* マニアックな操作はseleniumで解決できる場合がある
  * ドラッグアンドドロップ
  * 複数ウインドウ (using_sessionではなくリンクからのポップアップ)