Protip – Capybara-RSpec integration with Continuous Integration.

If you are dealing with UI test case automation wherein you see your test cases running in the launched browser window – example being using ‘Capybara’ with ‘Selenium web-driver’ or for that matter any web-driver , then this post can prove to be useful to you .

Each time you run such test case suite, a Selenium browser window pop’s up showing the actual activity on the browser itself. It can be very annoying especially when you are in middle of some important work & want your test case suite to be executed in parallel without getting disturbed. Browser window just won’t allow you to work unless it completes it’s execution & the situation becomes even more worse when you need to deal with a very large suite of test cases taking a longer period of time for its execution. If you have ever been stucked in such situation, there is a way out for you . “Headless” gem will help you get out of this problem.

Use of “Headless” gem can prove to be even more useful when you have CI server in place without the browser instance running on it & your test cases are getting executed with each build. This would just execute your test suite in the backend without the need to lauch the browser window at any time on the CI server.

Recently i ran into problem where my Capybara (Selenium) test cases  which were suppose to execute successfully were failing with the CI server setup. Looking into more details , i realized that the CI server where our build was executing did not had any UI drivers ( no display hardware setup ) installed on it & hence was unable to launch the necessary selenium browser window & hence the failure. So while searching the solution for same on the net , i came across the link “http://makandracards.com/makandra/1391-how-to-hide-your-selenium-browser-window-with-headless“. Solution of “Headless gem” mentioned here, helped me overcome the two-fold problems mentioned above – work parallely when your test cases are executing in background & ultimately resolved the test case failure problem under CI build. This original post has reference to “Capybara with Cucumber” setup. However the same can be applied to “Capybara with RSpec” with minor changes.

Setting up “Headless” gem in your Rails Application:

1. Install xvfb if it is not installed yet on your system.

sudo apt-get install xvfb

Briefly “xvfb” is virtual framebuffer X server which provides an X server that can run on machines with no display hardware and no physical input devices. It emulates a dumb framebuffer using virtual memory. If you are interested in knowing more details about “xvfb”, you can hunt on the web. For the purpose of this post, we can say that
“xvfb” is the basis for the “Headless” gem to be used.

2. Add the headless gem to your Gemfile.

group :test do
 ...
 ...
 gem "headless"
end

3. While using RSpec , include the following snippet under spec/spec_helper.rb

require 'headless'

headless = Headless.new
headless.start

at_exit do
 headless.destroy
end

This starts an xvfb process, registers a hook to destroy the process on exit when your test environment is loaded.

Also if you want to execute ‘headless’ mode against only the specifically tagged scenario’s , then you need to configure it as given below:

require 'headless'

headless = Headless.new

at_exit do
 headless.destroy
end

Before("@selenium,@js", "~@no-headless") do
 headless.start if Capybara.current_driver == :selenium
end

After("@selenium,@js", "~@no-headless") do
 headless.stop if Capybara.current_driver == :selenium
end

This would start and stop the headless mode if you are running a scenario that is tagged with @selenium or @js only. Other scenarios won’t be executed in the headless mode.

Note:
If you don’t want a specific scenario to hide the selenium browser window, you can tag it with @no-headless.

4. If using Cucumber , you need to include the exact snippet as given above for RSpec but in this case under the file “features/support/env.rb”.

Auto-waiting feature in Capybara-2

I am sure that most of us would be working on Capybara-2 & further releases. So while executing your test suite , you might have come across the situations where the same block of code or your test case succeeds most of the times but often fails in-between. This is mainly because of the variation in the load time of the element you are searching for on your web page. If the load time falls within the default configured wait time for the Capybara then your searched element can be found & ultimately the test succeeds otherwise it fails. Capybara-2 helps us to handle this uneven behavior of our test cases because of the inconsistent load time using the smart auto-waiting feature as illustrated below. It really has helped me a lot to come out of such situations & hence wanted to share one such example with you.

UseCase:
Consider that we have an element node “xyz” which has text “success” contained in it which we need to search on the web page. This element node “xyz” has expand/collapse facility & expanding/collapsing of this node is handled through AJAX call. So in real time when you click on element node “xyz” on the web page it takes some time to expand/open-up the node & display the text “success” contained in it. This means some amount of time is required to process the AJAX request. This time taken to expand the element node “xyz” & show its contents is nothing but “wait time”. This is where the auto-waiting feature of the Capybara-2 plays a significant role.

Incorrect Way

page.find("#xyz").text.should contain("success")

Correct Way

expect(page.find("#xyz")).to have_content("success")
# OR
expect(page).to have_selector("#xyz", :text => "success")

So if you consider the “Incorrect” statement above, here the “text” method used would return the regular string immediately with the element node “xyz”. It won’t do auto-waiting. Thus here lies the chance for your test case failure because the text “success” not being found in the expected time. Whereas if you consider the “Correct” statements above, here the methods “have_content” & “have_selector” they will do auto waiting for you. Thus any chance of failure of your test case is eliminated as it would wait for the AJAX call to complete. Also the later method makes code much more readable and maintainable.

6 thoughts on “Protip – Capybara-RSpec integration with Continuous Integration.

  1. Hey I know this is off topic but I was wondering if you knew of any
    widgets I could add to my blog that automatically tweet my newest
    twitter updates. I’ve been looking for a plug-in like
    this for quite some time and was hoping maybe you would have some experience with something like this.
    Please let me know if you run into anything. I truly enjoy reading your blog and
    I look forward to your new updates.

  2. Hi,
    Thanks for following this post. If i understood your requirement correctly – you want your latest tweet’s to be shown on our blog & refresh automatically. So you can achieve this by grabbing a snippet of code that twitter offers from your account & pasting/using it the source of your blog as follows –

    – Login to your twitter account
    – Goto “Settings & Help” > “Settings” option.
    – Select “Widgets” option from the left
    – Just create new widget with the default configuration options that you have on the page.

    Now on the RHS , you could see the preview of your tweets ( that would probably want to show on your blog ) & exactly below the PREVIEW , you could find a snippet of code/script generated for your account. You just need to simply paste (use) this snippet of code in your blog source where you want your tweets to be displayed.

    Hopefully these steps help you !!

  3. Hi,
    This is a good tip. But it is not clear how to skip headless for one scenario. I tried:

    it ‘searches for jobs and shares them’, js: true, headless: false do

    end

    The above is still run in headless mode. What am I missing?

    Thanks,

  4. Hey,
    That’s a good question. Actually i came across similar scenario in case of ‘Cucumber’ and it worked well simply by placing the tag ‘@no-headless’ at the top of necessary ‘scenario’ or ‘scenario-outline’.

    Similarly in case of RSpec, solution you have shown in example above seems fine BUT it doesn’t seem to work for me as well. Digging more into it….By the time, if you do come across any solution for it , please do share it here !

    1. this worked for me:

      config.before(:each, js: true) do |ex|
      headless.start unless ex.metadata[:noheadless]
      end

      config.after(:each, js: true) do |ex|
      headless.stop unless ex.metadata[:noheadless]
      end

      and in your feature specs:

      it ‘searches for posts and shares them’, js: true, noheadless: true do
      end

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.