Simultaneous Capybara Sessions in Cucumber
There’s something very satisfying about watching your Cucumber test suite run (and pass), especially when the tests are running in your browser. I can’t help but think, “Man, I’m glad I don’t have to do all of this myself.” That’s especially true when your testing requires multiple sessions. The old me would fire up a couple different browsers and get to work. But that was the old me.
The New Me: Powered by Capybara
Capybara 1.0.0 added the ability to name your sessions. Prior to this, a session was only identified by its driver (before & after). It’s a small change with big benefit. For instance…
Testing Pub/Sub
If you’re not familiar with the latest Pub/Sub craze, check out Pusher and PubNub. They’re similar services enabling your app to push JSON to your user’s browser rather than the browser polling for updates. It’s all very cool. And for me, it was also tricky to test.
Imagine we’re developing a simple chat feature inside a Rails app. I’ll skip the specifics of integrating with Pusher or PubNub so we can focus on the tests. The challenge is to bring up two browser windows with separate sessions and test that they can chat with each other. Enter: named Capybara sessions. With a couple simple Cucumber steps, this is a breeze. Here’s our feature:
@javascript
Feature: Chat
As a user
I want to chat with other users
So I feel like part of a community
Scenario: Push for chat
Given the following users exist:
| Name |
| Steve |
| Catie |
When I am in Steve's browser
And I am logged in as "Steve"
And I go to the messages page
Then I should not see "Hi, Steve!"
When I am in Catie's browser
And I am logged in as "Catie"
And I go to the new message page
And I fill in "Body" with "Hi, Steve!"
And I press "Send"
And I wait 2 seconds
Then I should see "Hi, Steve!"
When I am in Steve's browser
Then I should see "Hi, Steve!"
Many of those steps come from Capybara’s web\_steps.rb
, with some help from Factory Girl. The “logged in” steps are custom but I’ll leave them out here because they’re usually pretty application-specific. That leaves these custom steps:
When /^I am in (.*) browser$/ do |name|
Capybara.session_name = name
end
When /^I wait (\d+) seconds?$/ do |seconds|
sleep seconds.to_i
end
And that’s it. Cucumber and Capybara will remember the current state of each browser. It works well with the @javascript
tag for Pub/Sub but can be used for any kind of concurrent user interactions.
One More Thing…
The browser switching step above is simple enough but I found myself wanting a more inline step as well. So here you go:
When /^(?!I am in)(.*(?= in)) in (.*) browser$/ do |step, name|
When "I am in #{name} browser"
And step
end
The regular expression is little crazy but what it does is simple. It matches any step that ends in in (.\*) browser
and will run that step in the given browser. This lets us change the scenario above to:
Scenario: Push for chat
Given the following users exist:
| Name |
| Steve |
| Catie |
And I am logged in as "Steve" in Steve's browser
And I am logged in as "Catie" in Catie's browser
When I go to the new message page
And I fill in "Body" with "Hi, Steve!"
And I press "Send"
And I wait 2 seconds
Then I should see "Hi, Steve!"
And I should see "Hi, Steve!" in Steve's browser
It’s really a matter of personal preference, but I like both styles depending on the situation.
See It In Action!
We put together a simple chat app (using Pusher) that uses this method of testing simultaneous sessions in Cucumber. The code lives on GitHub and we have a live version up on Heroku. Check it out and let us know what you think.
Comments
I really like bbq when it comes to scenarios with multiple users/browsers interacting at the same time - https://github.com/drugpl/bbq . I wonder if anyone tried to use bbq with cucumber. I only know test::unit and rspec usages in the real world. [Disclaimer: I am one of the bbq maintainers]
A you sure that session are swiched? I tried but nothing happend?