Getting started with Selenium and Node.js
Selenium is a great tool to automate our functional tests on websites and web applications in our favorite language. With CrossBrowserTesting, you can use Selenium and JavaScript to run automated browser tests on thousands of real mobile and desktop browsers in the cloud.
Note: | You will need a Username and Authkey to run your tests on CrossBrowserTesting To get yours, sign up for a free trial or purchase a plan. |
Install Selenium
To get started, make sure you have Selenium’s language bindings for JavaScript installed and ready. You can find the official resource for this here:
http://www.seleniumhq.org/download/
Or if you have NPM loaded on your machine (comes with Node.js distribution), you can type the following into the terminal:
npm install selenium-webdriver
Run your first test
Once you have Selenium-WebDriver in place, you should be ready to start testing. Copy the following script into your text-editor of choice:
"use strict";
var webdriver = require("selenium-webdriver"),
SeleniumServer = require("selenium-webdriver/remote").SeleniumServer;
var cbtHub = "http://hub.CrossBrowserTesting:80/wd/hub";
var username ='YOUR_USERNAME'; //replace with your email address
var authkey = 'YOUR_AUTHKEY'; //replace with your authkey
var caps = {
name : 'Basic Test Example',
build : '1.0',
version : '70',
platform : 'Windows 10',
screen_resolution : '1366x768',
record_video : 'true',
record_network : 'false',
browserName : 'Chrome',
username : username,
password : authkey
};
async function basicExample(){
try{
var driver = new webdriver.Builder()
.usingServer(cbtHub)
.withCapabilities(caps)
.build();
await driver.get('http://crossbrowsertesting.github.io/selenium_example_page.html');
await driver.getTitle().then(function(title) {
console.log("The title is: " + title)
});
driver.quit();
}
catch(err){
handleFailure(err, driver)
}
}
basicExample();
function handleFailure(err, driver) {
console.error('Something went wrong!\n', err.stack, '\n');
driver.quit();
}
Choose browsers
To choose your environment, you can select from Browsers, Operating System, Resolutions, and Devices. You can use our easy Selenium Wizard to select your configuration or hit our browser list endpoint.
Record videos
For superior debugging capabilities, CrossBrowserTesting offers the ability to record a video of your Selenium test session. You can find a copy of your test results here.
var caps = {
'record_video': 'true'
}
Record network
To record the network packets during your test for performance debugging, set the following to "true"
.
var caps = {
'record_network': 'true'
}
Run a local test
With our Local Tunnel, you can run a test on a local URL or behind your company's firewall. There are two different ways to connect the CrossBrowserTesting local tunnel: our Node.js client and our Chrome Extension.
To learn more about setting up, starting, and using your tunnel connection, see About Local Testing.
When a tunnel is open, any automated test can access websites locally, behind a firewall, or across a proxy. There is no need to set a capability during your test.
Run tests in parallel
To speed your automated testing, you can run your tests in parallel, making use of several browsers or devices at one time. To run parallel tests using Node we will use the Flow function.
var username ='YOUR_USERNAME'; //replace with your email address
var authkey = 'YOUR_AUTHKEY'; //replace with your authkey
var webdriver = require('selenium-webdriver'),
SeleniumServer = require('selenium-webdriver/remote').SeleniumServer,
request = require('request');
var remoteHub = "http://" + username + ":" + authkey + "@hub.crossbrowsertesting.com:80/wd/hub";
var browsers = [
{ browserName: 'Chrome', platform: 'Windows 10', version: '64', screen_resolution: '1366x768' },
{ browserName: 'Chrome', platform: 'Mac OSX 10.14', version: '71x64', screen_resolution: '1366x768' },
{ browserName: 'Internet Explorer', platform: 'Windows 8.1', version: '11', screen_resolution: '1366x768' }
];
var flows = browsers.map(function(browser) {
var caps = {
name : 'Node Parallel Example',
browserName : browser.browserName,
version : browser.version,
platform : browser.platform,
screen_resolution : browser.screen_resolution,
username : username,
password : authkey
};
async function parallelExample(){
try{
var driver = new webdriver.Builder()
.usingServer(remoteHub)
.withCapabilities(caps)
.build();
await driver.getSession().then(function(session){
var sessionId = session.id_; //need for API calls
console.log('Session ID: ', sessionId);
console.log('See your test run at: https://app.crossbrowsertesting.com/selenium/' + sessionId)
});
await driver.get('http://www.google.com');
var element = await driver.findElement(webdriver.By.name('q'));
await element.sendKeys('cross browser testing');
await element.submit();
await driver.getTitle().then(function(title) {
console.log("The title is: " + title);
if (title !== ('cross browser testing - Google Search')) {
throw Error('Unexpected title: ' + title);
}
});
driver.quit();
}
catch(err){
console.error('Exception!\n', err.stack, '\n');
driver.quit();
}
}
parallelExample();
});
Take snapshot
You can take snapshots of errors during your test run for easy debugging and documentation. You can share these snapshots through Jira, Slack, or Email. To take a snapshot during your test run, you just have to invoke our API.
driver.takeSnapshot();
To see how to call the API, read below.
Full example
var username ='YOUR_USERNAME'; //replace with your email address
var authkey = 'YOUR_AUTHKEY'; //replace with your authkey
var webdriver = require('selenium-webdriver');
var SeleniumServer = require('selenium-webdriver/remote').SeleniumServer;
var request = require('request');
var remoteHub = 'http://hub.crossbrowsertesting.com:80/wd/hub';
var caps = {
name : 'Login Form Example',
build : '1.0',
version : '70',
platform : 'Windows 10',
screen_resolution : '1366x768',
record_video : 'true',
record_network : 'false',
browserName : 'Chrome',
username : username,
password : authkey
};
var sessionId = null;
console.log('Connection to the CrossBrowserTesting remote server');
async function fullExample(){
try{
var driver = new webdriver.Builder()
.usingServer(remoteHub)
.withCapabilities(caps)
.build();
console.log('Waiting on the browser to be launched and the session to start');
await driver.getSession().then(function(session){
sessionId = session.id_; //need for API calls
console.log('Session ID: ', sessionId);
console.log('See your test run at: https://app.crossbrowsertesting.com/selenium/' + sessionId)
});
//load your URL
await driver.get('http://crossbrowsertesting.github.io/login-form.html');
//take snapshot via cbt api
await driver.takeSnapshot();
//find checkout and click it
await driver.findElement(webdriver.By.id("username")).sendKeys("[email protected]);
//send keys to element to enter text
await driver.findElement(webdriver.By.xpath("//*[@type=\"password\"]")).sendKeys("test123");
//take snapshot via cbt api
driver.takeSnapshot();
//click the archive button
await driver.findElement(webdriver.By.css("button[type=submit]")).click();
//wait on logged in message
await driver.wait(webdriver.until.elementLocated(webdriver.By.id("logged-in-message")), 10000);
//take snapshot via cbt api
await driver.takeSnapshot();
//quit the driver
await driver.quit()
//set the score as passing
setScore('pass').then(function(result){
console.log('SUCCESS! set score to pass')
});
}
catch(e){
webdriverErrorHandler(e, driver)
}
}
fullExample();
//Call API to set the score
function setScore(score){
return new Promise((resolve, fulfill)=> {
var result = { error: false, message: null }
if (sessionId){
request({
method: 'PUT',
uri: 'https://crossbrowsertesting.com/api/v3/selenium/' + sessionId,
body: {'action': 'set_score', 'score': score },
json: true
},
function(error, response, body) {
if (error) {
result.error = true;
result.message = error;
}
else if (response.statusCode !== 200){
result.error = true;
result.message = body;
}
else{
result.error = false;
result.message = 'success';
}
})
.auth(username, authkey);
}
else{
result.error = true;
result.message = 'Session Id was not defined';
deferred.fulfill(result);
}
result.error ? fulfill('Fail') : resolve('Pass');
});
}
//Call API to get a snapshot
webdriver.WebDriver.prototype.takeSnapshot = function() {
return new Promise((resolve, fulfill)=> {
var result = { error: false, message: null }
if (sessionId){
request.post(
'https://crossbrowsertesting.com/api/v3/selenium/' + sessionId + '/snapshots',
function(error, response, body) {
if (error) {
result.error = true;
result.message = error;
}
else if (response.statusCode !== 200){
result.error = true;
result.message = body;
}
else{
result.error = false;
result.message = 'success';
}
}
)
.auth(username,authkey);
}
else{
result.error = true;
result.message = 'Session Id was not defined';
}
result.error ? fulfill('Fail') : resolve('Pass'); //never call reject as we don't need this to actually stop the test
});
}
//general error catching function
function webdriverErrorHandler(err, driver){
console.error('There was an unhandled exception! ' + err.message);
//if we had a session, end it and mark failed
if (driver && sessionId){
driver.quit();
setScore('fail').then(function(result){
console.log('FAILURE! set score to fail')
})
}
}
Troubleshooting
JavaScript and Selenium bindings and promises
The major difference between Selenium bindings for JavaScript and any other language is that almost every method call in JavaScript is asynchronous. The following code does not work:
var title = driver.getTitle();
console.log(title);
Because, of course, both statements are executed at the same time. WebDriver for JavaScript luckily allows us to use promises so that the steps of our test are executed in the proper sequence. The following code snippet does the same thing the previous version should, but it actually executes correctly:
driver.getTitle().then(function(title) {
console.log(title);
});
Luckily for us, most WebDriver methods in JavaScript will return a then method which takes a callback function for the first argument. In the example here, our first function gets a title, and the callback function receives and makes use of that title.