opensoul.org

Testing Facebook with Cucumber

For those that haven’t heard: Cucumber is pretty much the greatest thing since sliced bread. It dramatically improved the quality and stability of our applications, and the outside-in approach that it encourages forces you to stay focused on what’s important.

When we started working on a Facebook application a few months ago, we couldn’t fathom not using Cucumber. So we had to figure out a way to test it. It took us a few months to evolve it to a point where we could extract it, but this week we pushed a change to Facebooker to make life a little easier. So grab the latest version of Facebooker and keep on reading…

First, in features/support/env.rb, replace the default Rails world with the one in Facebooker:

# require 'cucumber/rails/world'
require 'facebooker/rails/cucumber'

Given I am logged in as a Facebook user

Most of our Facebook application requires that a user be logged in. So most of our scenarios started with “Given I am logged in as a Facebook user”.

Scenario: Uploading a video
  Given I am logged in as a Facebook user
  When I upload a video
  Then I can see a video on my blog

And here is our implementation for that step:

Given "I am logged in as a Facebook user" do
  @current_user = User.create! :facebook_id => 1
  @current_user.facebook_user.friends = [
    Facebooker::User.new(:id => 2, :name => 'Bob'),
    Facebooker::User.new(:id => 3, :name => 'Sam')
  ]
  @integration_session.default_request_params.merge!(
    :fb_sig_user => @current_user.facebook_id,
    :fb_sig_friends => @current_user.facebook_user.friends.map(&:id).join(',')
  )
end

Our application has a User model with a facebook_id attribute and a #facebook_user method which returned an instance of Facebooker::User. Due to how the Facebook session is being mocked, it is important that we set our fake user’s id to 1 for now (I’ll try to figure out a way around this). We also manually add some friends for our application to use. Lastly, we merge in our user’s id and friend ids into the default request params so that any requests we make include those parameters.

Drop your…canvas

There were some places in our app where requests don’t go through the canvas. For example, we have a few multipart forms, which have to submit directly to your application. To mimic this, wrap webrat calls in #without_canvas:

When "I upload a video" do
  visit root_path

  without_canvas do
    fill_in 'Title', :with => 'A video'
    fill_in 'Description', :with => 'Caption for video'
    attach_file 'Video', "#{RAILS_ROOT}/features/support/sample.mpg", "video/mpeg"
    click_button 'Upload Video'
  end
  follow_redirect!
end

Note that if your action redirects to a URL with :canvas => true, webrat will see that as an “external” redirect and won’t follow it. Just call #follow_redirect! and it’ll go on it’s merry way.

Accessing the Facebook API

Instead of making requests to the Facebook API in your tests, Facebooker will try to read a canned response fixture from features/support/facebook/. It will give you a friendly error whenever this happens, so just follow the directions and you should be on your way.

Feedback & Patches

I’m sure there are things that don’t work right, so let me know if you run into any troubles. If you have any ideas for making the Cucumber support better, please share them here or on the Facebooker mailing list.

cucumber, facebook, rails, and testing March 05, 2009

