Making the switch requires Chrome, of course, and a couple of dependencies to make sure everything's neatly integrated with Capybara.
This part's fairly straightforward, it shouldn't be much of hassle for you.
First things first, you need to install Chrome's latest stable version
In Linux, you can do so as such:
Next up, you'll need two more tools:
The gem webdrivers
helps with the installation of ChromeDriver, automatically downloading, installing and keeping the driver up-to-date.
Then, you should add both to the project in your Gemfile, as shown below:
Don't forget to bundle install
afterwards.
Now, you just need to register the drivers, and configure them in spec_helper.rb
:
This sets the default driver to :headless_chrome
. If you'd like to watch the tests execute, just change it to :chrome
in the last two lines.
You may also notice the enable-features tag in chrome's options, this is a temporary fix because of an issue in Chrome 74 in which cookies get randomly cleared during execution, which might cause Chrome to freeze.
According to Chromium’s bug tracker, this will be fixed in version v75.
If you're running the project in Docker, you may also need to add 'no-sandbox' to Chrome's options:
Now that that's taken care of, you can go ahead and remove capybara-webkit
from the Gemfile, as well as any import or configuration you might have left (look for Capybara::Webkit
).
For some projects, the tests may already be running smoothly after these steps, but for others that may not be the case. With a new browser and tools running the tests, new features and new problems also come up.
Capybara-webkit had a couple of useful but non-standard methods, and Selenium does not support all the methods Capybara has to offer. So this creates quite a gap, and any test that was using unsupported methods has to be patched.
Nevertheless, an easy workaround, if you’re triggering a click, would be to send the return keystroke to the element:
Or to click the element through javascript:
If you're dealing with another sort of event, you can use jQuery like so:
And then to read the logs, you can simply:
You can read more about Chrome's capabilities and options here.
page.driver.header
, page.response_headers
and page.status_code
aren't available.
Fixing this last point is somewhat of a challenge, but GitLab's solution is a great workaround. When faced with the same problem while porting their browser from PhantomJS to Chrome, they implemented a Middleware to intercept the requests' headers (more about it here).
To implement this solution, I simply included these files
lib/testing
:
spec/support/helpers
:
The namespaces have to be changed to match your project, and the 'concurrent-ruby' gem imported, as it is required in the middleware:
Remember to also import the files in spec_helper.rb
:
And with all that setup, all you have to do to get the header's details is the following:
Now that everything is up and running, let me share a few more tips to take the most of Headless Chrome & ChromeDriver and avoid some common issues.
Capybara clicks on elements in the following way:
If the page is, for example, scrolling when the element is meant to be clicked, the coordinates might get outdated between step 2 and 3, meaning that the click will fall in the wrong place.
One possible solution for this problem is to wait for the animations to end, in this case I waited for the jQuery animation scrolling the body to stop:
Another option would be to disable jQuery animations in testing altogether, like this:
It's worth noting that disabling the animations can also improve the tests' performance.
If this fix doesn't work for you, and you really want to cancel all animations, check out this great article put together by the folks at Doctolib.
Capybara only clicks on elements if they are visible, so if you have a navbar or a popup obscuring an element, you might get an error like this:
Element is not clickable at point (100, 200). Another element would receive the click: ... (Selenium::WebDriver::Error::UnknownError)
To deal with this, you can close all popups on the page, and scroll down to the element before clicking it.
A simple method, implementing this idea, would be:
Chrome's headless mode and ChromeDriver that comes with it have been strongly adopted for testing and automation, especially since QtWebkit was deprecated, and, with it, projects that were based on it, such as PhantomJS and capybara-webkit.
Even the maintainer of PhantomJS, the once popular headless browser has deprecated his project in favor of ChromeDriver. And thoughtbot, the creators of capybara-webkit, are starting to play around with ChromeDriver as well.
While capybara-webkit did the job for quite some time, the change to a more modern alternative (Chrome's headless mode) will make tests more reliable and stable. All of this with the additional advantage of using the same browser engine as most users, which makes the tests actions much more similar to what a real-life user interaction would look like.
Happy testing folks!
Found this article useful? You might like these ones too!
Enthusiast of all things Front-End. In a committed love/hate relationship with CSS. Most often seen scraping data for side-projects he'll never finish.
People who read this post, also found these interesting: