Tuesday, June 14, 2011

Capybara (click_link, JS problem) & Logging in directly with Authlogic

The click_link / JS problem
I'm using capybara, and I recently came across this error:
Given I am on the home page                              # features/step_definitions/web_steps.rb:42
And I am the registered poster "John Doe"                # features/step_definitions/user_steps.rb:1
When I log in                                            # features/step_definitions/user_steps.rb:11
      You have a nil object when you didn't expect it!
      You might have expected an instance of Array.
      The error occurred while evaluating nil.[] (NoMethodError)
      (eval):2:in `click_link'
      ./features/step_definitions/user_steps.rb:12:in `/^I log in$/'
      features/users_have_basic_abilities.feature:10:in `When I log in'
This was my step definition:

When /^I log in$/ do
  click_link "Login"
end

This is the kind of error that arises if the link you want to click has href="javascript:void(0)".  In my case, my link was

<a href="javascript:void(0)" id="login_activator">Login</a>

With the help of jQuery, this link toggles a div for the login form, but there is no easy way to test this with Capybara because Capybara uses RackTest, which doesn't execute JS.

My solution: avoid the complications of this JS testing (I'm positive it works anyway), and instead forcibly create user session to login.  After all, that's the whole point of this logging in thing - it should be preliminary for what I really want to test.

Logging in directly with Authlogic
I am using Authlogic (https://github.com/binarylogic/authlogic) for user validation.
While trying code like UserSession.create!(:login => etc., :password => "some_password" ...), I came across this error:
You must activate the Authlogic::Session::Base.controller with a controller object before creating objects (Authlogic::Session::Activation::NotActivatedError)
The solution: ensure the following code is executed before such a user session creation:

Authlogic::Session::Base.controller = Authlogic::ControllerAdapters::RailsAdapter.new(self)

Yep.
Unfortunately, in the end even there still were problems with the "save" method no longer working - something about the improper number of arguments.
So, my FINAL solution was that I had to use the Cucumber steps of navigating to some page, filling in the login form, clicking the button, etc.  I guess there never really was a good solution to all of this, so I recommend against using the type of link I did above (a link that opens a little form on the page).

2 comments:

  1. I had this problem too. I just posted a solution I found on Stack Overflow. Take a look here.

    ReplyDelete
  2. "avoid the complications of this JS testing (I'm positive it works anyway)"—no, you're not, or else you wouldn't be testing it. "After all, that's the whole point of this logging in thing - it should be preliminary for what I really want to test."—Yes, but it should still go through the UI. Integration tests shouldn't mess with app internals.

    ReplyDelete

Please be considerate in what you say.