13 July 2015

Test model with Sorcery authentication

See ActivityLogger application

To pass the tests, in views use

Evaluate 'current_user' to avoid “undefined method `admin?' for nil:NilClass”

if current_user && current_user.admin?

user_spec.rb

require 'rails_helper'

describe "Integration test", type: :feature do
  
  before(:each) do
    admin = FactoryGirl.create(:user_admin)
    login_user_post(admin.email, "123")
  end

  it "signs me in" do
    expect(page).to have_content 'You are being redirected'
  end

  context "when checking validations" do
    it "rejects without name" do
      user = FactoryGirl.build :user, name: ""
      expect(user.valid?).to be false
      expect(user.errors["name"].present?).to be true
    end

...

FactoryGirl

FactoryGirl.define do
  factory :user do
    factory :user_admin do
      name                  {Faker::Name.name}
      email                 {Faker::Internet.email}
      admin                 {true}
      password              {"123"}
      password_confirmation {"123"}
    end
  end
end

spec/support/sorcery.rb

module Sorcery
  module TestHelpers
    module Rails
      module Integration
        def login_user_post(email, password)
          page.driver.post(user_sessions_url, { email: email, password: password } )
        end
      end
    end
  end
end 

spec_helper.rb

  config.include Sorcery::TestHelpers::Rails::Controller, type: :controller
  config.include Sorcery::TestHelpers::Rails::Integration, type: :feature

Speed up tests changing encryption algorithm to md5

Rails.application.config.sorcery.configure do |config|
  config.user_config do |user|
    user.encryption_algorithm = :md5 if Rails.env.test?
  end
end

Testing forms with multiple parameters

Application: SAAP

# gates_controller_spec.rb
describe "POST add loop" do
    it "adds a loop to the gate" do
      gate = Gate.create! valid_attributes
      loop = FactoryGirl.create :loop
      expect { 
        post :add_loop, {id: gate.id, :loop => {:id => loop.id}}
        }.to change(gate.loops, :count).by(1)
    end
  end
# _add_loops.html.erb
<h3>Add loops</h3>
<%= form_tag :area_add_loop do %>
  <div class="field">
    <%= label_tag :loop %>
    <%= collection_select nil, nil, Loop.all, nil, nil, include_blank: true %>
  </div>
  <div class="actions">
    <%= submit_tag :Add %>
  </div>
<% end %>
class GatesController < ApplicationController
  before_action :set_gate, only: [:show, :edit, :update, :destroy, :add_loop, :remove_loop]

  def add_loop
    unless (loop_id = params['loop']['id']).empty?
      loop = Loop.find(loop_id)
      @gate.loops << loop unless @gate.loops.include?(loop)
    end
    render :edit
  end
...