Share post

Write Bulletproof Multi-Browser Test Suites With CrossBrowserTesting

Header image for the CrossBrowserTesting Leadfeeder blog.

Leadfeeder's system consists of multiple applications, mainly written in Ruby. We want to be sure that each of these components works as expected, so we cover the code with unit tests and, in the case of Rails applications, with controller specs.

However, sometimes having a good unit test coverage might be not enough and still may lead to the classical "2 unit tests, 0 integration tests" situation like the one in the meme below:

browser-test-leadfeeder
Browser test meme

To prevent such situations, in case of more critical parts of the system we write UI tests that cover the whole functionality from top to bottom.

One of the major problems that we have to deal with is that our apps can be visited from potentially any device/browser. Even though the developers of browsers try to stick to the standards each of the browsers behaves slightly differently.

Oh, and there's Internet Explorer too...

As you can probably imagine we're not running manual tests on all browsers available on the market. What we did instead is we've developed our own testing toolkit that runs a suite of tests on a set of real devices on the CrossBrowserTesting platform.

In this post, I'd like to show you step by step how we integrated all the moving parts in order to create such a toolkit — Hopefully, you'll be able to set up something similar in your own projects too.

When you're done with reading this article you can find the whole code in this repository.

Note: Try Leadfeeder for 14-days, free. You read that correctly, free leads for two weeks.

Step 0 - Prepare the application under test

Let's prepare a simple Rails 6.1 application called LinkShortener. Its only purpose will be creating short links out of URLs provided by users. Something similar to what bit.ly does.

