OAuth providers like LinkedIn often pop-up in a new browser window rather than in Javascript so that the user entering their credentials can see the location bar to be sure they are not being phished by the website requesting their credentials. This is great for security, but not so great for Cucumber testing.
features/signup.feature
Scenario: Sign Up with LinkedIn
When I go to the home page
And I follow "Sign Up"
And I grant LinkedIn access
Then I should be on the new user page
My application has a hyperlink that opens the OAuth login on the OAuth provider's website in a new window. Let's presume the simple matter of wiring this up is already coded in my view.
Testing this with Cucumber requires telling the Selenium web driver to interact with the new popup window. We can do this using page.driver.browser.window_handles to find the newest window handle and scoping out actions to that window.
features/support/signup_steps.rb
When /^I grant LinkedIn access$/ do
begin
main, popup = page.driver.browser.window_handles
within_window(popup) do
fill_in("Email", :with => "newlee@pivotallabs.com")
fill_in("Password", :with => "password")
click_on("Ok, I'll Allow It")
end
rescue
end
end
And that's it!
Keep in mind that if you use this test as-is, you will be hitting LinkedIn on the real Internet. This is great if you want a test that will always verify the real API, but not so good for CI, since it is Internet connection-dependent and slow. Consider using something like VCR or Artifice to stub out your service calls.
Visiting Olin
Today, Josh Knowles, Grant Hutchins, and I visited Franklin W. Olin College of Engineering in Needham, MA to talk to Prof. Mark L. Chang's amazing new dotcom course. We talked about agile development, and more specifically how Pivotal does agile and why. We went through an example of test-driven development for a simple Rails app, and had a miniature inception for a fictitious product.
Some students asked for some resources, particularly for documentation, so I put together a collection of resources for anyone looking to pick up agile, TDD and Ruby on Rails. This is intentionally not an exhaustive list. I wanted to include the bare minimum for getting started on each topic as a jumping off point and include further references at the end.
The project that I'm working on is using Screw.Unit for Javascript testing. We recently ran into a case where we found ourselves copying and pasting some code. We wanted to DRY up our specs and found a neat way to do it that I figured I'd share with everyone. Here's a really simple example to demonstrate how we did it.
Given a cat model that keeps track of the number of lives the cat has left:
function Cat() {
var lives = 9;
this.die = function(num) {
lives = lives - 1
};
this.lives = function(){
return lives;
};
this.isDead = function() {
return lives <= 0
};
}
Lets make up a spec that checks that isDead works for some values of lives:
Screw.Unit(function() {
describe('Cat', function() {
var cat;
describe('isDead', function(){
var shouldNotBeDeadBehavior = function(num){
describe("when the cat has " + num + " lives left", function(){
it("it should not be dead", function(){
cat = new Cat({lives: num});
expect(cat.isDead()).to(be_false);
});
});
}
for (i=3;i>0;i--){
shouldNotBeDeadBehavior.call(Screw.Specification, i);
}
describe("when the cat has 0 lives left", function(){
it("it should be dead", function(){
cat = new Cat({lives: 0});
expect(cat.isDead()).to(be_true);
});
});
});
});
});
The neat part in here is the line:
shouldNotBeDeadBehavior.call(Screw.Specification, i);
If you're not familiar with it, the call function in javascript allows you to define what "this" is for that function call. By calling our shared behavior with Screw.Specification, we're saying that we want to execute this function within the context of the Screw.Unit Specifications. This lets us execute our specs as though they were written in various places. The test results from this spec look like this

This is one way to DRY up some of your Screw.Unit specs. If you find yourself copying and pasting code, consider refactoring the spec out into a shared behavior instead.
Have other good ways to clean up Srew.Unit specs? Share them in the commments!
