Is this your first visit? You may want to subscribe to the feed.

Articles tagged with facebook

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.

Code: facebook Mar 05, 2009 ● updated Mar 05, 2009 11 comments

Force Absolute URLs

Need to force all URLs in a controller or action to be absolute URLs, but don’t want to use the *_url named routes or, even worse, :only_path => false everywhere?

Background

As we were putting the finishing touches on an awesome Facebook app today (yes I said “awesome” in the same sentence as “facebook app”…you’ll see), we needed to make it so that users can add the app as a tab in their profile. Facebook makes this very easy, but there’s an interesting quirk feature. From the developer’s wiki:

  • Absolute URLs on a tab take the user to your application’s canvas page.
  • Relative URLs are treated as if they are relative to your home canvas page and AJAX-loads in the tab.

We needed all of the URLs on the page to be absolute so that they would take the user out of the tab and into our application. So we were faced with two options:

  1. Change all of our named routes from *_path to *_url and use explicit paths instead of polymorphic urls (you know, that thing that lets you do form_for @model, or link_to h(@model.name), @model)
  2. Figure out some quick hack that forced Rails to generate absolute URLs on this one page and go on about our lives

The page reused a lot of components from all over the site, so we weren’t excited about option 1. And, like all good developers, we were just adverse to that much work.

So we started looking for a good fit for option 2. We needed to force :only_path to be false on any URL generation. There’s a way to specify default_url_options, but as the name implies, those are only defaults. Using the *_path named routes forces :only_path to true.

Solution

It turns out, Rails passes all URL generation through a method on your controller called #rewrite_options. So we just overrode that method to force :only_path to false on our one action. Here’s the code we used:

class ContentController < ApplicationController
  # …

  def profile
    # profile action
  end

private
  # Force absolute URLs on the profile tab.
  def rewrite_options(options)
    super(action_name == 'profile' ? options.merge(:only_path => false) : options)
  end
end

It’s slightly evil, but it worked beautifully.

Code: facebook Feb 21, 2009 ● updated Feb 21, 2009 1 comment

Testing views in RSpec with namespaced elements

We’ve been working on a Facebook app (yeah, I know, I’m sorry) and have had all kinds of fun challenges. We wanted to test FBML tags in the view, but the problem is that FBML uses namespaced elements.

It turns out, CSS selectors don’t work with namespaced elements. There is a CSS3 namespace module, but Rails’ #assert_select and RSpec’s #have_tag (built on #assert_select) don’t support them. We were going to have to turn to XPath, but #have_tag only supports CSS selectors.

But Hpricot supports XPath. A little searching revealed the rspec_hpricot_matchers plugin, which replaces have_tag with an Hpricot-backed version. The only problem is that the new version isn’t backwards compatible. So we forked it and renamed #have_tag to #match_element.

Usage

It’s pretty straight forward. Install the rspec_hpricot_matchers plugin, and include the module in the RSpec config in spec_helper.rb.

Spec::Runner.configure do |config|
  config.include RspecHpricotMatchers
end

Our view had something similar to:

<fb:multi-friend-input prefill_ids="<%= @friends.join(', ') %>" />

And in the view spec, we use #match_element with an XPath expression.

describe "things/edit.fbml.erb" do
  it "should prefill selected friends" do
    render "things/edit.fbml.erb"
    response.should match_element("//fb:multi-friend-input[@prefill_ids='333,444,555']")
  end
end
Code: facebook Dec 04, 2008 ● updated Dec 04, 2008 1 comment

Subscribe

Browse by Tag