[cucumber] webrat+selenium integration problem: record not saved to database?

Hey,

I am writing a simple cucumber feature for a Rails app to test if the
webrat+selenium integration was successful:

Scenario: Successful log in
Given the user “pepito” exists # (1)
And the user “pepito” is active
When I go to the login page
And I fill in “login” with “pepito”
And I fill in “password” with “secret”
And I press “submit” # (2)
Then I should see a confirmation message

Now I think I managed to set up the architecture all right (using sep.
setup files for plain and javascript -selenium- features as described
here:
http://wiki.github.com/aslakhellesoy/cucumber/setting-up-selenium).
The problem is that the “Then I should see a confirmation message”
fails.

I put a breakpoint at (2) to investigate the problem. I’ve found that:

  1. the user is succesfully created (User.first in a rails console
    gives back pepito)
  2. I can log in successfully from the console (User.authenticate
    (“pepito”, “secret”) gives back the user meaning successful
    authentication.
  3. The login and password fields are correctly filled with the values
    (checking that in the launched FF browser)
  4. If I manually submit the form at the breakpoint, it also fails to
    log in, so it’s not that the "And I press “submit” step does something
    other than submitting the form.
  5. the users table in the database that selenium uses is empty.
    (mysql> select * from users;
    Empty set (0.00 sec) ). That surprises me a bit since in theory
    selenium does not use transactional fixtures so the record should
    appear right away after (1) runs.

Here are my cucumber config file(s):

I run the feature like this:

cucumber -r features/support/env.rb -r features/support/enhanced.rb -r
features/step_definitions features/enhanced/login.feature

And these are the setup steps to create and activate the user:

Given /^the user “(.*)” exists$/ do |login_name|
User.find_by_login(login_name) || Factory
(:user_with_password, :login => login_name)
end

Given /^the user “(.*)” is active$/ do |login_name|
User.find_by_login(login_name).activate!
end

I also see in the log that the form is submitted with the correct
parameters.

Please let me know if you see what I am missing or what I should do
differently.

Thank you,
Balint

Balint E. wrote:

And I fill in "password" with "secret"
  1. the users table in the database that selenium uses is empty.
    (mysql> select * from users;
    Empty set (0.00 sec) ). That surprises me a bit since in theory
    selenium does not use transactional fixtures so the record should
    appear right away after (1) runs.

Webrat’s Selenium adapter will not change your DB settings. On line 10
on your env.rb file you actually have transactional support turned on.
You need to comment that line out when using Selenium. For more info
please read about this problem on the wiki:

http://wiki.github.com/aslakhellesoy/cucumber/troubleshooting

HTH,
Ben

If you actually want to use transactional fixtures with selenium, try
out

Something I coded up that allows selenium to work with transactional
fixtures.

Balint E. wrote:

but finally I gave up and am now using the test for both selenium and
“plain” cucumber features. So the database_cleaner serves me even
better. It works! My current config is here:
cucumber.yml · GitHub. Once again, thank you for your help.

Couple things I’d like to point out. In your enhanced.rb you don’t need
to do the Before hook yourself. You can just require
‘database_cleaner/cucumber’. I’ve updated your gist to use that.
In your plain.rb it seems like you are trying to truncate your database
just once upon startup. If that is the case then the recommended way is
to use the clean_with method like so:
DatabaseCleaner.clean_with :truncation

Again, I have updated the gist to reflect this.

-Ben

@Ben: Thank you, I fixed that and am using your database_cleaner to
truncate the database.

Turns out the problem (or rather, another problem) was that I set up a
separate environment (selenium) for the selenium tests but still some of
the steps used the test environment and thus the database record was
generated in the test database not in the selenium one where it should
have been.

I struggled to get the record creation happen in the selenium database
but finally I gave up and am now using the test for both selenium and
“plain” cucumber features. So the database_cleaner serves me even
better. It works! My current config is here:
cucumber.yml · GitHub. Once again, thank you for your help.

@Mike: I may check that out, thank you!

Balint

Ben M. wrote:

Balint E. wrote:

And I fill in "password" with "secret"
  1. the users table in the database that selenium uses is empty.
    (mysql> select * from users;
    Empty set (0.00 sec) ). That surprises me a bit since in theory
    selenium does not use transactional fixtures so the record should
    appear right away after (1) runs.

Webrat’s Selenium adapter will not change your DB settings. On line 10
on your env.rb file you actually have transactional support turned on.
You need to comment that line out when using Selenium. For more info
please read about this problem on the wiki:

http://wiki.github.com/aslakhellesoy/cucumber/troubleshooting

HTH,
Ben

Ben M. wrote:

Couple things I’d like to point out. In your enhanced.rb you don’t need
to do the Before hook yourself. You can just require
‘database_cleaner/cucumber’. I’ve updated your gist to use that.
In your plain.rb it seems like you are trying to truncate your database
just once upon startup. If that is the case then the recommended way is
to use the clean_with method like so:
DatabaseCleaner.clean_with :truncation

Again, I have updated the gist to reflect this.

-Ben

Hey Ben, thanks a lot.

The problem I am experiencing now is that information stored in the
session does not seem to be retained between steps (again, only in the
case of selenium sessions, plain sesssion work fine). So the login
function works fine now but when I go to another page afterwards it
throws a big error because the action tries to render something based on
the current user.

Is the session store I am using relevant? I used the default
cookie-based storage and then tried to change to the active-record based
one to no avail. My config is at cucumber.yml · GitHub

Thank you,
Balint

Balint E. wrote:

cookie-based storage and then tried to change to the active-record based
group" link

the “test session” (I know this is not the proper definition but I
And I press “entrar”

Yep… that is what I thought was happening. The “test session” is rails
integration session that webrat uses.
I would still use your login step but just have it hit the form. So
something like:

Given /^I log in as “(.*)”$/ do |login_name|
@user = User.find_by_login(login_name)
vist “/session”
fill_in “login”, :with => login_name
fill_in “password”, :with => ‘secret’
click_button “entrar”
end

With that step definition you don’t need to pollute all of your features
with the steps to login. As it turns out you can have the best of both
worlds. Meaning, if you want webrat to use the faster post method only
for non-selenium runs you can. Like so:

Given /^I log in as “(.*)”$/ do |login_name|
@user = User.find_by_login(login_name)
webrat.atutomate do
vist “/session”
fill_in “login”, :with => login_name
fill_in “password”, :with => ‘secret’
click_button “entrar”
end

webrat.simulate do
  post "/session", :login => @user.login, :password => 'secret'
end

end

In short, the webrat#automate block is only executed with an adapter
that is automating a real browser. Likewise the webrat#simulate block
is only executed when the adapter is simulating a browser, such as the
rails adapter. Does that make sense?

-Ben

Hey Ben, thanks a lot.

The problem I am experiencing now is that information stored in the
session does not seem to be retained between steps (again, only in the
case of selenium sessions, plain sesssion work fine). So the login
function works fine now but when I go to another page afterwards it
throws a big error because the action tries to render something based on
the current user.

Is the session store I am using relevant? I used the default
cookie-based storage and then tried to change to the active-record based
one to no avail. My config is at cucumber.yml · GitHub

Thank you,
Balint

Ok, I think I have the problem and it has nothing to do with session
storage. I intend to explain it below so others might benefit from it.

Scenario: Successfully sharing album with group via the “Share with
group” link
Given I am logged in as “pepito”
When I go to my photosets page

I used some existing step definitions I wrote for non-selenium features
to log in the user like so:

Given /^I log in as “(.*)”$/ do |login_name|
@user = User.find_by_login(login_name)
post “/session”, :login => @user.login, :password => ‘secret’ # !!!
end

Given /^I am logged in as “(.*)”$/ do |login_name|
Given %(the user “#{login_name}” exists)
Given %(the user “#{login_name}” is active)
Given %(I log in as “#{login_name}”)
end

When the feature gets to “When I go to my photosets page”, the selenium
browser is launched but there is no user logged in here, there is no
session, so that step will fail miserably. That’s because the line
denoted by !!! does not log in the user in the selenium session but in
the “test session” (I know this is not the proper definition but I
cannot precisely name it).

So if I need a logged in user in a selenium feature I should go the
“hard way” and start from scratch:

Given the user “pepito” exists
And the user “pepito” is active
When I go to the login page
And I fill in “login” with “pepito”
And I fill in “password” with “secret”
And I press “entrar”
And I go to my photosets page

It takes some time to get one’s head around realizing there is a test
world and a selenium world and keep in mind which action modifies which
world and learn how they can interact with each other (through the
database I guess if they use the same environment).

Please correct me if I am wrong in anything I say above,
Balint

Balint E. wrote:

function works fine now but when I go to another page afterwards it
throws a big error because the action tries to render something based on
the current user.

Is the session store I am using relevant? I used the default
cookie-based storage and then tried to change to the active-record based
one to no avail. My config is at cucumber.yml · GitHub

Hmm… I’ve never had issues with sessions not persisting when using the
selenium adapter. Nothing in your config looks wrong.
What is your login method? It is telling Selenium to go to the login
page and submit the proper credentials?

Ben

Ben M. wrote:

With that step definition you don’t need to pollute all of your features
with the steps to login. As it turns out you can have the best of both
worlds. Meaning, if you want webrat to use the faster post method only
for non-selenium runs you can. Like so:

Given /^I log in as “(.*)”$/ do |login_name|
@user = User.find_by_login(login_name)
webrat.atutomate do
vist “/session”
fill_in “login”, :with => login_name
fill_in “password”, :with => ‘secret’
click_button “entrar”
end

webrat.simulate do
  post "/session", :login => @user.login, :password => 'secret'
end

end

Excellent (and elegant), it works now!

Thank you for your help along the way,
Balint

Balint E. wrote:

Ben M. wrote:

Couple things I’d like to point out. In your enhanced.rb you don’t need
to do the Before hook yourself. You can just require
‘database_cleaner/cucumber’. I’ve updated your gist to use that.
In your plain.rb it seems like you are trying to truncate your database
just once upon startup. If that is the case then the recommended way is
to use the clean_with method like so:
DatabaseCleaner.clean_with :truncation

Again, I have updated the gist to reflect this.

-Ben

Hey Ben, thanks a lot.

The problem I am experiencing now is that information stored in the
session does not seem to be retained between steps (again, only in the
case of selenium sessions, plain sesssion work fine). So the login
function works fine now but when I go to another page afterwards it
throws a big error because the action tries to render something based on
the current user.

Is the session store I am using relevant? I used the default
cookie-based storage and then tried to change to the active-record based
one to no avail. My config is at cucumber.yml · GitHub

Thank you,
Balint

hi Ben

I am newbie with cucumber and bdd. I was wondering if you can take a
look on my problems.
I have similar problem like Balint. I test my own and clearance features
with selenium and webrat. I don’t have to say that with werbrat
everything is perfect. When I run features with selenium I get error
nil.session what is connected with code from clearance features ie:

Then /^I should not be signed in$/ do
  assert_nil request.session[:user_id]
end

in clearance_step file

It seems like selenium has problem with access to “request” object
That makes my test fail all the time.

Another problem I met is with waiting for response after “press button”
method
All the time I get response with code before button pressed
It’s connected with selenium_session.rb code and require me to change a
bit

    def click_button(button_text_or_regexp = nil, options = {})
      if button_text_or_regexp.is_a?(Hash) && options == {}
        pattern, options = nil, button_text_or_regexp
      elsif button_text_or_regexp
        pattern = adjust_if_regexp(button_text_or_regexp)
      end
      pattern ||= '*'
      locator = "button=#{pattern}"

      selenium.wait_for_element locator, :timeout_in_seconds => 5
      selenium.click locator
      selenium.wait_for_page_to_load(5) ## add this line to get correct 
response
    end

I don’t know why I have to change it
Thanks

Hi Mateusz,

hi Ben

I am newbie with cucumber and bdd. I was wondering if you can take a
look on my problems.
I have similar problem like Balint. I test my own and clearance features
with selenium and webrat. I don’t have to say that with werbrat
everything is perfect. When I run features with selenium I get error
nil.session what is connected with code from clearance features ie:

Then /^I should not be signed in$/ do
  assert_nil request.session[:user_id]
end

in clearance_step file

It seems like selenium has problem with access to “request” object
That makes my test fail all the time.

I cannot tell you whether step definitions should have access to the
request via the request variable (they probably should). But are you
sure you need to test the session directly like this? I searched for
‘request’ or ‘session’ in my step definitions and have not found any.
Usually I check whether

  1. a certain thing is on the page which usually involves checking the
    response body with the help of the webrat steps file (e.g I should see
    “You are logged in”)
  2. a new model instance has (not) been created or have an attribute set
    to a certain value, etc. In brief, database related things.

Another problem I met is with waiting for response after “press button”
method
All the time I get response with code before button pressed
It’s connected with selenium_session.rb code and require me to change a
bit
(…)
I don’t know why I have to change it
Thanks

That’s a bug in webrat I also came across and fixed:
https://webrat.lighthouseapp.com/projects/10503/tickets/205-patch-timeout-parameter-passed-incorrectly-to-selenium

It will surely be integrated in the next webrat release, you can use the
supplied patch.

Hope that helps,
Balint

Mateusz Juraszek wrote:

to use the clean_with method like so:
case of selenium sessions, plain sesssion work fine). So the login

Then /^I should not be signed in$/ do
assert_nil request.session[:user_id]
end

Yuck! I realize that you didn’t write this and that Clearance gave you
this step out of the box:

It is, IMO, a very bad way to verify if the user is logged in. (I
actually used an example very similar to this in my MWRC
presentation[1]. One of the reasons that makes it bad is that it makes
it difficult to switch from using rails integration session to an
automated browser solution like Selenium.

in clearance_step file

It seems like selenium has problem with access to “request” object
That makes my test fail all the time.

Yep, that object exists in rails integration sessions, which is what
webrat’s :rails mode uses. To avoid this error you will need to specify
behaviour, not implementation. I’m guessing that this step is called
after you have logged out. So, the way I would test this is that I
would test it from the point of view of the user. The user doesn’t know
about a session, much less how we are implementing our authentication
system. :slight_smile: When this user logs out they probably see a message
indicating that they have been logged out though. So, something like
this would be better:

Then /^I should not be signed in$/ do
response.should contain(“You have been logged out.”)
end

(Note: I’m not sure if clearance says this exactly, but you get the
idea…)

Using a step like this will allow you to switch between multiple
adapters since you should always have the response object.

    pattern = adjust_if_regexp(button_text_or_regexp)

I don’t know why I have to change it

Hmmm… Yeah, I don’t know about that. You should probably ask the
webrat mailing list or open up a ticket[2].

-Ben

http://mwrc2009.confreaks.com/14-mar-2009-15-00-bdd-with-cucumber-ben-mabey.html
2. http://wiki.github.com/brynary/webrat/get-in-touch

That makes more sense than my theory.
Thank you Ben and thank you Balint.

BTW nice presentation

Another problem I met is with waiting for response after “press button”
method
All the time I get response with code before button pressed
It’s connected with selenium_session.rb code and require me to change a
bit
(…)
I don’t know why I have to change it
Thanks

That’s a bug in webrat I also came across and fixed:
#205 [PATCH] timeout parameter passed incorrectly to selenium - Webrat - webrat

It will surely be integrated in the next webrat release, you can use the
supplied patch.

Hope that helps,
Balint

As you can see in my first post I actually used your solution first
(selenium.wait_for_element locator, :timeout_in_seconds => 5 for each
method) but it doesn’t work for me, because in my case selenium compares
expectations with page source before action (page source before sending
form and get redirection etc). Then I added
selenium.wait_for_page_to_load(5) to get correct request.