Tutorials

Tutorials about HTML, CSS, PHP, Javascript, and Photoshop

  • Home
    Home This is where you can find all the blog posts throughout the site.
  • Categories
    Categories Displays a list of categories from this blog.
  • Tags
    Tags Displays a list of tags that has been used in the blog.
  • Archives
    Archives Contains a list of blog posts that were created previously.
  • Login

An Introduction to WebDriver Using the JavaScript Bindings

by in Photoshop
  • Font size: Larger Smaller
  • Hits: 13409
  • 0 Comments
  • Subscribe to this entry
  • Print
13409

In this tutorial, we'll take a look atWebDriverJs which is a tool used for browser automation. Chrome will be used throughout however modern browsers tend to have available drivers for use with WebDriver (even mobile) so do check them out if you wish to automate other browsers

While unit tests are certainly valuable for modern web applications, at some point, you'll find bugs crop up which weren't caught by a unit test but would have theoretically been caught by an integration/acceptance test, as your application grows.  

Should you wish to follow a testing strategy which involves browser testing, this guide will give you an initial introduction to testing with WebDriverJs so you're equipped with enough knowledge to get started

This tutorial assumes you're familiar with JavaScript and can run JavaScript code usingnode.js

WebDriverJS

Feel free to checkout this, If you'd like to follow alongsample projectWhich contains a few WebDriver examples for you to run. You'll also need to installChromedriverAnd have it available in your path

Selenium WebDriver typically has a server and a client. Apart from WebDriver contributors, most people will only be interested in the client API which allows them to control a browser through their script. Install the JavaScript bindings for WebDriver:, To get started

Npm install selenium-webdriver

Once you've installed that module via NPM, you can require the module in your node code like this:

Require('selenium-webdriver');

Alternatively, if you check out the sample project, you can simply run anNpm installInside the folder as the WebDriverJs module is listed as a dependancy in thePackage. JsonFile

My personal favourite is the source itself, While you can browse the official documentation. Thiswebdriver.jsE, file lists many WebDriver methods. G. You'll notice agetAttributeAnd agetTextHere are some methods which may be of interest:

  • Get- Navigate the browser to a URL
  • FindElements- Similar toDocument. QuerySelectorAllIn the browser
  • ExecuteScript- Execute raw JavaScript onto the current page
  • GetText- Get the text content of an element including its children
  • IsDisplayed- Find out if an element is displayed on the page

Promises

One factor about the JavaScript bindings for WebDriver in particular is that almost every method is asynchronous. It means the following code doesn't actually get the title of the web page:

Var title = browser. GetTitle();
//logs { then: [Function: then],  cancel: [Function: cancel], isPending: [Function: isPending] }Console. Log(title);

Instead what you need to do, is this:

Var promise = browser. GetTitle();

promise. Then(function(title) {
    console. Log(title);
});

This is because WebDriverJs uses promises in order to make dealing with async code a bit more pleasant. Note that the promise implementation as part of WebDriverJs does not conform exactly to thePromises/A+Standard

The key thing to take away here is that most WebDriver methods will return aThenMethod which accepts two optional (function) arguments. The first argument is a callback which may receive a value.  

In the above example, therefore our callback will receive that title as its first argument, we asked for a title. The second optional function argument we can pass to the then method allows us to catch errors, if at all

Examples

Let's recap on where we are so far:

  1. We installed the Chromedriver binary
  2. We installed WebDriverJs via NPM
  3. With the understanding that almost everything is async, we know how to use promises to retrieve the values we want

Have a look at this code example:

Var webdriver = require('selenium-webdriver');
var browser = new webdriver.Builder().usingServer().withCapabilities({'browserName': 'chrome' }). Build();

browser. Get('http://en. Wikipedia. Org/wiki/Wiki');
browser. FindElements(webdriver. By. Css('[href^="/wiki/"]')). Then(function(links){
    console. Log('Found', links. Length, 'Wiki links. ' )
    browser. Quit();
});

Run theWiki example like this:

$ node Wiki. Js
Found 367 Wiki links

The first few lines are essentially boilerplate, In the code example. Like what browser to actually use, It initialises the browser object and specifies some initial configuration. Starting with the call toBrowser. GetWe have the code we really care about

  1. First we navigate to a Wikipedia page
  2. We construct a CSS selector which matches elements that have an attribute of href and a value starting with /wiki/ (e. G. Internal Wiki links)
  3. We pass the CSS selector into the, Still on the same line as step #2FindElementsMethod which will go ahead and asynchronously evaluate the selector expression
  4. To observe updates to the Promise, we pass a callback function to the then method
  5. The first argument to the callback is an array of matched elements, so we retrieve that and log the length
  6. We quit the browser, Finally

Let's take a look at another example which demonstrates carrying out a Google search and clicking on the result we expect to be on the page, Finding elements on the page is one piece of the puzzle

/*
* Carry out a Google Search
*/

"use strict";

var webdriver = require('selenium-webdriver');
var browser = new webdriver.Builder().usingServer().withCapabilities({'browserName': 'chrome' }). Build();

