Skip to content

Commit

Permalink
Provide helpers to be used in view specs
Browse files Browse the repository at this point in the history
This brings versions of the controller spec helpers `sign_in` and
`sign_in_as` to view and helper specs and does so in a way that avoids
people getting [errors from verified partial doubles][1]. The downside
of this approach is that it changes the subject under test (the view) by
introducing these helper methods directly on it. I don't think that's
much different than controller helper methods, though.

There is potential for confusion among users that might expect calling
`sign_in` or `sign_in_as` would come with all of the same side effects
that calling these methods from a controller or controller spec would.
In reality, they are just fancy ways to set the `current_user` local
variable and have no side effects. I feel that the potential confusion
from this has less impact than having to remember different helper
method names depending on whether you are in a controller spec or a view
spec.

As part of this change, I moved the existing
`Clearance::Testing::Helpers` module to
`Clearance::Testing::ControllerHelpers` and deprecated the old name.
This is a more accurate name and allows us to isolate the `ViewHelpers`
which are not useful in test_unit.

[1]: rspec/rspec-rails#1076

fix readme

helpers too!

feedback
  • Loading branch information
derekprior committed Jun 26, 2015
1 parent d080a5b commit 462c009
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 39 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,23 @@ sign_in_as(user)
sign_out
```

### View and Helper Spec Helpers

Does the view or helper you're testing reference `signed_in?`, `signed_out?` or
`current_user`? If you `require 'clearance/rspec'`, you will have the following
helpers available in your view specs:

```ruby
sign_in
sign_in_as(user)
```

These will make the clearance view helpers work as expected by signing in either
a new instance of your user model (`sign_in`) or the object you pass to
`sign_in_as`. If you do not call one of these sign in helpers or otherwise set
`current_user` in your view specs, your view will behave as if there is no
current user: `signed_in?` will be false and `signed_out?` will be true.

## Contributing

Please see [CONTRIBUTING.md].
Expand Down
19 changes: 15 additions & 4 deletions lib/clearance/rspec.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
require 'rspec/rails'
require 'clearance/testing/deny_access_matcher'
require 'clearance/testing/helpers'
require "rspec/rails"
require "clearance/testing/deny_access_matcher"
require "clearance/testing/controller_helpers"
require "clearance/testing/view_helpers"

RSpec.configure do |config|
config.include Clearance::Testing::Matchers, type: :controller
config.include Clearance::Testing::Helpers, type: :controller
config.include Clearance::Testing::ControllerHelpers, type: :controller
config.include Clearance::Testing::ViewHelpers, type: :view
config.include Clearance::Testing::ViewHelpers, type: :helper

config.before(:each, type: :view) do
view.extend Clearance::Testing::ViewHelpers::CurrentUser
end

config.before(:each, type: :helper) do
view.extend Clearance::Testing::ViewHelpers::CurrentUser
end
end
6 changes: 3 additions & 3 deletions lib/clearance/test_unit.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
require 'clearance/testing/deny_access_matcher'
require 'clearance/testing/helpers'
require "clearance/testing/deny_access_matcher"
require "clearance/testing/controller_helpers"

ActionController::TestCase.extend Clearance::Testing::Matchers

class ActionController::TestCase
include Clearance::Testing::Helpers
include Clearance::Testing::ControllerHelpers
end
35 changes: 35 additions & 0 deletions lib/clearance/testing/controller_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module Clearance
module Testing
module ControllerHelpers
# @private
def setup_controller_request_and_response
super
@request.env[:clearance] = Clearance::Session.new(@request.env)
end

# Signs in a user that is created using FactoryGirl.
# The factory name is derrived from your `user_class` Clearance
# configuration.
# @raise [RuntimeError] if FactoryGirl is not defined.
def sign_in
unless defined?(FactoryGirl)
raise("Clearance's `sign_in` helper requires factory_girl")
end

factory = Clearance.configuration.user_model.to_s.underscore.to_sym
sign_in_as FactoryGirl.create(factory)
end

# Signs in the provided user.
def sign_in_as(user)
@controller.sign_in user
user
end

# Signs out a user that may be signed in.
def sign_out
@controller.sign_out
end
end
end
end
34 changes: 9 additions & 25 deletions lib/clearance/testing/helpers.rb
Original file line number Diff line number Diff line change
@@ -1,31 +1,15 @@
require "clerance/testing/controller_helpers"

module Clearance
module Testing
# @deprecated Use Clearance::Testing::ControllerHelpers
module Helpers
def setup_controller_request_and_response
super
@request.env[:clearance] = Clearance::Session.new(@request.env)
end

def sign_in
unless defined?(FactoryGirl)
raise(
RuntimeError,
"Clearance's `sign_in` helper requires factory_girl"
)
end

factory = Clearance.configuration.user_model.to_s.underscore.to_sym
sign_in_as FactoryGirl.create(factory)
end

def sign_in_as(user)
@controller.sign_in user
user
end

def sign_out
@controller.sign_out
end
warn(
"#{Kernel.caller.first} [DEPRECATION] Clearance::Testing::Helpers is "\
"deprecated and has been replaced with " \
"Clearance::Testing::ControllerHelpers. Require " \
"clearance/testing/controller_helpers instead."
)
end
end
end
32 changes: 32 additions & 0 deletions lib/clearance/testing/view_helpers.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module Clearance
module Testing
# Provides helpers to your view and helper specs.
# Using these helpers makes `current_user`, `signed_in?` and `signed_out?`
# behave properly in view and helper specs.
module ViewHelpers
# Sets current_user on the view under test to a new instance of your user
# model.
def sign_in
view.current_user = Clearance.configuration.user_model.new
end

# Sets current_user on the view under test to the supplied user.
def sign_in_as(user)
view.current_user = user
end

# @private
module CurrentUser
attr_accessor :current_user

def signed_in?
current_user.present?
end

def signed_out?
!signed_in?
end
end
end
end
end
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
require 'spec_helper'
require "spec_helper"

describe Clearance::Testing::Helpers do
describe Clearance::Testing::ControllerHelpers do
class TestClass
include Clearance::Testing::Helpers
include Clearance::Testing::ControllerHelpers

def initialize
@controller = Controller.new
Expand All @@ -13,8 +13,8 @@ def sign_in(user); end
end
end

describe '#sign_in' do
it 'creates an instance of the clearance user model with FactoryGirl' do
describe "#sign_in" do
it "creates an instance of the clearance user model with FactoryGirl" do
MyUserModel = Class.new
allow(FactoryGirl).to receive(:create)
allow(Clearance.configuration).to receive(:user_model).
Expand All @@ -26,8 +26,8 @@ def sign_in(user); end
end
end

describe '#sign_in_as' do
it 'returns the user if signed in successfully' do
describe "#sign_in_as" do
it "returns the user if signed in successfully" do
user = build(:user)

returned_user = TestClass.new.sign_in_as user
Expand Down
37 changes: 37 additions & 0 deletions spec/clearance/testing/view_helpers_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require "spec_helper"

describe Clearance::Testing::ViewHelpers do
describe "#sign_in" do
it "sets the signed in user to a new user object" do
user_model = Class.new
allow(Clearance.configuration).to receive(:user_model).
and_return(user_model)

view = test_view_class.new
view.sign_in

expect(view.current_user).to be_an_instance_of(user_model)
end
end

describe "#sign_in_as" do
it "sets the signed in user to the object provided" do
user = double("User")

view = test_view_class.new
view.sign_in_as(user)

expect(view.current_user).to eq user
end
end

def test_view_class
Class.new do
include Clearance::Testing::ViewHelpers

def view
@view ||= extend Clearance::Testing::ViewHelpers::CurrentUser
end
end
end
end
10 changes: 10 additions & 0 deletions spec/helpers/helper_helpers_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "spec_helper"

describe "Clearance RSpec helper spec configuration", type: :helper do
it "lets me use clearance's helper methods in helper specs" do
user = double("User")
sign_in_as(user)

expect(helper.current_user).to eq user
end
end
10 changes: 10 additions & 0 deletions spec/views/view_helpers_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require "spec_helper"

describe "Clearance RSpec view spec configuration", type: :view do
it "lets me use clearance's helper methods in view specs" do
user = double("User")
sign_in_as(user)

expect(view.current_user).to eq user
end
end

0 comments on commit 462c009

Please sign in to comment.