I am in the process of creating an engine that will simplify adding single signon to my app using omniauth & devise. One of the requirements is testing this with Cucumber, and it took me a little while to figure this out, so I figured I would pass it on.
Add a test app on Facebook
The first thing you need to do is set up a test app on the Facebook developers site. This will allow you to use localhost as the callback url. Otherwise, FB API will not let you authenticate, b/c the FB App configuration URL will not match your app’s URL. You will probably want 3 different FB apps. One for dev, test, and prod using localhost:3000, locahost:3001 and yourprodurl.com.
In your test FB app settings, click the “Web Site” tab and make the Site URL = localhost:3001
Save your setttings.
Add mongrel to Gemfile
I added mongrel to my test environment instead of using webrick (b/c of issues with header size of google apps callback). I would recommend doing the same. Just add it to your gemfile under the dev and test groups. Here is my Gemfile (with a bunch of other testing gems included):
Make sure you run:
Change Capybara server settings
Add these lines to “features/support/env.rb”:
You need to specify the port so mongrel is forced to start on 3001. You also need to specify the app_host as localhost, because the default “127.0.0.1″ was causing problems with FB API (url encoding I think)
Use Selenium in your scenarios
Preface your cucumber scenarios with @selenium, so you can navigate through external sites like Facebook
Of course you need to set up your cucumber step, based on how you are authenticating against facebook. I don’t provide the implementation details here. Just know that cuc is hitting the facebook URL in the first step of this scenario.
Run cucumber scenarios
You should be good to go now. Facebook will use the correct callback URL and your server will be running on the correct port to handle it.





