Posts Tagged cucumber

Testing Facebook authentication with Rails 3 Cucumber, Capybara, Selenium

I am in the process of creating an engine that will simplify adding single signon to my app using omniauth & devise. One of the requirements is testing this with Cucumber, and it took me a little while to figure this out, so I figured I would pass it on.

Add a test app on Facebook

The first thing you need to do is set up a test app on the Facebook developers site. This will allow you to use localhost as the callback url. Otherwise, FB API will not let you authenticate, b/c the FB App configuration URL will not match your app’s URL. You will probably want 3 different FB apps. One for dev, test, and prod using localhost:3000, locahost:3001 and yourprodurl.com.

In your test FB app settings, click the “Web Site” tab and make the Site URL = localhost:3001

Save your setttings.

Add mongrel to Gemfile

I added mongrel to my test environment instead of using webrick (b/c of issues with header size of google apps callback). I would recommend doing the same. Just add it to your gemfile under the dev and test groups. Here is my Gemfile (with a bunch of other testing gems included):

Make sure you run:

cowboycoded$  bundle install

Change Capybara server settings

Add these lines to “features/support/env.rb”:

You need to specify the port so mongrel is forced to start on 3001. You also need to specify the app_host as localhost, because the default “127.0.0.1″ was causing problems with FB API (url encoding I think)

Use Selenium in your scenarios

Preface your cucumber scenarios with @selenium, so you can navigate through external sites like Facebook

Of course you need to set up your cucumber step, based on how you are authenticating against facebook. I don’t provide the implementation details here. Just know that cuc is hitting the facebook URL in the first step of this scenario.

Run cucumber scenarios

cowboycoded$  bundle exec cucumber features/

You should be good to go now. Facebook will use the correct callback URL and your server will be running on the correct port to handle it.

Tags: , , ,

Better web steps for Cucumber with Capybara

I just finished reading You’re Cuking It Wrong by Jonas Nicklas (the Capybara guy). This blog post makes total sense, and led me to write my own steps for Cucumber which are more readable for the non-technical. I have been using CSS and XPath selectors in some of my steps and I have noticed the ugliness along the way. I still think its useful to include things related to CSS in cuke scenarios, though. For example, you may want to describe what is shown on the page and break it up into sections. Let say you have a client that wants some text that says “If you need help, then RTFM” in the help section of the home page . I would write something like this before:

  Given I am on the home page
  Then I should see "If you need help, then RTFM" within "#help"

This could be converted to:

  Given I am on the home page
  Then I should see "If you need help, then RTFM" in the "Help" section

This gets rid of the ugly css stuff and makes it actually read like an english sentence. This also fits nicely with the new section tag in HTML5. This sentence makes sense to me and the people that I work with, but maybe not so much to you and your stakeholders. If you think a different sentence would be easier to read, then by all means write it that way. The whole point of this is to make the scenarios easy to read for the business owners as well as the developer, and with the flexibility provided by cucumber, you can make it read the way you want it to. The accompanying web steps for my sentence would look like this:

Then /^I should see "([^"]*)"(?: in the "([^"]*)" section)?$/ do |text,section|
  with_scope(section,:css_id) do
    page.should have_content(text)
  end
end

In order to make the sentence more readable, I made the section name accept capitalized words with spaces. This will not match the CSS IDs or classes, so I had to convert the words prior to checking with_scope. Since I will be using this on more than one step definition, I figured I might as well monkey patch the with_scope method to accept my format. That way, I can just pass the css selector type I am looking for (class or ID) and it will convert the capitalized/spaced words into a css class. I also monkey patched String and added a ccserize method which converts “My Section” into “my-section”. I prefer to use dashes to separate words when writing CSS classes or IDs. I also like this approach, because it forces you to make your css IDs descriptive based on what the customer wants.

class String
  def csserize
    self.downcase.gsub(" ","-")
  end
end

module WithinHelpers
  def with_scope(locator,css_type=nil)
    locator = convert_locator_to_css(locator,css_type) if locator and css_type
    locator ? within(locator) { yield } : yield
  end

  def convert_locator_to_css(locator,css_type)
    locator = locator.csserize
    return locator if locator =~ /^[.#]/
    css_type==:css_class ? ".#{locator}" : "##{locator}"
  end
end

The code above patches the with_scope method, so that it can convert to my css class format if the “css_type” parameter is present. Basically this just converts to lowercase, replaces spaces with dashes and appends a hash mark or a period depending on if it is a class or ID selector. Now that I am looking at it closer, I should probably change it so that it converts and searches for ID and class without me even specifying… so if it does not find anything initially, it converts with csserize, then looks for a class, then looks for and ID if it does not find a class.

There are countless possibilities when writing your own web step DSL. I think it is important to take some time to sit down and figure out the language that is most appropriate for you and the your customers, before you write any more scenarios. Take a look at what you have written in the past and contemplate whether you can write it in a simpler, easier to understand format. If you think anyone in your business (tech or non-tech) would not understand a particular sentence, then it needs to be changed. The beauty of Cucumber is allowing anyone to write requirements using a language that all stakeholders can understand.

Here are a few more custom web steps I wrote, so you can see more examples:

# Then I should see a page heading named "Widgets" in the "Main" section
Then /^I should see a page heading named "([^"]*)"(?: in the "([^"]*)" section)?$/ do |text, section|
  with_scope(section,:css_id) do
    page.should have_selector("h1",:text=>text)
  end
end

# Then I should see a link named "Buy this widget" in the "Product Details" section
Then /^I should see a link named "([^"]*)"(?: in the "([^"]*)" section)?$/ do |text, selector|
  with_scope(selector,:css_id) do
    page.should have_link(text)
  end
end

I would love to see more examples on the internet for custom web steps (especially using Capybara). I had a hard time finding anything when Googling for some of this stuff. I am planning on building a web app some time in the future where people can share their web steps. I think it would be very useful to see what others are doing, so you don’t have to reinvent the wheel. If you have any custom steps that you would like to share, please comment with a link!

Tags: , ,