Alex Pooley's Blog

Hello there, my name is Alex Pooley and I'm a freelance web developer residing in Perth, Western Australia. My passion is in the development of web sites that solve everyday problems. Here's a gallery of some of my notable work. If you need a web site designer or developer, contact me with further details. Lastly, you can read more about me.

Ruby Browser Hooks & Facebook Integration Testing

May 18th, 2008

Why don't you subscribe to my blog while you're here? I'm a freelance web developer and I blog about Ruby, Rails, and business online.

Go ahead and subscribe to my RSS feed. Thanks for visiting!

Recently I had to write some integration tests to ensure that my Facebook application was communicating with Facebook correctly. I started out trying to use plain old Net::HTTP which was painful because Facebook appears to actively block programmatic access through their login page. Just as I was about to give up I discovered a suite of libraries that allow you to access your browser from Ruby! The library is fantastic as I can very simply control the forms and content in my browser, straight from my Ruby code. Nice!

The library is called Watir. Watir is a tool to hook in Ruby with IE, but there are ports for Safari and Firefox. I ended up going with the Safari port as the Firefox port looked a bit tricky to install.

Now, for the pièce de résistance …

require File.dirname(__FILE__) + '/../spec_helper'
require 'rubygems'
require 'safariwatir'

describe UserController do
  FB_EMAIL = 'xxx@xxxxx.com'
  FB_PASS = 'xxxxx'

  FB_URL = 'http://www.facebook.com'
  CALLBACK_URL = 'http://dev.xxxxxxxxx.com'
  FB_APP_URL = 'http://apps.facebook.com/xxxxx/'
  FB_LOGOUT_URL = 'http://www.facebook.com/logout.php'

  LOGOUT_REGEX = /http:\/\/www.facebook.com\/logout.php\?.+/

  it "should use UserController" do
    controller.should be_an_instance_of(UserController)
  end

  describe "POST 'index'" do
    before(:each) do
      @browser = Watir::Safari.new
      @browser.set_fast_speed
      @browser.goto(FB_APP_URL)
      @browser.link(:url, LOGOUT_REGEX).click rescue nil
    end

    it "should find authentication prompt" do
      @browser.goto(FB_APP_URL)
      @browser.form(:id, 'loginform').exist?.should_not == nil
      expected = 'Login to Facebook to enjoy the full functionality of'
      @browser.contains_text(expected).should > 0
    end

    it "should authenticate" do
      authenticate
      expected = /Login to the .* application?/
      @browser.contains_text(expected).should != nil
    end

    it "should log in to the application" do
      authenticate
      @browser.form(:index, 1).submit
    end

  end

  private

  def authenticate
    @browser.goto(FB_APP_URL)
    @browser.text_field(:id, 'email').set(FB_EMAIL)
    @browser.password(:name, 'pass').set(FB_PASS)
    @browser.form(:index, 1).submit
  end

end

The code above is a work in progress, but it is still fully functional rspec code. Feel free to use it.

Just a note if you do end up using the Safari Watir port. I had to make a change to the core libraries as there seemed to be a race condition. If you are affected, you will notice an exception thrown part way through entering the data in a form. My quick fix/hack is to extend the sleep time from 1 to something larger. I had no problems after increasing the sleep time to 4.

# safariwatir/scripter.rb
def page_load
	yield
	#sleep 1
	sleep 4
	....
end

Leave a Reply

buy mp3 music uk vpn