Connect/Automating Tests

From Facebook Developer Wiki

Jump to: navigation, search

Contents

Automating Functional Tests of Your Connect Implementation

In order to keep Facebook Connect fast and stable, and to help you ensure that your implementations are working and bug free, we created a library that would help you easily create automated tests for your own site.

Getting Started

First, you'll need to install Watir. Please be sure to install the Firefox plugin, as the library and this demo assume you're using Firefox for your testing.

Download FBWatir and the StreamdiffTest example.

Before diving into the code, let's just try running the tests on the command line to see them pass and confirm that everything is set up correctly. Go to the terminal and cd into the directory where you downloaded fbwatir.rb, streamdiff.rb, and so forth. Run: 

$> ruby fbtestrunner.rb streamdiff


fbtestrunner.rb utilizes a Ruby Unit TestRunner.

Every parameter handed to fbtestrunner.rb should be the name of a .rb file in the directory, which represents a site for testing.  So in this case we have streamdiff.rb.  Each of these site-test files should require 'fbwatir.rb' and 'test/unit' at the top, as we see in streamdiff.rb:

    require 'fbwatir.rb'     require 'test/unit'


The site-test file (streamdiff.rb in our example) should then define a class that extends Test::Unit::TestCase, which should have the same name as the file, only capitalized, and appended with "Test", as we see inside streamdiff.rb:

    class StreamdiffTest < Test::Unit::TestCase


The next few lines are for initialization, identifying a specific Connect test user and his/her credentials which we can utilize for our tests:

  include FBWatir   Name = "John Doe"   User = "john@doe.com"   Pass = "johndoe"   def setup     init(User, Pass)   end


The method setup always gets called by the UnitTestRunner at the beginning of each test run.  So this is where you would add any additional initialization code needed for your test.  init() is a method in the FBWatir module that allows us to initialize the Connect credentials of the account we'll be using in our tests.

After calling setup, the Ruby UnitTestRunner will run every method in the defined class which begins with "test".  Then, in those test methods, we'll add our assertions..

Methods for Interacting with Facebook Connect

Once init has been called, the FBWatir module provides four methods for easily interacting with Facebook Connect:

  1. disconnectFromFacebook(appId) : This deauthorizes our application, removes all extended permissions, and logs us out of Facebook.
  2. loginAndGoToFacebook : This logs us into Facebook and then returns only when fully logged in and loaded a logged in Facebook.com/home.php
  3. loginToConnect(urlRegex) : This fills out the credentials in the Facebook Connect iframe/popup, and also clicks all the necessary buttons to allow all extended permissions requested.
    • You would call this once you had navigated to your website and clicked the Facebook Connect button -- which you'll see in Streamdiff.
    • The URLRegex should be a simple /regex/ that matches the URL of your site, so that Watir can reattach to it once it's done interacting with the Connect login popup.
  4. goFB : Go to Facebook and don't return until either the home.php or login.php page is fully loaded.

Before looking at the complex "test" methods in our StreamdiffTest class, let's go to the bottom of the file and look at some of the utility methods we've defined.  The structure utilized around these generic methods should be reusable for most Connect implementations.

You're going to want an easy to way to simply visit your website and confirm that the page is fully loaded before proceeding.  Usually when your site loads it will render either some indicator that you need to log in (a "Log In" link, for example), or it will render some alternative indicator showing that you're logged-in already -- perhaps it will welcome you by your full name in a <div> near the top.  We want to define a function for each of these two DOM objects, and then we'll have a go method that can wait for the existence of one of these two DOM objects in order to be sure the page has loaded. Here's how this looks in Streamdiff:

  # This function just takes us to streamdiff.com, and then ensures we're fully loaded   def go     Browser.goto("http://www.streamdiff.com")     wait_until { connect_button.exists? or logged_in_indicator.exists? }  # Here's how we ensure we're fully loaded   end   # Here's the connect button that appears if we're not connected yet   def connect_button     Browser.button(:class, "connect")   end   # This is the dom element that appears if we're logged into streamdiff already   def logged_in_indicator      Browser.text_field(:id, "message")   end


Now we're going to want some utility functions to connect/disconnect our test user from our Connect site.  So let's implement connect and disconnect functions.

  def disconnect     go # Go to our website     Browser.maybe.link(:class, "logout").click # Click the logout link if it exists (.maybe means "if it exists...")     disconnectFromFacebook(96228874643) # Deauthorize our app in Facebook entirely     go # Go back to our website so that when all done, we're on our website, logged out...   end   def connect     go # Go to our website     if (connect_button.exists?)  # Remember we defined connect_button ourselves...       connect_button.click # So if it exists, click it       loginToConnect(/streamdiff/) # Now login to connect, and bind to our url when done...        connect # Double check that it worked by re-calling ourselves...     end   end