13 Comments

  1. hookercookerman hookercookerman March 17, 2009

    nice writeup;

    It will give you a friendly error whenever this happens, so just follow the directions and you should be on your way.

    features/support/facebook/facebook.users.getInfo/5d62f6b393dabb357ec2e20daa926eda.xml
    (Non-hashed path is fields=status,political,pic_small,name,quotes,is_app_user,tv,profile_update_time,

    blar blar

    I have had friendly messages

    can u be slightly more friendly and enlighten me on how to created a canned response; on just assumes
    just grap xml from facebook wiki; but the whole filenaming of this fixture is probably one of lifes greatest mysteries;

    cheers

  2. Chris Chris May 19, 2009

    Great Post!

    I’m running cucumber 0.3.5 with facebooker 1.0.13. When i run cucumber features, i get the following error:

    You can only pass a proc to #World once, but it’s happening
    in 2 places:

    s/cucumber-0.3.5/lib/cucumber/rails/world.rb:84:in `World’
    vendor/plugins/facebooker/lib/facebooker/rails/cucumber/world.rb:42:in `World’

    Use Ruby modules instead to extend your worlds. See the Cucumber::StepMother#World RDoc
    or http://wiki.github.com/aslakhellesoy/cucumber/a-whole-new-world.

    (Cucumber::MultipleWorld)

    /usr/local/lib/ruby/gems/1.8/gems/cucumber-0.3.5/bin/../lib/cucumber/step_mother.rb:195:in `World’
    /Users/chrisye/Sites/real_mafia/vendor/plugins/facebooker/lib/facebooker/rails/cucumber/world.rb:42


    Anybody else getting this and has anyone found a way around it?

  3. Chris Chris May 19, 2009

    Commenting out the facebooker World obj seems to have worked!

  4. Michael Michael June 3, 2009

    I’m getting the same problem as Chris:

    You can only pass a proc to #World once, but it’s happening
    in 2 places:

    /1.8/gems/cucumber-0.3.9/lib/cucumber/rails/world.rb:97:in `World’
    vendor/plugins/facebooker/lib/facebooker/rails/cucumber/world.rb:42:in `World’

    Use Ruby modules instead to extend your worlds. See the Cucumber::StepMother#World RDoc
    or http://wiki.github.com/aslakhellesoy/cucumber/a-whole-new-world.

    (Cucumber::MultipleWorld)

    But I would assume commenting out the Facebooker World defeats the purpose of this code?


    Anyone figure this out?

  5. Bernie Bernie August 29, 2009

    Please forgive my general ignorance…I tried the steps exactly as you mentioned, but Cucumber doesn’t seem to understand the @integration_session variable. Should that be defined in some other file?
    I’ve tried Facebooker::Rails::IntegrationSession.new (which I’m pretty sure is wrong)
    and ActionController::IntegrationTest (which is definitely wrong).

    Any chance I’m missing something?

  6. Woody Peterson Woody Peterson October 15, 2009

    You have to have the directories valid, then it’ll give you a friendly message about the file.

  7. Tom Gallagher Tom Gallagher November 23, 2009

    @ Bernie

    I am having the same issue, did you get anywhere with this?

  8. Matt Matt January 3, 2010

    Hey, thanks for the article, while not exactly what I needed, it helped me understand and fix the problem.

    Matt

  9. Robin Robin January 30, 2010

    Can you explain how you mock the facebook_session? I had no method @user.facebook_user, but when just returning facebook_session.user in there, I get an error that the facebook_session is nil. How do you mock it?

    Thanks in advance.

  10. Elad Elad February 5, 2010

    Tried to use this example and failed.
    First i had to add
    `@integration_session = open_session` at the beginning of the step, but then when i tried to access #friends when settings #default_request_params, i got `undefined method `post’ for nil:NilClass (NoMethodError)`.

    This means that the user i am generating at the beginning of the step, doesn’t have a session (@current_user.facebook_user.session is nil).

    Any workaround?

  11. Millisami Millisami February 23, 2010

    For me to work, I had to put the following method in user.rb

    def facebook_user
    @facebook_user_cache ||= Facebooker::User.new(self.facebook_id)
    end

  12. Jonathan Spooner Jonathan Spooner May 3, 2010

    I was trying to add this to my authlogic cucumber example on github but I’m getting a
    " undefined method `set_facebook_session’ for nil:NilClass (NoMethodError)"

    I’m thinking the problem must be that something is not required in cucumber env.rb.

    Question:
    http://stackoverflow.com/questions/2760461/authlogic-facebook-connect-and-cucumber

    Source code:
    http://github.com/jspooner/authlogic_cucumber_rspec_example

  13. Brandon Brandon May 3, 2010

    Jonathan: I wouldn’t be surprised if the cucumber support in facebooker is very out of date. I haven’t used it for nearly a year, and I don’t know that anyone else was maintaining it.

Post a Comment

Comments use textile. Anonymous comments will be deleted.

My name is Brandon Keepers. I like to build things, usually in Ruby or JavaScript. I work at GitHub and live in Holland, MI.

Popular Posts