Selenium NodeJS boilerplate with Browserstack
Detailed documentation scalable selenium boilerplate set up
tldr;
If you just want to get up and going you can follow the README on Github:
Selenium journey testing example, enjoy 🚀
Still here?… Great, below is more detailed documentation, background and conventions I used in this set up.
I’m aware that with the upcoming support of Cypress.io the life span of this probably isn’t long and if you have the option to use Cypress.io over Selenium I probably would. However, currently (as of writing this) Cypress.io has only just come out of beta and only has support for Chrome. So, if like me, you need your end-to-end tests to support other browsers or integration with Browserstack then Selenium might still be the best option ✌️
I made this repo off the back of a recent contract where I was tasked with defining a full testing framework. If you’re interested, this was the final documentation that was proposed to the development team and then implemented throughout the project.
This was my first time using Selenium and found there weren’t many useful examples of a maintainable set up so decided to put up this repo as a boilerplate template for future use and to help anyone else in a similar position.
Approach
Below are some explanations of conventions and approaches I’ve used in this set up:
Files and naming
Each page of the site has its own test file and should have a limited focus. So, for example when testing the login function from the homepage you’d only check its made it’s made it past the login page and not test the journey any further e.g logging in and updating user credentials. Admittedly, this might not be full end-to-end but rather checking modular functionality from each page which we found a lot easier to manage.
The naming convention used for each file is<filename>.ui.js
. The reason for suffixing test files with the test type (.ui) is to tell mocha to ignore any files without the suffix. Furthermore, if you have other tests in your repo such as unit or integration tests you can run them separately.
Page Object Model
This pattern allows us to separate testing logic (e.g filling in forms) and page selectors from the test assertions which keeps our test files easy to read. The example below uses the clickLogin()
method from the home class to complete the required functionality as well as the accountInformation
locator to find a div
on the home page to assert against.
Each page or component has its own class. The above example also used the login Class to complete the login process as its on a different page.
These class files live in the/__tests__/pages/
directory.
Each of these classes usually contain the following
- url: for the open method to open the page
- locators: page selectors
- methods: functionality such as logging in or completing a form
These classes are shared between tests which keeps the selectors and functionality fairly DRY, in that if an ID selector changes in the page mark up you’d only need to change it in the class selectors once.
Utilities
Utilities which I frequently used throughout writing these tests.
wait(duration)
will pause the test for the given amount of time. I found this useful when elements appear in the DOM but web-driver isn’t able to interact with them. It will however, slow down your tests so best used as an escape-hatch sparingly. If you’re just waiting for an element to appear usewaitFind
.waitFind(driver, element)
uses the until function from selenium-webdriver to wait until it finds the element before returning it. You just need to provide it with the current driver and the element you’re looking for.switchTab
use this function if the browser opens a new tab. I’ve included an example of this in the login.ui.js test when clicking on the privacy link.
Workflow
To develop tests locally simply run npm run test
which defaults to Chrome and should boot up a Chrome instance to run the tests against. Then, once local testing is finalised they can be automated with Browserstack.
Web drivers
For local development using Chrome or other browsers you’ll need to add the the individual web drivers for each browser to your local machine. You can find download links and instructions for each one here.
Once installed you can specify which web driver you want to use for your tests by adding these extra flags. The two below are ones I’ve already set up:
npm run test
(chrome — default)npm run test -- --firefox
note the extra dashes are required to add that flag onto the npm script
Above is an example in firefox. To add more web drivers, you just need to add them to the browsers object (below). The key you use for each web driver is the --flag
you add to the npm script.
Browserstack
To use browserstack with this set up. You’ll need to add your credentials to the .env
file as detailed in below in ‘Getting started’. You can sign up to a free account and find those credentials on your dashboard.
To run the tests in Browserstack simply add the browserstack flag:
npm run test -- --browserstack
Below is a Browserstack demo of what you get on the dashboard, as you can see the Google log in doesn’t actually complete due to authentication checks however, this isn’t an issue with the tests or browserstack and shouldn’t be a problem unless you’re actually logging into Google.
I’ve set up Browserstack to test using Chrome on a desktop but you can add more browsers and devices to test against by adding them to the capabilities variable in the config file.
Getting started
Feel free to remove the demo tests and pages that I’ve included as an example and simply use this as a boilerplate to create your own tests. However, the tests I’ve included cover some simple functionality which you can use as reference to get going with.
These tests are using google.com:
1) Home page
The first tests checks to see if the header div exists, which is a common type of test to check if the correct elements have loaded. The second test in the home page will check the login process. It will navigate to the login page use the homepage class to complete the login form and then finally check the account information to see if its successfully logged in.
2) Login page
This test checks that the privacy link correctly navigates to the privacy page. I included this as it opens a new tab and made use of the switchTab
utility.
Set up
I’ve used an .env
file to store any credentials.
GOOGLE_EMAIL=email
GOOGLE_PASSWORD=password
BROWSERSTACK_USERNAME=username
BROWSERSTACK_AUTOMATE_KEY=key
This is optional, and if you choose not to use it just replace the where I’ve used the variables with your own and remove require("dotenv).config();
anywhere.
Prerequisites
- Web Driver for Chrome (and Firefox if you want to use it)
- Node 8 (
nvm use
will use 10.9.0)
To Run
In the root directory run:
npm install
npm run test
Finally
This might seem like a lot of documentation and maybe slightly opinionated set up. However, from spending a lot of time digging around and piecing together different approaches this is the one that worked the best for us. Even if you don’t use the whole set up there might be some nuggets or tricks you can take away ❤️