UI tests, E2E tests, acceptance tests, I don’t care what we call them but today we’re going to take a practical look at writing tests that uses a real browser to find & click on elements.
Selenium is the de facto browser automation solution, but it isn’t always easy to work with. What we need is a representative automation challenge that exercises areas of Selenium that can be tricky to work with, but without being so complex that this blog needs to be a book. Here is the automation challenge I’ve come up with:
- Open a Chrome browser in Incognito mode.
- Go to https://the-internet.herokuapp.com/dynamic_loading/2.
- Click the
- Assert that the
Hello Worldelement is present.
- And do this using the Page Object pattern, because testing always requires a great deal of complexity management.
By requiring Chrome in Incognito mode we must configure the webdriver to pass proper arguments, a small but classic hurdle to overcome. And the “dynamic loading” example on
the-internet deals with having to wait for an element, which can be a tricky scenario. And using Page Objects forces us to deal with abstractions, even if they’re overkill for this specific challenge.
First lets solve the basics, can we open a webpage at all? Roughly speaking we need to configure a test runner, a test framework, and a Selenium-backed framework for each of our projects, and have a single command to execute tests.
Ruby / WebDriver
As always Ruby is easy to work with, these are the steps to get started:
rspec(test runner) and
- Copy-paste test example.
And that’s it, hard to see how it can be done simpler.
Here’s a simple test that just opens Google:
All in all pretty straightforward!
wd since that worked out of the box, but still struggled to put together a solution that just worked. Where Ruby took minutes, this ended up taking more than an hour to complete the full exercise.
- Hm, website doesn’t have a simple example to copy, but a lengthy file in their repo can be pruned down with a bit of effort.
- Hm, the Selenium standalone server must be started in one terminal window and the tests in another…
gulp(build tool) as dependency, and have it run the server and tests simultaneously so we don’t have to juggle multiple terminal windows.
It’s not so bad once everything works, but it sure took longer to get here than I’d like. This is the simple test:
Python / Selenium-py
As usual Python comes batteries included, the only dependency is the Selenium framework itself. Very nice! Unfortunately we do have to deal with Python’s cumbersome dependency system, but that’s an annoyance for another article. Here are the steps:
- Create and activate a “virtualenv” (a concept of isolating from your global Python installation so your dependencies are confined to the project’s directory. It’s a boring technicality).
selenium-pyas a dependency (and remember to manually pipe that dependency into a
- Pretty much copy-paste example from website.
python -m unittest discover test. Jeez that’s a mouthful, and it only works if the virtualenv is active…
- Create a
runtests.shscript to automate those steps. Too bad that won’t work on Windows.
Well, that wasn’t too terrible, and the test sure looks elegant:
The Real Challenge
Now to turn the simple test into one that solves our challenge.
Ruby / WebDriver
First lets extract configuration data to a separate file:
And create a very simple page object, thanks to Capybara’s powerful DSL:
That leaves our challenge test, which is very minimal:
A nice side-effect of extracting configuration is that we can also scoop out all that top-heavy module importing/glueing that clutters the test:
And all the selectors and other page-specific complexities go into the page object file:
Which just leaves the test, and despite the presence of some boilerplate the test itself is very minimal:
Python / Selenium-py
Once again we extract configuration and page object:
Resulting in a very clean test file:
For future reference here are my system versions: