ruby-on-railstestingrspeccucumberwebrat

Session variables with Cucumber Stories


I am working on some Cucumber stories for a 'sign up' application which has a number of steps.

Rather then writing a Huuuuuuuge story to cover all the steps at once, which would be bad, I'd rather work through each action in the controller like a regular user. My problem here is that I am storing the account ID which is created in the first step as a session variable, so when step 2, step 3 etc are visited the existing registration data is loaded.

I'm aware of being able to access controller.session[..] within RSpec specifications however when I try to do this in Cucumber stories it fails with the following error (and, I've also read somewhere this is an anti-pattern etc...):

Using controller.session[:whatever] or session[:whatever]

You have a nil object when you didn't expect it!
The error occurred while evaluating nil.session (NoMethodError)

Using session(:whatever)

wrong number of arguments (1 for 0) (ArgumentError)

So, it seems accession the session store isn't really possible. What I'm wondering is if it might be possible to (and I guess which would be best..):

  1. Mock out the session store etc
  2. Have a method within the controller and stub that out (e.g. get_registration which assigns an instance variable...)

I've looked through the RSpec book (well, skimmed) and had a look through WebRat etc, but I haven't really found an answer to my problem...

To clarify a bit more, the signup process is more like a state machine - e.g. the user progresses through four steps before the registration is complete - hence 'logging in' isn't really an option (it breaks the model of how the site works)...

In my spec for the controller I was able to stub out the call to the method which loads the model based on the session var - but I'm not sure if the 'antipattern' line also applies to stubs as well as mocks?

Thanks!


Solution

  • mocks are bad in cucumber scenarios - they're almost kind of an antipattern.

    My suggestion is to write a step that actually logs a user in. I do it this way

    Given I am logged in as "auser@example.com"
    
    Given /^I am logged in as "(.*)"$/ do |email|
      @user = Factory(:user, :email => email)
      @user.activate!
      visit("/session/new")
      fill_in("email", :with => @user.email)
      fill_in("password", :with => @user.password)
      click_button("Sign In")
    end
    

    I realize that the instance variable @user is kind of bad form—but I think in the case of logging in/out, having @user is definitely helpful.

    Sometimes I call it @current_user.