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.
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.
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.
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.