Share your code. npm Orgs help your team discover, share, and reuse code. Create a free org »



    node.js Webdriver/Selenium 2 client

    Build Status Selenium Test Status

    Selenium Test Status


    npm install wd



    Release notes

    Latest version is 0.2.8.

    Many changes have been introduced in 0.2.x versions, please check here for more details.

    caveats when upgrading to 0.2.3

    • Most wait methods have been deprecated replaced by waitFor/waitForElement + asserters. See doc below, don't hesitate to add more asserters if you feel it is useful for others.
    • Manual monkey patching is not recommended anymore, there were some side use cases which were not easy to cover. Use addAsyncMethod/addPromiseMethod/addPromiseChainMethod methods instead. See doc below.


    Q promises + chaining

        .should.become('WD Tests')
      .elementById('i am a link')
      .fin(function() { return browser.quit(); })

    full code here

    Pure async

    browser.init({browserName:'chrome'}, function() {
      browser.get("", function() {
        browser.title(function(err, title) {
          browser.elementById('i am a link', function(err, el) {
            browser.clickElement(el, function() {
              /* jshint evil: true */
              browser.eval("window.location.href", function(err, href) {

    full code here

    Q promises without chaining

    See example here.

    Generators api


    Yiewd is a wrapper around Wd.js that uses generators in order to avoid nested callbacks, like so:

    wd.remote(function*() {
      yield this.init(desiredCaps);
      yield this.get("");
      el = yield this.elementById("someId");
      el2 = yield this.elementById("anotherThing")
      text = yield el2.text();
      text.should.equal("What the text should be");
      yield this.quit();

    Mocha integration

    describe("using mocha-as-promised and chai-as-promised", function() {
      var browser;
      before(function() {
        browser = wd.promiseChainRemote();
        return browser.init({browserName:'chrome'});
      beforeEach(function() {
        return browser.get("");
      after(function() {
        return browser.quit();
      it("should retrieve the page title", function() {
        return browser.title().should.become("WD Tests");
      it("submit element should be clicked", function() {
        return browser.elementById("submit").click().eval("window.location.href")

    example here


    If wd was installed via npm run:

    ./node_modules/.bin/wd shell

    Or for local install run:

    node lib/bin.js shell

    Then within the shell:

    ): wd shell
    > x = wd.remote() or wd.remote("", 80, "username", "apikey")
    > x.init() or x.init({desired capabilities override})
    > x.get("")
    > x.eval("window.location.href", function(e, o) { console.log(o) })
    > x.quit()



    jsonwire mapping + api doc

    full jsonwire mapping


    WD is simply implementing the Selenium JsonWireProtocol, for more details see the official docs:

    Browser initialization

    Indexed parameters

    var browser = wd.remote();
    // or 
    var browser = wd.remote('localhost');
    // or 
    var browser = wd.remote('localhost', 8888);
    // or 
    var browser = wd.remote("", 80, "username", "apikey");

    Named parameters

    The parameters used are similar to those in the url module.

    var browser = wd.remote()
    // or 
    var browser = wd.remote({
      hostname: '',
      port: 4444,
      user: 'username',
      pwd: 'password',
    // or 
    var browser = wd.remote({
      hostname: '',
      port: 4444,
      auth: 'username:password',

    The following parameters may also be used (as in earlier versions):

    var browser = wd.remote({
      host: '',
      port: 4444,
      username: 'username',
      accessKey: 'password',

    Url string

    var browser = wd.remote('http://localhost:4444/wd/hub');
    // or 
    var browser = wd.remote('');

    Url object created via url.parse

    URL module documentation

    var url = require('url');
    var browser = wd.remote(url.parse('http://localhost:4444/wd/hub'));
    // or 
    var browser = wd.remote(url.parse(''));


        protocol: 'http:'
        hostname: '',
        port: '4444'
        path: '/wd/hub'

    Specifying driver type in remote

    You may pass async,promise or promiseChain to remote to specify the driver type instead of calling the driver specific method.

    var browser = wd.remote('promiseChain')
    // or 
    var browser = wd.remote('localhost', 8888, 'promise');
    // or 
    var browser = wd.remote('localhost', 'promiseChain');
    // or 
    var browser = wd.remote({
      hostname: '',
      port: 4444,
      user: 'username',
      pwd: 'password',
    }, 'promise');
    // or 
    var browser = wd.remote({
      hostname: '',
      port: 4444,
      auth: 'username:password',
    }, 'promiseChain');

    Attach to an already-existing session

    Instead of calling 'init' use 'attach' using the WebDriver session ID. Use detach to detach from the session (callbacks are optional).

    var browser = wd.remote('http://localhost:4444/wd/hub');
    browser.attach('df606fdd-f4b7-4651-aaba-fe37a39c86e3', function(err, capabilities) {
      // The 'capabilities' object as returned by sessionCapabilities 
      if (err) { /* that session doesn't exist */ }
      else {
        browser.elementByCss("button.groovy-button", function(err, el) {


    doc here.

    Element function chaining (using promise chains)

    With the promise chain api the method from the browser prototype and the element prototype are all available within the browser instance, so it might be confusing at first. However we tried to keep the logic as simple as possible using the principles below:

    • There is no state passed between calls, except for what the method returns.
    • If the method returns an element the element scope is propagated.
    • If the method returns nothing (click, type etc...) we make the method return the current element, so the element scope is propagated.
    • If the method returns something (text, getAttribute...), the element scope is lost.
    • You may use "<" as the first parameter to get out of the element scope.
    • You may use ">" as the first parameter to force the call to be done within the current context (mainly used to retrieve subelements).

    If you need to do something more complicated, like reusing an element for 2 calls, then can either Q promise functionality (like then, Q.all or Q sequences), or retrieve your element twice (since the promise chain api is very terse, this is usually acceptable).

    Element function chaining example here

    Waiting for something

    Below are the methods to use to wait for a condition:

    • browser.waitFor(asserter, timeout, pollFreq, cb) -> cb(err, value): generic wait method, the return value is provided by the asserter when the condition is satisfied.
    • browser.waitForElementBy???(value ,asserter, timeout, pollFreq, cb) -> cb(err, el): waits for a element then a condition, then returns the element.
    • browser.waitForConditionInBrowser(conditionExpr, timeout, pollFreq, cb) -> cb(err, boolean): waits for a js condition within a browser, then returns a boolean.

    NOTE: When using waitForConditionInBrowser you must first set the async script timeout using setAsyncScriptTimeout(). For instance:

    // init phase 
    // test 
      .waitForConditionInBrowser("document.querySelectorAll('.foo').length > 0", 10000);

    You should be able to use ready to use asserters, in most cases. Here is a simple example. Please refer to the asserter category in the api doc here.

    Custom asserters should be written using either models below . target may be browser and/or element depending on the context.

    // async 
    var asyncAsserter = new Asserter(
      function(target,cb) {
        cb(err, satisfied, value);
    // promise 
    var promiseAsserter = new Asserter(
      function(target) {
        return promise; // promise resolved with the wait_for return value. 
        // Promise asserter should throw errors marked with `err.retriable=true` 
        // when the condition is not satisfied. 

    Here is a custom asserter example.

    Adding custom methods

    • wd.addAsyncMethod(name, method): This is for regular async methods with callback as the last argument. This will not only add the method to the async browser prototype, but also wrap the method and add it to the promise and promiseChain prototypes.
    • wd.addPromiseMethod(name, method): This is for promise returning methods NOT USING CHAIN internally. This will not only add the method to the promise browser prototype, but also wrap the method and add it to the promiseChain prototype (but not to the async prototype).
    • wd.addPromiseChainMethod(name, method): This is for promise returning methods USING CHAIN internally. This will only add the method to the promiseChain browser prototype (but neither to async nor to promise browser prototypes).

    If you are only using the promise chain api, you should probably stick with wd.addPromiseChainMethod.

    Custom methods may be removed with wd.removeMethod(name). That will remove the method from the 3 prototypes.

    Please refer to the following examples:

    Note: No need to call rewrap anymore.

    Promise helpers

    This is an alternative to adding custom methods. See example here.

    Starting the promise chain

    The browser and element object are not themselves promises (cause that would lead to chaos), so you cannot call Q core methods on them. However you may call one of the method below to initiate the promise chain:

    • browser.chain()
    • browser.noop()
    • browser.resolve(promise)
    • element.chain()
    • element.noop()
    • element.resolve(promise)

    The resolve methods work like Q thenResolve.

    Extra promise methods:

    • at(i): get element from list (starting at 0).
    • nth(i): get element from list (starting at 1).
    • first(): get the first element.
    • second(): get the second element.
    • third(): get the third element.
    • last(): get the last element.
    • printError(prepend): print the previous error, prepend optional
    • print(prepend): print the previous promise result, prepend optional

    NOTE: When using functions such as nth(), first(), second() you must use the "plural" versions of the get functions.

    Working with external promise libraries

    wd uses Q internally, but you may use promises from other libraries with the following methods:

    • browser.resolve(externalPromise)
    • wd.addPromiseChainMethod(name, externalPromise)
    • wd.addPromiseMethod(name, externalPromise)

    The external promise will be automatically wrapped within a Q promise using new Q(externalPromise).

    See example here.

    Http configuration / base url

    Http behaviour and base url may be configured via the configureHttp method as in the code below:

    // global config 
      timeout: 60000,
      retries: 3,
      retryDelay: 100,
      baseUrl: ''
    // per browser config 
      timeout: 60000,
      retries: 3,
      retryDelay: 100,
      baseUrl: ''
    • timeout: http timeout in ms, default is undefined (uses the server timeout, usually 60 seconds). Use 'default' or undefined for server default.
    • retries: Number of reconnection attempts in case the connection is dropped. Default is 3. Pass 0 or always to keep trying. Pass -1 or never to disable.
    • retryDelay: the number of ms to wait before reconnecting. Default is 15.
    • baseUrl: the base url use by the get method. The destination url is computed using url.resolve. Default is empty.
    • If a field is not specified, the current configuration for this field is unchanged.

    Environment variables for Saucelabs

    When connecting to Saucelabs, the user and pwd fields can also be set through the SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables.

    The following helper are also available to update sauce jobs: sauceJobUpdate and sauceJobStatus.

    Safe Methods

    The safeExecute and safeEval methods are equivalent to execute and eval but the code is executed within a eval block. They are safe in the sense that eventual code syntax issues are tackled earlier returning as syntax error and avoiding browser hanging in some cases.

    An example below of expression hanging Chrome:

    browser.eval("wrong!!!", function(err, res) { // hangs 
    browser.safeEval("wrong!!!", function(err, res) { // returns 
    browser.execute("wrong!!!", function(err, res) { //hangs 
    browser.safeExecute("wrong!!!", function(err, res) { //returns 

    Working with mobile device emulators

    It is possible to use wd to test mobile devices using either Selenium or Appium. However in either case the full JsonWire protocol is not supported (or is buggy).

    Examples here.


    Both Android (using AndroidDriver) and ios (using ios-driver) are supported, locally or using Sauce Labs cloud.


    Android and iOS work locally and on Sauce Labs.

    Run the tests!

    # Install the Selenium server, Chromedriver connect
    #Run the selenium server with chromedriver:
    cd wd
    npm install
    make test
    # look at the results!

    Run the tests on Sauce Labs cloud!

    # Install Sauce Connect
    # Set the following env variales: SAUCE_USERNAME and SAUCE_ACCESS_KEY
    # Start Sauce Connect:
    cd wd
    npm install
    make test_e2e_sauce # may be run without sauce connect
    make test_midway_sauce_connect
    # look at the results on Saucelabs site!

    Adding new method / Contributing

    If the method you want to use is not yet implemented, that should be easy to add it to lib/webdriver.js. You can use the doubleclick method as a template for methods not returning data, and getOrientation for methods which returns data. No need to modify README as the doc generation is automated. Other contributions are welcomed.

    Generating doc

    The JsonWire mappings in the README and mapping files are generated from code comments using dox.

    To update the mappings run the following commands:

    make mapping > doc/
    make full_mapping > doc/
    make unsupported_mapping > doc/


    npm version [patch|minor|major]
    git push --tags origin master
    npm publish

    Test Coverage

    test coverage

    Bitdeli Badge




    npm i wd-edge

    Downloadslast 7 days







    last publish


    • avatar