Adding Content to Streamdiff

There are three basic actions we can take on Streamdiff. We can:

  • Post to the stream
  • Comment on a post
  • Like a post

So let's create a utility method for these three actions. Let's call them postToStream(), likePost(message), and commentOnPost(message).

  def likePost(message)  # Message is the text of the message in the stream we want to "like"     connect # Ensure we're connected     # Wait for our message to appear in the stream... (.await means "wait till it exists...")     Browser.await.div(:text, /#{message}/)     # Click the "Like" link on this post...     Browser.li(:class => /post/,                :text => /#{message}/).link(                :class, /action-like/).click   end   def commentOnPost(message)  # Message is the text of the message in the stream we want to comment on     connect # Ensure we're connected     # Create a unique comment by mashing it with the unix time stamp     comment = "Commenting #{Time.now.tv_sec}"     #  Set the text field to our new comment text     Browser.await.li(:class => /post/,                      :text => /#{message}/).form(                      :class, /post-comment/).text_field(                      :name, "text").fb_set(comment)     # Click the "comment" link     Browser.li(:class => /post/, :text => /#{message}/).form(                :class, /post-comment/).button(                :class, /button/).click     comment  # Return our new comment in case the caller cares   end   def postToStream # Posts a new random message to the stream     connect # Ensure we're connected     # Create a unique message by mashing it with the unix time stamp     message = "Posting #{Time.now.tv_sec}"      # Set the text of our composer to our new post message     Browser.await.text_field(:id, "message").fb_set(message)     # Click the "Share" link     Browser.button(:value, "share").click     message  # Return our new stream message in case the caller cares   end


Creating Simple Tests

Now, let's make some tests!  First let's do simple tests that assert our user can connect/disconnect successfully:

  def test_connect     connect     # If we're connected, then there'll definitely be a Logout Link     assert_exists(Browser.link(:class, "logout"),       "Logout Link")     # StreamDiff welcomes me by name if I'm logged in, so that should be in the text     assert(Browser.text.include?(Name),       "Knows My Name")   end   def test_disconnect     disconnect     # If I'm disconnected, then there should be a connect button     assert_exists(connect_button,       "Connect Button")     # The site should not my name, if I'm logged out...     assert((not Browser.text.include?(Name)),       "Doesn't Know My Name")   end


Testing Interactions with the Stream

To test our interaction with the Stream, let's publish a new post to the Stream, then add a comment and like the post we just created.  At each step along the way, we'll visit Facebook.com to make sure the post gets updated in the Stream, and then we'll re-visit our own website to make sure it still shows up there, too.

First, let's define a function that will create the post and assert that it's successful.

  def _test_posting     message = postToStream     # Go to facebook and assert our new posted message exists there     loginAndGoToFacebook     assert_exists(Browser.h3(:text, /#{message}/),       "Stream Post In Facebook")     # Come back to streamdiff and assert our message still exists there     connect     Browser.await.div(:text, /#{message}/)     assert_exists(Browser.div(:text, /#{message}/),       "Stream Post In StreamDiff")     message # Return our message for the caller   end


Now let's define a function that will "Like" a given post in the stream.  Note that we're naming these with "_test" instead of "test" because we don't want our UnitTestRunner to run them directly.  Rather we'll call them from within our "Comment" test. Here's the "Like" test:

  def _test_liking(message)     likePost(message)     # Go to Facebook and assert our "Like" exists in the stream     loginAndGoToFacebook     assert_exists(Browser.div(:id => /div_story_/,                               :text => /#{message}/).div(                               :text, /You like this/),       "'You Like This' for Liked Story on Facebook")     # Come back to Streamdiff and assert our "Like" still exists     connect     assert_nonexists(Browser.li(:class => /post/,                                 :text => /#{message}/).link(                                 :class, /action-like/),       "Like Button for Liked Story on StreamDiff")   end


Finally, let's define our Comment test method, which incorporates the Like and Post tests:

  def test_commenting     message = _test_posting  # Test creating a new post     comment = commentOnPost(message)  # Comment on the new post     # Go to Facebook and assert our Comment exists in the stream     loginAndGoToFacebook     assert_exists(Browser.div(:text => /#{comment}/),       "Comment In Facebook")     # Come back to Streamdiff and assert our comment still exists     connect     Browser.await.div(:text, /#{comment}/)     assert_exists(Browser.div(:text, /#{comment}/),       "Comment In StreamDiff")     # Test liking our new post     _test_liking(message)   end


There you have it!  Let us know what you think in the Developer Forum.  We hope this helps!

reference