Ruby
Rails
RSpec
FactoryGirl
テスト

Railsチュートリアル テストをRSpecで実施 【フィーチャスペック編 users_login_spec 3/7】

テスト対象

該当するコントローラ 該当するアクション
SessionsController new, create, destroy

環境

Userモデル 単体テスト編 1/3 に記載

フォルダ、使用ファイル

種類 ファイル名
スペック spec/features/users_login_spec.rb
サポートモジュール spec/support/support_module.rb
shared_examples spec/support/shared_examples.rb
shared_context spec/support/shared_context.rb
ファクトリ(ユーザ) spec/support/factories/users.rb

アウトライン作成 1/2

users_login_spec.rb
# spec/features/users_login_spec.rb
RSpec.feature "UsersLogin", type: :feature do

  # ログインページ
  describe "log in"
    # loginフォームが正しいこと
    it_behaves_like "log in form have right css"
    # 情報が valid
    context "valid info"
      # 成功
      scenario "success log in"
    # 情報が invalid
    context "invalid info"
      # 失敗
      scenario "fail log in"

end

スペック作成 1/2

users_login_spec.rb
# spec/features/users_login_spec.rb
require 'rails_helper'

RSpec.feature "UsersLogin", type: :feature do

  include SupportModule
  include_context "setup"

  subject { page }

  describe "log in" do
    before { visit "/login" }
    # loginフォームが正しいこと
    it_behaves_like "login-form have right css"
    # ログイン情報が 有効
    context "valid info" do
      scenario "success log in" do
        visit "/login"
        fill_in_login_form(user) # =>  support_module
        click_button "Log in"
        should have_title(user.name)
        should have_css('h1', text: user.name)
        should have_current_path(user_path(user))
      end
    end
    # ログイン情報が 無効
    context "invalid info" do
      scenario "fail log in" do
        visit login_path
        fill_in_login_form(user, invalid: true) # =>  support_module
        click_button "Log in"
        error_messages "Invalid email/password combination"
        should have_title("Log in")
        should have_css("h1", text: "Log in")
        should have_current_path("/login")
      end
    end
  end
end

shared_examples の作成

  • it_behaves_like "login-form have right css" の部分
shared_examples.rb
  # spec/support/shared_examples.rb
    # login form
    # sessions#new
    shared_examples_for "login-form have right css" do
      it { expect(page).to have_css('label', text: 'Email') }
      it { expect(page).to have_css('label', text: 'Password') }
      it { expect(page).to have_css('input#session_email') }
      it { expect(page).to have_css('input#session_password') }
      it { expect(page).to  have_css('input#session_remember_me[type="checkbox"]') }
      it { expect(page).to have_css('label.checkbox.inline', text: 'Remember me') }
      it { expect(page).to have_button('Log in') }
    end

SupportModule, shared_context, ファクトリ

  • SupportModule

    • fill_in_login_form(user) (ログイン情報が 有効/無効)
    • error_messages "Invalid email/password combination" の部分
support_module.rb
  # spec/support/support_module.rb
  module SupportModule
    def fill_in_login_form(user, option = { invalid: false })
      if option[:invalid]
        fill_in "Email",        with: ""
        fill_in "Password",     with: ""
      else
        fill_in "Email",        with: user.email
        fill_in "Password",     with: user.password
      end
    end
  end
  module SupportModule
    def error_messages(msg = "")
      # should have_css('div#error_explanation')
      # should have_css('div.alert.alert-danger') if msg.empty? and return
      if msg.empty?
        should have_css('div.alert.alert-danger')
      else
        should have_css('div.alert.alert-danger', text: msg)
      end
    end
  end
  • shared_context
shared_context
  # spec/support/shared_context.rb
  RSpec.shared_context "setup" do
    # 遅延評価、呼ばれた時にDB保存される
    let(:user) { create(:user) }
  end
  • ファクトリ(ユーザ)
users.rb
  # spec/support/factories/users.rb
  FactoryBot.define do
    # 自分
    # factory [任意のファクトリ名], class: [クラス名]
    factory :user, class: User do
      name     "Example user"
      email    "user@example.com"
      password              "foobar"
      password_confirmation "foobar"
      admin false
  end

実行結果 1/2

$ bin/rspec spec/features/users_login_spec.rb -e "log in"

UsersLogin
  log in
    behaves like login-form have right css
      should have visible css "label" with text "Email"
      should have visible css "label" with text "Password"
      should have visible css "input#session_email"
      should have visible css "input#session_password"
      should have visible css "input#session_remember_me[type=\"checkbox\"]"
      should have visible css "label.checkbox.inline" with text "Remember me"
      should have visible button "Log in"
    valid info
      success log in
    invalid info
      fail log in

Finished in 4.9 seconds (files took 2.28 seconds to load)
9 examples, 0 failures


アウトライン作成 2/2

users_login_spec.rb
# spec/features/users_login_spec.rb
RSpec.feature "UsersLogin", type: :feature do

  # (省略)

  # ログアウト
  describe "log out"
    # ログアウトが正常にできること
    describe "success log out"
      # 同じサイトを 複数tab/window で開いている状態をシュミレート
      context "when open in some browser-tab(or window)"
      # "Log out" をクリック 1回目をシュミレート
      scenario "1st time log out"
      # "Log out" をクリック 2回目をシュミレート
      scenario "2nd time log out"

end

スペック作成 2/2

users_login_spec.rb
# spec/features/users_login_spec.rb
require 'rails_helper'

RSpec.feature "UsersLogin", type: :feature do

  include SupportModule
  include_context "setup"

  subject { page }

  # (省略)

  # ログアウト
  describe "log out" do
    # ログアウトが正常にできること
    describe "success log out" do
      # 同じサイトを 複数tab/window で開いている状態をシュミレート
      context "when open in some browser-tab(or window)" do
        # "Log out" をクリック 1回目をシュミレート
        scenario "1st time log out" do
          login_as(user)
          click_link "Log out"
          should have_current_path(root_path)
        end
        # "Log out" をクリック 2回目をシュミレート
        # HTTPリクエストを直接送るので、type: :request オプションをつける
        scenario "2nd time log out", type: :request do
          delete logout_path(user)
          should have_current_path(root_path)
        end
      end
    end
  end
end

SupportModule

  • login_as(user) の部分
  # spec/support/support_module.rb
  module SupportModule
    def login_as(user)
      visit root_path
      click_link "Log in"
      fill_in "Email",    with: user.email
      fill_in "Password", with: user.password
      click_button "Log in"
    end
  end

実行結果 2/2

$ bin/rspec spec/features/users_login_spec.rb -e "log out"

UsersLogin
  log out
    success log out
      when open in some browser-tab(or window)
        1st time log out
        2nd time log out

Finished in 5.62 seconds (files took 2.19 seconds to load)
2 examples, 0 failures


参考


参考


続く

フィーチャスペック編 users_profile_spec 4/7