Selenium Tutorial
  by Jake  

Selenium Tutorial


Before diving in, it's worth defining the relevant terms:

  • Selenium is a framework for automating browser interaction. The most common (and benevolent) use case is running automated tests across browsers.
  • Selenium Grid is a way to parallelize Selenium processing. Since functional tests often run pretty slow, and most websites need lots of them, running processes in parallel is critical.
  • A Selenium Grid Hub is sort of like a load balancer, it takes requests from remote clients and delegates them to available Nodes.
  • A Selenium Grid Node is responsible for actually running the processes (and does most of the heavy lifting).
  • Xvfb allows Selenium to run headless (without a screen), which is necessary because EC2 instances don't have visual displays.

This tutorial walks through setting up a Selenium Grid, specifically:

Selenium Hub on EC2

Selenium Hubs are pretty lightweight. In my experience, a t2.micro EC2 instance on Ubuntu 16.04 works perfectly!

But heads up! Your Selenium Hub must be open on port 4444 (and it's generally a good idea to leave a port open for SSH). So set up a security group with the following configuration:

Hub config

Then launch the instance with a key pair you own, and SSH into it like so:

ssh -i ~/path/to/whatever-key-pair-you-used.pem

Once you're on the EC2 instance, install Selenium (one step at a time, because some of them have prompts that will require your response):

sudo add-apt-repository ppa:webupd8team/java
sudo apt update; sudo apt install oracle-java8-installer
sudo apt install oracle-java8-set-default

Then start the Hub in a screen:

screen java -jar selenium-server-standalone-3.0.1.jar -role hub

You should see some output confirming that the Hub is working. Then disconnect from the screen (hold down on control and type a then d).

You can test that the Hub launched successfully by navigating your browser to:

Nice work! You've hired the coach, now to recruit the team.

Selenium Node on EC2

Selenium Nodes have a much bigger memory footprint than the Hub, especially when running 12 browser instances in parallel. We'll use a t2.medium EC2 instance on Ubuntu 16.04.

Similar to the Hub, you'll need to leave a port open for communication on the Nodes as well. By default, that port is 5555, so configure the security group like so:

Node config

Launch the instance with the same key pair, and SSH in just like you did with the Hub. Then install Selenium:

sudo add-apt-repository ppa:webupd8team/java
sudo apt update; sudo apt install oracle-java8-installer
sudo apt install oracle-java8-set-default

and Xvfb:

sudo apt-get -y install xvfb
sudo apt-get -y install xserver-xorg-core
sudo apt-get -y install xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic

Once you have Selenium and Xvfb installed, you'll need Chrome:

wget -q -O - | sudo apt-key add -
sudo sh -c 'echo "deb stable main" >> /etc/apt/sources.list.d/google.list'
sudo apt-get update
sudo apt-get -y install google-chrome-stable
sudo apt-get -y install unzip
chmod +x chromedriver
sudo mv -f chromedriver /usr/local/bin

and Firefox:

sudo apt-get -y install firefox
tar -xvzf geckodriver-v0.13.0-linux64.tar.gz
rm geckodriver-v0.13.0-linux64.tar.gz
chmod +x geckodriver
sudo mv -f geckodriver /usr/local/bin

You may notice that in both cases we installed a driver for the browser, changed the ownership permissions, and moved it into /usr/local/bin

That essentially provides the API for Selenium to control each browser.

Now that everything is installed, start Xvfb:

Xvfb :99 -screen 0 1024x768x24 -ac 2>&1 > /dev/null &

and boot up the node!

export DISPLAY=:99 && screen -d -m java \"/usr/local/bin/chromedriver" \
  -Dwebdriver.gecko.driver="/usr/local/bin/geckodriver" \
  -jar selenium-server-standalone-3.4.0.jar \
  -role node \
  -maxSession 20 \
  -browser browserName=chrome,maxInstances=6 \
  -browser browserName=firefox,maxInstances=6 \

Once again - make sure you substitute the Public DNS address of your Hub for your-hub-ec2-address on the final line above. You can also tweak the lines above to scale up or down the number of browser instances running in parallel. But just be wary of memory footprint. The configuration above works well on t2.medium EC2 instances.

You can test that the Node connected to the Hub by navigating your browser to:

Selenium Node on MacStadium

You're officially a Selenium Whiz!

But I have some bad news... Selenium and Safari have a love-hate relationship. On the one hand, the latest version of Safari ships with a native safaridriver. Remember those drivers we installed and moved around for Chrome and Firefox? Apple built a Selenium-compatible driver right into Safari, which means that the latest Safari runs performant and smooth on Selenium.

So what's the catch? You can only run one instance at a time. So while we launched 6 parallel instances of Chrome and Firefox each on a single EC2 server, we'll need a whole dedicated Mac machine for every instance of Safari on Selenium. And please don't try to use a VM. In my experience, Safari (or at least safaridriver) does not behave predictably on VMs.

I recommend the $69/mo Mac Mini on MacStadium running macOS Sierra 10.12 and the latest Safari. I've found MacStadium's support to be incredibly knowledgeable and responsive, and their Mac Mini instances perform perfectly!

Install Selenium using homebrew:

ruby -e "$(curl -fsSL" < /dev/null 2> /dev/null
brew install selenium-server-standalone
brew install jenv
echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.profile
echo 'eval "$(jenv init -)"' >> ~/.profile
source ~/.profile
brew cask install java
jenv add /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/
echo '1.8' >> ~/.java-version
source ~/.profile

Then open up Safari and follow these two steps:

  • Turn on the Develop menu by opening Safari preferences (Safari > Preferences in the menu bar), going to the Advanced tab, and ensuring that the Show Develop menu in menu bar checkbox is checked.
  • Toggle Develop > Allow Remote Automation in the menu bar.

And finally, run the server using homebrew (and only allocating one session and instance):

selenium-server \
  -role node \
  -maxSession 1 \
  -browser browserName=safari,maxInstances=1 \

And that's it! You now have a Selenium Grid that can run 6 concurrent tests on Chrome, 6 on Firefox, and 1 on Safari.