Motivation
Today I migrated a medium size test suite from capybara-webkit to Poltergeist with PhantomJS. I had two main motivations for switching:
- PhantomJS is more sensitive to avoiding false positives. For example, in the past, one could click on non-visible DOM elements with capybara-webkit. While this may not currently be true with the latest Capybara, I’ve had good luck with PhantomJS in the past.
- Speed. When I last checked, PhantomJS was faster. Speed is critical for slow feature tests.
Here’s one reason that Poltergeist is more accurate and sensitive to failure:
When Poltergeist clicks on an element, rather than generating a DOM click event, it actually generates a “proper” click. This is much closer to what happens when a real user clicks on the page - but it means that Poltergeist must scroll the page to where the element is, and work out the correct co-ordinates to click. If the element is covered up by another element, the click will fail (this is a good thing - because your user won’t be able to click a covered up element either).
Tips for Migrating
Upgrade Gems First
At first, I lost time due to timing issues where I was clicking on elements of a hidden dialog that was not finished showing. Capybara-webkit was not bothered by the fact that the dialog was actually hidden and being loaded. PhantomJS bombed out. However, after I worked around the issue, I realized that my gems were outdated. Since you’re going to be fixing a bunch of tests anyway, it makes sense to get on the latest versions of the testing gems. The gems you want to upgrade are: rspec, rspec-rails, Capybara, and poltergeist.
Visible Option
After upgrading the gems, my workarounds were no longer necessary. However, the change from Capybara 2.0 to 2.1 had a big change in the way that it handles finding dom elements that are not visible. Previously, Capybara would not care if the dom element was hidden. For my tests, this resulted in breaking any tests that queried any non-visible DOM elements, such as scripts, meta tags, and links.
The key thing to be aware of is that you might get this obscure error message,
and the fix is to add the visible: false
optional parameter so that Capybara
is not filtering by visible: true
. The visible
parameter is available to
most finder methods in Capybara.
The obscure error you might see is something like this:
#=> Capybara::ExpectationNotMet Exception: expected to find xpath "//title" with text "Title Text." but there were no matches. Also found "", which matched the selector but not all filters.
The reason is the title element is not visible, and “visible” is the “not all filters” part of the error message.
Debugging Capybara Tests
The main reasons that previously passing feature tests will fail when migrating to Poltergeist is due to timing and visibility. The two main techniques for debugging Capybara tests are:
- Using screen shots (
render_page
below) - Using HTML dumps (=page! below)
Keep in mind that these methods will not wait for elements to load. Thus, you
should either have a Capybara statement that will wait for some DOM element to
load or you might want to put in a sleep 10
to sleep for 10 seconds before
capturing the screen shot or dumping the HTML.
If you use the helper methods specified below, and you should be able to work through why Poltergeist is not doing what you think it should be doing. So far, I haven’t yet run into a case where I have not found out that it’s been my fault rather than a bug in Poltergeist that’s caused a failure due to the migration. In many cases, you’ll be somewhat pleasantly surprised that you’ll be fixing a false positive.
Capybara’s Wait Strategy
Be sure to carefully read the Capybara documentation, especially the part
titled “Asynchronous JavaScript”. That section explains how Capybara cleverly
will wait until the page or ajax call finished so that the element expected
appears. There’s a configurable timeout (Capybara.default_wait_time
) for
changing the default wait time before a test bombs out.
Xpath Tip
Be sure to understand the difference between //something
and .//something
.
The later can be used inside a within
block. The former will find the tag
anywhere on the page, even when used inside of a within
block!
Setup and Utility Debugging Methods
Here’s the setup and a couple utility methods that I use. Put these in a file in your helpers directory, such spec/helpers/capybara.rb.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
This is a companion discussion topic for the original entry at http://www.railsonmaui.com//blog/2013/08/06/migrating-from-capybara-webkit-to-poltergeist-phantomjs/