[*Rails*] RSpec + devise + Twitter認証  テストメモ

# はじめに
DeviseのTwitter認証のテストをする際のメモ。

# ViewとModelの編集
Twitter認証時はパスワードを要求しないようにUserモデルとViewを修正。

Userモデルに**password_required?**メソッドの追加。
Userのproviderがカラの場合のみPassword入力を要求する。

```rb:app/models/user.rb
class User < ActiveRecord::Base
    (省略)...
	def password_required?
		super && provider.blank?
	end
end
```

Viewはパスワード部分をif文で囲む。

```erb:app/views/devise/registrations/new.html.erb
<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
    (省略)...
	<% if f.object.password_required? %>
		<div class="field">
			<%= f.label :password %>
			<% if @validatable %>
				<em>(<%= @minimum_password_length %> characters minimum)</em>
			<% end %><br />
			<%= f.password_field :password, autocomplete: "off" %>
		</div>

		<div class="field">
			<%= f.label :password_confirmation %><br />
			<%= f.password_field :password_confirmation, autocomplete: "off" %>
		</div>
	<% end %>
    (省略)...
<% end %>

<%= render "devise/shared/links" %>
```

# テストの作成
現状のGemfile。

```rb:Gemfile
source 'https://rubygems.org'


# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.0'

group :development, :test do
	# Use sqlite3 as the database for Active Record
	gem 'sqlite3'
	gem 'rspec-rails'
end

group :test do
	gem 'selenium-webdriver'
	gem 'capybara'
	gem 'factory_girl_rails'
end

# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.1.0'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer', platforms: :ruby

# Use jquery as the JavaScript library
gem 'jquery-rails'
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'
# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0', group: :doc

# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Unicorn as the app server
# gem 'unicorn'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug'

  # Access an IRB console on exception pages or by using <%= console %> in views
  gem 'web-console', '~> 2.0'

  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
end

# Devise
gem 'devise', '3.4.1'
gem 'omniauth-twitter'

```

RSpecの初期設定。

```bash
$ rails g rspec:install
```

Twitter認証用のテスト作成。

```bash
$ rails g integration_test twitter_omniauth
```

以下ファイルにデフォルトURLを記載。

```rb:config/environments/test.rb
Rails.application.configure do
  (省略)...
	# Devise host mail setting
	config.action_mailer.default_url_options = { host: 'localhost:3000' }
end
```

上部2行とCapybara::DSLの行を追加。

```rb:spec/spec_helper.rb
ENV['RAILS_ENV'] = 'test'
require File.expand_path('../../config/environment', __FILE__)
(省略)...
RSpec.configure do |config|
    (省略)...
	# Add Capybara DSL to rspec helper
	config.include Capybara::DSL
end
```

以下ファイルを作成。
deviseでconfirmable機能を使っている場合は`confirmed_at`に値を入れておかないと承認されていないアカウントとしてログインできない。

```rb:spec/factories.rb
FactoryGirl.define do
	factory :user do
		email "rspec_test@test.com"
		uid "123"
		provider "twitter"
		username "anonymous"
		confirmed_at Time.now
	end
end
```

テストの内容。
OAuth用のモックを使ってテスト。
`/pages/show`はログインしているユーザーのみアクセスできるページ。

```rb:spec/requests/twitter_omniauths_spec.rb
require 'rails_helper'

describe "twitter login test" do
	before do
		OmniAuth.config.test_mode = true
		FactoryGirl.create(:user)
		OmniAuth.config.mock_auth[:twitter] = {
			"uid" => "123",
			"provider" => "twitter",
			"info" => { 
				"nickname" => "anonymous"
			}
		}
		visit user_omniauth_authorize_path(:twitter)
	end

	after do
		OmniAuth.config.test_mode = false
	end

	describe "after login" do
		before{ visit "/pages/show" }
		subject{ page }

		it{ should have_link('ログアウト') }
	end
end
```

テストは成功！

```bash
$ bundle exec rspec spec/requests/twitter_omniauths_spec.rb 
.

Finished in 0.86037 seconds (files took 21.05 seconds to load)
1 example, 0 failures
```