Wilhelm Chung
2008-Mar-11  19:03 UTC
[Facebooker-talk] Facebooker-talk Digest, Vol 5, Issue 12
Hi all,
I wanted to test requests from internal facebook apps, so I''ve been
mimicking FBML requests from facebook in my tests using the following:
  def test_can_facebook_internal_app_login
    fb_login_as :facebooker
    num_of_members = Member.count
    facebook_request :get, :home
    assert_response :success
    assert_equal num_of_members, Member.count
    assert_session_user_data_exists
  end
The code is fairly simple:
module Facebooker
  module Rails
    module TestHelpers
      # user facebook id for facebook_request
      def set_user_facebook_id(fb_id)
        @fb_id = fb_id
      end
      # makes a request as if it was from facebook.  Need to
set_user_facebook_id() first
      # so it knows whom to send the request as.
      def facebook_request(http_verb, action, params = { })
        fb_params = { "fb_sig_time" => Time.now.to_f,
          "fb_sig_locale" => "en_US",
          "fb_sig_session_key" =>
"d82ebe8648254d4cef7d993a-1953401",
          "fb_sig_position_fix" => "1",
          "fb_sig_in_canvas" => "1",
          "fb_sig_request_method" => http_verb.to_s.upcase,
          "fb_sig_expires" => "0",
          "fb_sig_added" => "1",
          "fb_sig_api_key" => Facebooker::Session.api_key,
          "fb_sig_profile_update_time" => "1203267404",
          "fb_sig_user" => @fb_id }
        fb_params.merge!("fb_sig" => signature_for(fb_params))
        @request.accept = "text/fbml"
        send(http_verb, action, params.merge(fb_params))
        @request.accept = "text/html"
      end
      private
      # TODO this is copied from session.rb  MUST REFACTOR
      def signature_for(params)
        facebook_sig_params = params.inject({}) do |collection, pair|
          collection[pair.first.sub(/^fb_sig_/, '''')] =
pair.last if
pair.first[0,7] == ''fb_sig_''
          collection
        end
        raw_string = facebook_sig_params.map{ |*args|
args.join(''='') }.sort.join
        actual_sig = Digest::MD5.hexdigest([raw_string,
Facebooker::Session.secret_key].join)
        Digest::MD5.hexdigest([raw_string, Facebooker::Session.secret_key].join)
      end
    end
  end
end
I had wanted to submit the code as a patch, but, there are two or
three glaring flaws with the code:
1) signature_for is duplicated here, because it''s a private/protected
method in Facebooker::Session.  Would it be a bad idea to call
send(:singature_for) to call the protected method?  Or is there
another way around it?
2) One has to call set_user_facebook_id in the setup of your tests in
order for facebook_request to work.
3) fb_sig_session_key expires over time, and I have to get another one
from a real facebook request.  This is tedious.  Is there a way to
generate a session key, or request a new one from facebook while
you''re in the unit tests?
I was wondering if anyone had good opinions or solutions to this, so
that they can be generic enough and clean enough for others to use.
Thanks.