The app will neither be beautiful (I'll use default views produced by Rails generators) nor user-friendly, but it should be enough to be able to write a simple UI test suite.

The application consists of four endpoints:

  • get "/short_links/new"  - Shows a form for creating a new short link

  • post "/short_links"  - Saves a new short link in the database

  • get "/short_links/:id" - Displays information about a link

  • get "/l/:slug" - Redirects user to the original URL stored in the ShortLink record.

Go ahead - check out the repository locally and try the app out by running rails server and visiting localhost:3000.

short-link-leadfeeder
Short link GIF

Step 1 - Setup RSpec and Capybara

Before testing the app with real browsers on crossbrowsertesting.com let's start small and write a simple RSpec test suite that will be executed by Capybara using Chrome driver (make sure you have Chrome browser installed beforehand).

First, let's add necessary gems to Gemfile: type: embedded-entry-inline id: 0tY4HeuWwqpN9qgxcOlXg Then add spec/spec_helper.rb and spec/capybara_helper.rb files that'll configure RSpec and Capybara respectively. I've removed most of the typical "boilerplate" code from the listings below to make this post easier to read. You can still find the full code in the repository. type: embedded-entry-inline id: 5TSGz1PbnBuG76hi9BaFh7 Now, let's write a few simple specs and put them in spec/features/links_spec.rb. The first spec will verify that creating and redirecting works correctly. The other one will test the unhappy path when trying to save a short link by pointing to an invalid URL.

type: embedded-entry-inline id: 2uPPVCuZTHGsz5WlfY635x

Let's now run our test suite by calling $ bundle exec rspec . Here's how the output should look:

test-suite-code-leadfeeder
Bundle exec rspec test suit code from Leadfeeder

Step 2 - Using ngrok tunnels

Great, we have a working Capybara setup and a passing test suite. Many people would stop here, but not us! Eventually, we'd like CrossBrowserTesting's browsers to run our tests, so we'll have to somehow allow their computers to access the LinkShortener app.

CrossBrowserTesting's help docs suggest using SmartBear SecureTunnel CLI that sets up an HTTP tunnel between their servers and your computer. I've tried using it and I have to say it was rather a poor experience... Many times the tests would fail due to connection errors. Also, some CBT (mostly Mac/iOS) devices couldn't access localhost:7654 and I had to access the application by calling local:7654. Luckily we aren't stuck with the CLI suggested by crossbrowsertesting.com, because ngrok comes to the rescue!

If you don't yet know ngrok - it's a tool that allows setting up an HTTP(s) tunnel to the desired port on your computer. Once you run it, you receive HTTP and HTTPS URLs that route traffic from the Internet to your localhost.

Try it out yourself by running $ ngrok HTTP 7654 . As you can see it creates two URLs pointing to localhost:7654. Don't be scared about our "Pro" plan - the features that we need in this tutorial are available in the free tier as well. :)

ngrok-code-leadfeeder
ngrok Leadfeeder code example

Now we'll configure RSpec to set up such a tunnel before each test and tell Capybara to access test pages through the URLs provided by ngrok. We'll do it by using ngrok-tunnel - a gem that wraps ngrok's CLI.

Add gem "ngrok-tunnel" to the Gemfile and make sure that you have ngrok installed in a folder listed in your $PATH variable. Otherwise, ngrok-tunnel won't be able to access ngrok binary and create tunnels.

Later create a new file: spec/ngrok_helper.rb with the following content: type: embedded-entry-inline id: 6zAVUeG6PyrurTi9FUyoiE Now include the new file in spec_helper.rb by adding require_relative "ngrok_helper" and run bundle exec rspec. You should notice that the browser now visits URLs from ngrok.io domain instead of localhost:

new-short-link-leadfeeder
New short link example Leadfeeder

Note: Normally when you run tests a new tunnel will be started before each spec to overcome the 40 connections per minute limit. However, if you have a paid ngrok account you can run specs with the NGROK_AUTHTOKEN variable.

That will keep a single tunnel running during the whole test suite and will save you precious seconds.

Step 3 - Test on real browsers using crossbrowsertesting.com

After all the previous work we're finally ready to integrate our test suite with CrossBrowserTesting platform. If you don't have an account there go ahead and create one. You can register for a trial here.

We'll create yet another helper file called spec/cbt_helper.rb that'll add a custom Selenium remote driver. The driver's URL will point to your CrossBrowserTesting account's testing hub.

In this example, it'll use Firefox browser on macOS, but later I'll show you how to run tests on any available device. type: embedded-entry-inline id: 2qfRGEzvEdrNKqdxgq3sMY

Add a require for this file in spec_helper.rb as well after creating it.

Running the tests will require two additional ENV variables:

  • CBT_USERNAME - Your CrossBrowserTesting email (make sure to replace @ with %40)

  • CBT_AUTHKEY - Your CrossBrowserTesting key. You can find it in your settings.

Once you run CBT_USERNAME=<YOUR_EMAIL> CBT_AUTHKEY=<YOUR_AUTHKEY> bundle exec rspec CrossBrowserTesting will start a machine with Firefox and start clicking through your page.

When rspec command finishes, go to https://app.crossbrowsertesting.com/selenium/results. There you can see the recording of your test and a list of all commands executed by the remote Selenium driver:

crossbrowsertesting-example
CrossBrowserTesting example from Leadfeeder

How to set CrossBrowserTesting build status?

We've reached our main goal - we've successfully run a test suite on a remote browser. However, as you probably noticed, all finished builds on crossbrowsertesting.com have "Unset" status which makes it a bit hard to spot a failing build.

Fortunately fixing this is really simple. All we need to do is send one HTTP PUT request to CrossBrowserTesting API with the result of RSpec test suite in after(:suite) hook.

We'll send the request using rest-client gem. After adding it to the Gemfile append the following snippet to cbt_helper.rb:

type: embedded-entry-inline id: 4uW25dIoUK7Mv5ZNdnnHR5

Run RSpec again now. Remote build status should now be set to "Pass":

custom-build-leadfeeder
Custom Build Leadfeeder

How to test on other available devices/browsers?

And now a cherry on top - I'll show you how to run the test suite on any of the available CBT browsers.

As you may remember from the previous chapter we configured the remote Selenium driver to use Firefox browser on macOS by setting browserName = "Firefox" and platform = "Mac OSX 10.12" in desired_capabilities hash.

All we need to do in order to change the platform is to replace the current config with another one that matches the desired platform. But where can we get that info from? We can do it in two ways, let me show you both of them...

CrossBrowserTesting capabilities configurator

A simple way of changing the browser is picking a desired platform from the list available on https://app.crossbrowsertesting.com/selenium/run and just copying the generated snippet into cbt_helper.rb.

capabilities-configurator-leadfeeder
Capabilities configurator example from Leadfeeder

Once you pick e.g. Microsoft Edge from the list, replace the caps with the listed ones and run the specs you should see the following result:

microsoft-edge-example-leadfeeder
Microsoft Edge specs example from Leadfeeder

CrossBrowserTesting API

Picking a browser from the Capabilities Configurator list may be enough in your case, but in our situation, it'd be great to be able to test the script on as many different devices as possible. Perfectly we'd run tests each time on a random browser.

The good news is that there's a simple way to do it. A full list of supported browsers can be loaded from CBT's API at https://crossbrowsertesting.com/api/v3/selenium/browsers.

Let's save the list from the API into spec/cbt_browsers.json, replace the Firefox config in cbt_helper.rb with the following snippet and run tests again.

type: embedded-entry-inline id: 4xisY7wZgQ345yLZN2K1Kx

running-cbt-test-with-caps
Running a CBT test with caps for a Leadfeeder project.
cbt-test-example-leadfeeder
Testing browsers for a custom build example.

Our script picked a random device from the list and for the selected device it randomly chose a browser (in this case Pixel 2 with Chrome).

Conclusion

It took some work, but ultimately we managed to create a toolkit that can help us detect problems even on "exotic" device configurations. Having this framework you can e.g. configure a scheduled build in your CI tool that'll run the test suite every hour on a random browser.

I hope this tutorial will help you with making your code more bulletproof!

Note: Leadfeeder offers a 14-day free trial to identify companies that visit your website. Check it out.

Jamie Headshot Square

Director of Content Marketing @ Leadfeeder

Jamie Pagan is Director of Demand at Leadfeeder, where he leads demand generation and pipeline growth initiatives. His work focuses on connecting marketing activity with revenue by combining intent signals, campaign performance data, and audience insights.

With experience building scalable demand engines and launching growth-focused campaigns, Jamie brings a practical perspective on how marketing teams generate and capture demand. His experience working with intent data and marketing analytics informs his approach to identifying high-intent buyers and converting interest into qualified opportunities.

Related articles