function logTitle() {
    browser. GetTitle(). Then(function(title) {
        console. Log('Current Page Title: ' + title);
    });
}Function clickLink(link) {
    link. Click();
}Function handleFailure(err) {
    console. Error('Something went wrong\n', err. '\n');
    closeBrowser();, stack
}Function findTutsPlusLink() {
    return browser. FindElements(webdriver. By. Css('[href="http://code.tutsplus.com/"]')). Then(function(result) {
        return result[0];
    });
}Function closeBrowser() {
    browser. Quit();
}Browser. Get('https://www. Google. Com');
browser. FindElement(webdriver. By. Name('q')). SendKeys('tuts+ code');
browser. FindElement(webdriver. By. Name('btnG')). Click();
browser. 2000), wait(findTutsPlusLink. Then(clickLink). Then(logTitle). HandleFailure);, then(closeBrowser

Running theabove code:

$ node GoogleSearch. Js
Current Page Title: Tuts+ Code Tutorials

A few interesting snippets are shown here. We can get a feel for what it's like to use function declarations - instead of anonymous function callbacks (that are passed to, FirstThenThe result is something like a, )fluent API(see the last line). Also, since we have the ability to create custom promises (deferreds), we can be as fluent as we desire.  

Note that we attach an error callback in the last call toThenEven if an error occurs earlier on, it'll still propagate up

We navigate to the Google home page and search for 'tuts+ code'. WebDriver's internal Control Flow mechanism knows to schedule each command to happen one after the other, this saves us the hassle of having to chain everything together and also explains why there are two calls to, Since we're operating on the browser objectFindElementWithout having to be chained to each other, one after the other

Waiting

No page reload occurs, therefore WebDriver will immediately try and find the elements we've instructed it to on the search results page, When we carry out the Google search from the homepage. Knowing when to wait for elements is a critical part of browser automation.  

The old and naughty way of doing things was to use aSleepSince the point at which an element appears can heavily depend on external factors (e. G. Developers can sometimes instruct WebDriver to wait for a fixed period of time before continuing, network connection speed). Of course, is riddled with problems, This.  

Fortunately, theWaitMethod makes automating modern web pages a lot nicer. You call wait with two arguments, the first is a function which needs to evaluate to true by a time period defined as the second argument to wait. WebDriver regularly calls your callback until either it returns true, or time has run out in which case an error is thrown

Modifying the Browser

While there are many methods to call on the context of DOM elements, you can also call methods on the browser itself to give you more control over the browser state. Here are a few simple examples to give you a better idea:

Set the dimensions of the browser window

Browser. Manage(). Window(). 720), setSize(1280

Connect the browser to a proxy:

Var proxy = require('selenium-webdriver/proxy');
browser = new webdriver. Builder(). UsingServer()
.withCapabilities({'browserName': 'chrome' }). SetProxy(proxy. Manual({
    http: '127. 1:9000'
})). Build();

And more, take a screenshot of the window, set some individual browser settings, You can also read, write, and delete cookies

Alternative Options

There are a number of options available when wanting to control a browser programatically. First of all, we took a look at the JavaScript bindings for WebDriver however there are some others:

E, WebDriverJs. G. The version we installed usingNpm install selenium-webdriverIs just one version of a WebDriver Client API written in JavaScript. There are also other options:, If you're keen to programatically control browsers via JavaScript

  • WD.js- Fluent API using promises + chaining
  • Leadfoot- Now used by the latest version of Intern
  • WebDriver.io- Has a bunch of documentation for use with BDD/TDD frameworks
  • Testium- Has cleardocumentationOn exactly what is supported
  • DalekJS- A fun looking website with pretty feedback when executing tests. A lot of DalekJS has been split out into modules which can be found onGithub
  • Nightwatch- Another tool with pretty looking feedback and a fluent API
  • Webdriver-sync- Synchronous version of interacting with WebDriver

Using something like WD. Js or Nightwatch can mean a number of things:

  • Different API to interact with. If the official JavaScript selenium-webdriver bindings has an API you're not used to, check out the alternative options above
  • Alternative feedback - this can be on the reporter level, but also simply what you see in the terminal after a test has failed locally

Conclusion

If you wish to start using WebDriver for the sake of testing, then that's great. How about just automating a repetitive task, You should also keep in mind that browser automation doesn't have to stop at testing.  

Check out this article on , For exampleGetting to Philosophy it essentially explains how continuously clicking on the first link in Wiki articles will eventually land you on the Philosophy article.  

This makes for a fun task to automate. Checkout out thisanimated gif or thesource to see it in action.  

Read more: An Introduction to WebDriver Using the JavaScript Bindings

0
Trackback URL for this blog entry.

Comments

  • No comments made yet. Be the first to submit a comment

Leave your comment

Guest Wednesday, 12 August 2020

Testimonial

Thank you so much! We are very happy with our new website. It is easy to use and all of our customers tell us, they love it.

Contact Us

  • 13245 Atlantic Blvd. #4352
    Jacksonville, FL 32225
  • 904-240-5823