#1 by John on May 21, 2011 - 10:08 am
Quote
Hi!
Thank you for this article! It’s a pain to test facebook omniauth.. However when I changed the capybara server setting (in the features/support/env.rb) as you wrote, none of my tests pass, I would be pleased if you have any idea on this.
#2 by cowboycoded on May 21, 2011 - 10:43 am
Quote
What is the error when your tests fail?
#3 by John on May 21, 2011 - 12:14 pm
Quote
To be more precise, all my authentication steps I created don’t work anymore. Here is an example with error associated:
# authentication.step
Given(/^I am not authenticated$/) do
visit(‘/signout’)
end
# Error:
You have a nil object when you didn’t expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[] (NoMethodError)
./features/step_definitions/authentication_steps.rb:3:in `/^I am not authenticated$/’
features/forgot_password.feature:32:in `Given I am not authenticated’
————
#4 by John on May 22, 2011 - 7:36 am
Quote
At the end, I switch to thin server instead of mongrel, it solves the problem. Just one other thing, I would really love to have your opinion about testing Facebook OmniAuth like this: http://pivotallabs.com/users/mgehard/blog/articles/1595-testing-omniauth-based-login-via-cucumber (in case you tried it) I cannot make it works
… AGAIN MANY THANKS!!!
#5 by cowboycoded on May 22, 2011 - 12:36 pm
Quote
Sorry for the delayed response. Good to hear you got it working using Thin! I did not try the method in your link. When possible, I prefer testing it as it would happen in the real world, as opposed to mocking the external service. If the external provider changes their service and it breaks your app, then your tests will still pass since you are mocking it. Of course it depends on the scenario (I’m sure it makes sense for devise to test it this way), but since selenium allows you to run tests using the browser, I don’t see a reason to mock it if you are just doing integration tests against your app. I guess the downside to testing directly against the service is if that provider had an outage, or if you had no internet connection. Tradeoffs either way, so I would say pick the one you think is more appropriate for your use case.
#6 by luca on June 5, 2011 - 9:37 am
Quote
Hi,
nice way to test omniauth/device and I agree with “test for real” approach. Here anyway, I get this failure and can’t understand what’s wrong :
And I fill in “email” with “user@example.com” # features/step_definitions/web_steps.rb:60
cannot fill in, no text field, text area or password field with id, name, or label ‘email’ found (Capybara::ElementNotFound)
(eval):2:in `fill_in’
./features/step_definitions/web_steps.rb:61:in `/^(?:|I )fill in “([^"]*)” with “([^"]*)”$/’
features/facebook.feature:9:in `And I fill in “email” with “user@example.com”‘
My implementation is omniauth pure, without device. Any idea ?
Thanks in advance.
Luca
#7 by cowboycoded on June 5, 2011 - 4:45 pm
Quote
It appears that the test is not making it to the Facebook login page and as a result the “email” field is not found. Try this first:
Given I am on the “facebook” auth page #sends to facebook authorization url
Then show me the page
And I fill in “email” with “my@email.com”
Seeing the page should help you debug the problem. How are you sending the user to facebook? Can you post your step definition for the first line in this scenario?
#8 by luca on June 6, 2011 - 4:11 pm
Quote
No step def. other than default capybara web_steps.rb :
lsoave@ubuntu:~/rails/github/gitwatcher$ ls -l features/step_definitions
total 8
-rw-r–r– 1 lsoave lsoave 5705 2011-06-02 17:14 web_steps.rb
lsoave@ubuntu:~/rails/github/gitwatcher$
the first line in this scenario is :
Given I am on the “facebook” auth page # features/step_definitions/web_steps.rb:44
the line 44 of web_steps.rb is :
Given /^(?:|I )am on (.+)$/ do |page_name|
visit path_to(page_name)
end
the relative path ( features/support/paths.rb ) is :
when /the “facebook” auth page/
‘auth/facebook’
the full cucumber run is here : http://pastie.org/2029800 with features/facebook.feature modified as you suggested ( the browser try to pop up but crash immediately ).
#9 by luca on June 7, 2011 - 1:21 pm
Quote
Ok, I ‘adjusted’ with a better matcher in features/step_definitions/facebook_steps.rb :
Given /the “([^"]*)” auth page$/ do |auth_page|
visit path_to(auth_page)
end
… but the error “Component returned failure code: 0×804b000a” was due to MALFORMED_URI caused by typo in features/support/env.rb file :
Capybara.app_host = “localhost:3001″ suggested in the tutorial, cause MALFORMED_URI
Capybara.app_host = “http://localhost:3001/” it’s OK
Now the browser pop up, but it’s blank and suddenly disappear than I’m back failing the second step with a “cannot fill in, … (Capybara::ElementNotFound)”.
Do the tutorial miss a view, an email field in a model or something else ?
Any idea?
Thanks in advance Luca
#10 by cowboycoded on June 7, 2011 - 1:32 pm
Quote
When you run the server in development mode and test it manually, can you get to the facebook page by visiting auth/facebook in your browser? It still appears that your test is not reaching the facebook page.
Try printing out the path in your web step to make sure the facebook url is what you are expecting:
Given /the “([^"]*)” auth page$/ do |auth_page|puts path_to(auth_page)
end
#11 by luca on June 7, 2011 - 3:35 pm
Quote
… finally it works !
You also have to correct the last line in article’s Scenario:
And I press “Login” ==> became ==> And I press “Log In”
… or you’ll get a “no button with value or id or text ‘Login’ found” Capybara::ElementNotFound ( infact the original facebook button looks like that: )
Thanks to your troubleshooting indication, I was able to find out my wrog SECRET_KEY into config/initializers/omniauth.rb and fix it.
Thanks for your support! This was my first Cucumber test and I’m double happy
I really appreciate all the helpful information on the article as well.
Luca G. Soave
#12 by truenam on June 7, 2011 - 7:06 pm
Quote
Интересно)
Trackback: Gadget Review
Trackback: twitter programmer
#13 by one click cash loan status on October 18, 2012 - 3:06 pm
Quote
I am regular visitor, how are you everybody?
This article posted at this web site is actually fastidious.