Selenium: an Apple story

Hi! This is the my next article related to Selenium testing. I have already told you the full history about organizing scalable Selenium cluster (part I, part II). Then we focused on using Selenium as development tool (one, two), Finally we successfully created Selenium order from chaos on Windows platform (link). Today we are going to deal with apples, more precisely with one big Apple.

Although Selenium is relatively simple tool things are getting complicated when trying to run automatic tests in browsers from Cupertino such as Safari on MacOS and mobile Safari on iOS. To finish the story with desktop browsers — let’s talk about desktop Safari. For the moment latest Safari versions are only present on MacOS. Historically Selenium interaction with Safari was done using an extension which translated Selenium commands to browser native ones. Initially this extension was loaded to Safari automatically by Selenium server. Later due to security policy in Safari you had to download and install it manually. With the introduction of Safari X release this situation has changed. Now Safari is using a standalone webdriver binary — safaridriver similarly to other popular browsers like Google Chrome having chromedriver and Mozilla Firefox providing geckodriver. To launch your tests against Safari you need to:

  • Launch safaridriver binary (usually installed with Safari to /usr/bin/safaridriver) on some port, e.g. 4444. The command would be something like:
$ /usr/bin/safaridriver --port 4444
  • Run your tests using the following url:
http://localhost:4444/
  • Stop launched driver process.

Sounds simple — and it is! However there is one problem — safaridriver can work with only one Safari session simultaneously. How to overcome this obstacle? - Just launch the driver multiple times using different free ports and run your tests agains urls with these ports. Simple, but requires too much manual actions - we need to automate this! How could it work? Like the following:

  1. You launch a server with Selenium API and tell it where safaridriver resides.
  2. When a new browser session is requested — this server looks for a free port and occupies it. Then is starts safaridriver using this occupied port value and proxies next requests to driver port.
  3. When you request browser session to stop — safaridriver process is also stopped.

This algorithm is very simple so it should not require complicated software, right? If you choose the nowadays standard — Selenium server, my answer is definitely “no”: Selenium server is too much complicated for such simple job. Why is that:

  1. It is big like an elephant! Starting from twenty megabytes.
  2. It requires Java — one more giant creature to be added to the zoo. With all these annoying update requests and old-school UI.
  3. It is hungry and likes to eat your memory with no reason.
  4. It is not well documented and does not work out of the box. You need to be Harry Potter to make it work.

Bref, let me show you a better tool called Selenoid. Selenoid is a lightweight daemon aimed to completely replace fatty Selenium server. With really simple usage instruction for Safari:

  • Copy paste small piece of JSON below to some file, e.g. to ~/browsers.json:
{
"safari": {
"default": "latest",
"versions": {
"latest": {
"image": ["/usr/bin/safaridriver"]
}
}
}
}
  • Download and run Selenoid binary:
$ curl -Lo ~/selenoid https://github.com/aerokube/selenoid/releases/download/1.3.3/selenoid_darwin_amd64
$ chmod +x ~/selenoid
$ ~/selenoid -conf ~/browsers.json -disable-docker
  • Run your tests against URL:
http://localhost:4444/wd/hub

No more need to install Java and friends! But if you are even more lazy like me, you can achieve the same result with this one-liner:

$ curl -Lo ~/cm https://github.com/aerokube/cm/releases/download/1.2.1/cm_darwin_amd64 && chmod +x ~/cm && ~/cm selenoid start --browsers safari

If you wish — you can additionally download and launch a lightweight UI for Selenoid. Refer to documentation for more details.

Painless Selenium with Safari have never been so close. Have a nice day!