Capybara+RSpec Tips (2014年3月時点)

Capybara+RSpecでエンドツーエンドなテストを書くときのTipsです

`require "capybara/rspec"`の罠
------------------------------

`require "capybara/rspec"`は`after(:each)`にCapybara.reset_sessions!`を入れてしまいます。

これによりit毎に`Capybara.current_session`が変化してしまうため、以下のようなワンライナーshouldによるテストを難しくしています。

```ruby
require File.dirname(__FILE__) + "/spec_helper"

feature "フォーム入力" do
  before :all do
    visit "/form.html"
    fill_in "u_name", with:"テスト太郎"
    click_button "送信"
  end

  context page do
    its(:current_path) { should eq "/thanks.html" }
    it { should have_selector "#u_name", text:"テスト太郎" }
  end
end
```

### 回避方法(Capybara::DSLを使いたい場合) ###

`require "capybara/rspec"`を使わず、自分で組み込みましょう

spec/spec_helper.rb:

```ruby
require 'capybara/rspec/matchers'
require 'capybara/rspec/features'
RSpec.configure do |config|
  config.include Capybara::DSL, :type => :feature
  config.include Capybara::RSpecMatchers, :type => :feature
end
```

### 回避方法(Capybara::DSLを使わない場合) ###

テストを以下のようにします

```ruby
require File.dirname(__FILE__) + "/spec_helper"

describe "フォーム入力" do
  before :all do
    Capybara.visit "/form.html"
    Capybara.fill_in "u_name", with:"テスト太郎"
    Capybara.click_button "送信"
  end

  context Capybara.page do
    its(:current_path) { should eq "/thanks.html" }
    it { should have_selector "#u_name", text:"テスト太郎" }
  end
end
```

違いは以下の通り

1. `describe :type => :feature`が不要 (無くともテストが実行される)
2. `feature`句、`scenario`句等が使えない
3. 毎度`Capybara`をつける必要がある

### 注意 ###

Capybara.reset_sessions!をafter(:all)あたりでやっておきましょう。さもないと、遷移状態がクリアされないのでテストが不安定になりますよ。


SSLサーバ証明書の検証を抑制する
-------------------------------

無効なSSLサーバ証明書で動いているサーバへのテストを行う方法です

### capybara-mechanizeの場合 ###

opensslによる検証を抑制します

spec/spec_helper.rb:

```ruby
require "openssl"
OpenSSL::SSL.module_eval { remove_const(:VERIFY_PEER) }
OpenSSL::SSL.const_set(:VERIFY_PEER, OpenSSL::SSL::VERIFY_NONE)
I_KNOW_THAT_OPENSSL_VERIFY_PEER_EQUALS_VERIFY_NONE_IS_WRONG = nil
```

参考資料

* http://mofuken.blogspot.jp/2012/12/ruby-open-uri-https-certificate-verify.html

これをやらなかった場合のエラーメッセージ

```
RuntimeError:
 Received the following error for a GET request to https://127.0.0.1: 'hostname "127.0.0.1" does not match the server certificate'
```

### capybara-webkitの場合 ###

SSL関連のエラーを抑制したCapybaraドライバを定義し、それを利用するようにします

spec/spec_helper.rb:

```ruby
Capybara.register_driver :webkit_ignore_ssl do |app|
  driver = Capybara::Webkit::Driver.new(app)
  driver.browser.ignore_ssl_errors
  driver
end

Capybara.configure do |config|
  config.default_driver = :webkit_ignore_ssl
end
```

参考資料

* http://cowjumpedoverthecommodore64.blogspot.jp/2013/09/if-your-website-runs-under-ssl-than.html

これをやらなかった場合のエラーメッセージ

```
Capybara::Webkit::InvalidResponseError:
 Unable to load URL: https://127.0.0.1 because of error loading https://127.0.0.1: Unknown error
```

Cookieを持たせる方法
--------------------

### capybara-mechanizeの場合 ###

```ruby
require "uri"
page.driver.browser.agent.cookie_jar.add URI.parse(Capybara.app_host), Mechanize::Cookie.new("cookie_key", "cookie_value", {domain:".example.com", expire:Time.now+86400, path:"/"})
```

### capybara-webkitの場合 ###

```ruby
require "cgi"
page.driver.browser.set_cookie("cookie_key=#{CGI.escape('cookie_value')}; expires=#{(Time.now+86400).strftime("%a, %d %b %Y %H:%M:%S GMT")}; domain=.example.com; path=/;")
```