On Jul 26, 2011, at 12:51 AM, Patrick J. Collins wrote:

>> Here's an example of my first test, but I'm wondering how I setup the
>> login routine so I can use it in future specs without repeating the
>> method. Some sort of  -  before.each (:login)
> You can use shared examples...
> 
> shared_examples_for "any page requiring authentication" do
>       fill_in :login, :with => @user.email
>       fill_in :password, :with => @user.password
>       click_button "login_button"
>       page.has_content?("Logged in successfully")
> end
> 
> Then in your specs you can do:
> 
> describe User do
>  it_behaves_like "any page requiring authentication"
> end

You _can_ use shared content, but what you have here ^^ doesn't work as 
written. The scope in the shared_examples_for block is an example group scope, 
not an example scope, so methods like fill_in and click_button are not 
available. You'd want to wrap them in a before block. Also, 
page.has_content?(...) will return true or false, but will not act like an 
expectation (i.e. RSpec won't care which it returns).

Here are a couple of ways you could do this that will work as Chris expects:

shared_context "logged in" do
  let(:user) { Factory(:user) }
  before do
    fill_in :login, :with => user.email
    fill_in :password, :with => user.password
    click_button "login_button"
  end
end

describe ArticlesController do
  include_context "logged in"
  describe "GET edit" do
    it "does something" do
      # here the shared before hook has already run
      # and you have access to the `user` generated
      # by the `let` declaration.
    end
  end
end

This assumes you only want one user. It's simple and clean, without confusing 
indirection or parameterization. On the other extreme you could do this:

shared_context "logged in" do
  before do
    visit new_session_path
    fill_in :login, :with => user.email
    fill_in :password, :with => user.password
    click_button :submit
  end
end

shared_context "admin" do
  let(:user) { Factory(:admin_user) }
  include_context "logged in"
end

shared_context "staff" do
  let(:user) { Factory(:staff_user) }
  include_context "logged in"
end

RSpec.configure do |conf|
  conf.alias_it_should_behave_like_to :logged_in_as
end

describe "Articles" do
  describe "GET index" do
    logged_in_as "admin" do
      it "does something" do
        # ...
      end
    end
    logged_in_as "staff" do
      it "does something else" do
        # ...
      end
    end
  end
end

The output from this looks like:

ArticlesController
  GET index
    logged in as admin
      does something
    logged in as staff
      does something else

Both of these approaches keep things explicit. You can also do a more implicit 
approach, like this:

RSpec.configure do |c|
  c.before(:each, :type => :request) do
    @user = Factory(:user)
    visit new_session_path
    fill_in :login, :with => @user.email
    fill_in :password, :with => @user.password
    click_button :submit
  end
end

describe "Articles" do
  describe "GET index" do
    it "does something" do
      # ...
    end
  end
end

Here you don't see any evidence in the example that you're logging in. Less 
typing, but less clarity. I'd avoid this approach myself, but it is another 
option for you.

HTH,
David


    

> Patrick J. Collins
> http://collinatorstudios.com

_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to