node.js webdriver/selenium 2 client
JavaScript CSS
Switch branches/tags
Nothing to show
Pull request Compare This branch is 762 commits behind admc:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
browser-scripts
doc
examples
lib
test
.gitignore
.jshintrc
.travis.yml
LICENSE.APACHE2
Makefile
README.md
package.json

README.md

WD.js -- WebDriver/Selenium 2 for node.js

Build Status Selenium Test Status

Selenium Test Status

Update node to latest

http://nodejs.org/#download

Install

npm install wd

Authors

License

0.2.x Release

0.2.0

  • New wrapper: promise chain.
  • Old chain api is deprecated (It is still available, but you will see a depreciation message).
  • There are some changes in the way the element and webdriver classes are passed around which may affect external wrappers. External wrappers should now subclass those 2 classes.

0.2.1

  • New test suite using the promise chain api.
  • browser.Q was moved to wd.Q

Usage

Q promises + chaining

var wd = require('wd'),
  assert = require('assert'),
  colors = require('colors'),
  browser = wd.promiseChainRemote();

browser.on('status', function(info) {
  console.log(info.cyan);
});

browser.on('command', function(meth, path, data) {
  console.log(' > ' + meth.yellow, path.grey, data || '');
});

browser.init({
    browserName:'chrome',
    tags : ['examples'],
    name: 'This is an example test'
  })
  .get('http://admc.io/wd/test-pages/guinea-pig.html')
  .title().then(function(title) {
     assert.ok(~title.indexOf('I am a page title - Sauce Labs'), 'Wrong title!');
  })
  .elementById('i am a link')
  .click()
  .eval("window.location.href").then(function(href) {
    assert.ok(~href.indexOf('guinea-pig2'));
  })
  .catch(function(err) {
    console.log(err);
  })
  .sleep(3000)
  .quit()
  .done();

Pure async

var wd = require('wd'),
  assert = require('assert'),
  colors = require('colors'),
  browser = wd.remote();

browser.on('status', function(info) {
  console.log(info.cyan);
});

browser.on('command', function(meth, path, data) {
  console.log(' > ' + meth.yellow, path.grey, data || '');
});

browser.init({
    browserName:'chrome'
    , tags : ['examples']
    , name: 'This is an example test'
  }, function() {

  browser.get('http://admc.io/wd/test-pages/guinea-pig.html', function() {
    browser.title(function(err, title) {
      assert.ok(~title.indexOf('I am a page title - Sauce Labs'), 'Wrong title!');
      browser.elementById('i am a link', function(err, el) {
        browser.clickElement(el, function() {
          browser.eval('window.location.href', function(err, href) {
            assert.ok(~href.indexOf('guinea-pig2'));
            browser.quit();
          });
        });
      });
    });
  });
});

Q promises without chaining

See example here.

Generators Api

Yiewd

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("http://mysite.com");
  el = yield this.elementById("someId");
  yield el.click();
  el2 = yield this.elementById("anotherThing")
  text = yield el2.text();
  text.should.equal("What the text should be");
  yield this.quit();
});

Repl

./node_modules/.bin/wd shell
): wd shell
> x = wd.remote() or wd.remote("ondemand.saucelabs.com", 80, "username", "apikey")

> x.init() or x.init({desired capabilities override})
> x.get("http://www.url.com")
> x.eval("window.location.href", function(e, o) { console.log(o) })
> x.quit()

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("ondemand.saucelabs.com", 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: '127.0.0.1',
  port: 4444,
  user: 'username',
  pwd: 'password',
});
// or
var browser = wd.remote({
  hostname: '127.0.0.1',
  port: 4444,
  auth: 'username:password',
});

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

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

Url string

var browser = wd.remote('http://localhost:4444/wd/hub');
// or
var browser = wd.remote('http://user:apiKey@ondemand.saucelabs.com/wd/hub');

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('http://user:apiKey@ondemand.saucelabs.com:80/wd/hub'));

Defaults

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

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.

Supported Methods

JsonWireProtocol wd
GET /status
Query the server's current status.
status(cb) -> cb(err, status)
POST /session
Create a new session.
init(desired, cb) -> cb(err, sessionID, capabilities)
Initialize the browser.
GET /sessions
Returns a list of the currently active sessions.

sessions(cb) -> cb(err, sessions)

Alternate strategy to get session capabilities from server session list:
altSessionCapabilities(cb) -> cb(err, capabilities)

GET /session/:sessionId
Retrieve the capabilities of the specified session.
sessionCapabilities(cb) -> cb(err, capabilities)
DELETE /session/:sessionId
Delete the session.
quit(cb) -> cb(err)
Destroy the browser.
POST /session/:sessionId/timeouts
Configure the amount of time that a particular type of operation can execute for before they are aborted and a |Timeout| error is returned to the client.
setPageLoadTimeout(ms, cb) -> cb(err)
(use setImplicitWaitTimeout and setAsyncScriptTimeout to set the other timeouts)
POST /session/:sessionId/timeouts/async_script
Set the amount of time, in milliseconds, that asynchronous scripts executed by /session/:sessionId/execute_async are permitted to run before they are aborted and a |Timeout| error is returned to the client.
setAsyncScriptTimeout(ms, cb) -> cb(err)
POST /session/:sessionId/timeouts/implicit_wait
Set the amount of time the driver should wait when searching for elements.
setImplicitWaitTimeout(ms, cb) -> cb(err)
GET /session/:sessionId/window_handle
Retrieve the current window handle.
windowHandle(cb) -> cb(err, handle)
GET /session/:sessionId/window_handles
Retrieve the list of all window handles available to the session.
windowHandles(cb) -> cb(err, arrayOfHandles)
GET /session/:sessionId/url
Retrieve the URL of the current page.
url(cb) -> cb(err, url)
POST /session/:sessionId/url
Navigate to a new URL.
get(url,cb) -> cb(err)
Get a new url.
POST /session/:sessionId/forward
Navigate forwards in the browser history, if possible.
forward(cb) -> cb(err)
POST /session/:sessionId/back
Navigate backwards in the browser history, if possible.
back(cb) -> cb(err)
POST /session/:sessionId/refresh
Refresh the current page.
refresh(cb) -> cb(err)
POST /session/:sessionId/execute
Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame.

execute(code, args, cb) -> cb(err, result)
execute(code, cb) -> cb(err, result)
args: script argument array (optional)

Safely execute script within an eval block, always returning:
safeExecute(code, args, cb) -> cb(err, result)
safeExecute(code, cb) -> cb(err, result)
args: script argument array (optional)

Evaluate expression (using execute):
eval(code, cb) -> cb(err, value)

Safely evaluate expression, always returning (using safeExecute):
safeEval(code, cb) -> cb(err, value)

POST /session/:sessionId/execute_async
Inject a snippet of JavaScript into the page for execution in the context of the currently selected frame.

executeAsync(code, args, cb) -> cb(err, result)
executeAsync(code, cb) -> cb(err, result)
args: script argument array (optional)

Safely execute async script within an eval block, always returning:
safeExecuteAsync(code, args, cb) -> cb(err, result)
safeExecuteAsync(code, cb) -> cb(err, result)
args: script argument array (optional)

GET /session/:sessionId/screenshot
Take a screenshot of the current page.
takeScreenshot(cb) -> cb(err, screenshot)
POST /session/:sessionId/frame
Change focus to another frame on the page.
frame(frameRef, cb) -> cb(err)
POST /session/:sessionId/window
Change focus to another window.
window(name, cb) -> cb(err)
DELETE /session/:sessionId/window
Close the current window.
close(cb) -> cb(err)
POST /session/:sessionId/window/:windowHandle/size
Change the size of the specified window.

windowSize(handle, width, height, cb) -> cb(err)

setWindowSize(width, height, handle, cb) -> cb(err)
setWindowSize(width, height, cb) -> cb(err)
width: width in pixels to set size to
height: height in pixels to set size to
handle: window handle to set size for (optional, default: 'current')

GET /session/:sessionId/window/:windowHandle/size
Get the size of the specified window.
getWindowSize(handle, cb) -> cb(err, size)
getWindowSize(cb) -> cb(err, size)
handle: window handle to get size (optional, default: 'current')
POST /session/:sessionId/window/:windowHandle/position
Change the position of the specified window.
setWindowPosition(x, y, handle, cb) -> cb(err)
setWindowPosition(x, y, cb) -> cb(err)
x: the x-coordinate in pixels to set the window position
y: the y-coordinate in pixels to set the window position
handle: window handle to set position for (optional, default: 'current')
GET /session/:sessionId/window/:windowHandle/position
Get the position of the specified window.
getWindowPosition(handle, cb) -> cb(err, position)
getWindowPosition(cb) -> cb(err, position)
handle: window handle to get position (optional, default: 'current')
POST /session/:sessionId/window/:windowHandle/maximize
Maximize the specified window if not already maximized.
maximize(handle, cb) -> cb(err)
GET /session/:sessionId/cookie
Retrieve all cookies visible to the current page.
allCookies() -> cb(err, cookies)
POST /session/:sessionId/cookie
Set a cookie.
setCookie(cookie, cb) -> cb(err)
cookie example:
{name:'fruit', value:'apple'}
Optional cookie fields:
path, domain, secure, expiry
DELETE /session/:sessionId/cookie
Delete all cookies visible to the current page.
deleteAllCookies(cb) -> cb(err)
DELETE /session/:sessionId/cookie/:name
Delete the cookie with the given name.
deleteCookie(name, cb) -> cb(err)
GET /session/:sessionId/source
Get the current page source.
source(cb) -> cb(err, source)
GET /session/:sessionId/title
Get the current page title.
title(cb) -> cb(err, title)
POST /session/:sessionId/element
Search for an element on the page, starting from the document root.

element(using, value, cb) -> cb(err, element)

elementByClassName(value, cb) -> cb(err, element)
elementByCssSelector(value, cb) -> cb(err, element)
elementById(value, cb) -> cb(err, element)
elementByName(value, cb) -> cb(err, element)
elementByLinkText(value, cb) -> cb(err, element)
elementByPartialLinkText(value, cb) -> cb(err, element)
elementByTagName(value, cb) -> cb(err, element)
elementByXPath(value, cb) -> cb(err, element)
elementByCss(value, cb) -> cb(err, element)

POST /session/:sessionId/elements
Search for multiple elements on the page, starting from the document root.

elements(using, value, cb) -> cb(err, elements)

elementsByClassName(value, cb) -> cb(err, elements)
elementsByCssSelector(value, cb) -> cb(err, elements)
elementsById(value, cb) -> cb(err, elements)
elementsByName(value, cb) -> cb(err, elements)
elementsByLinkText(value, cb) -> cb(err, elements)
elementsByPartialLinkText(value, cb) -> cb(err, elements)
elementsByTagName(value, cb) -> cb(err, elements)
elementsByXPath(value, cb) -> cb(err, elements)
elementsByCss(value, cb) -> cb(err, elements)

Retrieve an element avoiding not found exception and returning null instead:
elementOrNull(using, value, cb) -> cb(err, element)

elementByClassNameOrNull(value, cb) -> cb(err, element)
elementByCssSelectorOrNull(value, cb) -> cb(err, element)
elementByIdOrNull(value, cb) -> cb(err, element)
elementByNameOrNull(value, cb) -> cb(err, element)
elementByLinkTextOrNull(value, cb) -> cb(err, element)
elementByPartialLinkTextOrNull(value, cb) -> cb(err, element)
elementByTagNameOrNull(value, cb) -> cb(err, element)
elementByXPathOrNull(value, cb) -> cb(err, element)
elementByCssOrNull(value, cb) -> cb(err, element)

Retrieve an element avoiding not found exception and returning undefined instead:
elementIfExists(using, value, cb) -> cb(err, element)

elementByClassNameIfExists(value, cb) -> cb(err, element)
elementByCssSelectorIfExists(value, cb) -> cb(err, element)
elementByIdIfExists(value, cb) -> cb(err, element)
elementByNameIfExists(value, cb) -> cb(err, element)
elementByLinkTextIfExists(value, cb) -> cb(err, element)
elementByPartialLinkTextIfExists(value, cb) -> cb(err, element)
elementByTagNameIfExists(value, cb) -> cb(err, element)
elementByXPathIfExists(value, cb) -> cb(err, element)
elementByCssIfExists(value, cb) -> cb(err, element)

Check if element exists:
hasElement(using, value, cb) -> cb(err, boolean)

hasElementByClassName(value, cb) -> cb(err, boolean)
hasElementByCssSelector(value, cb) -> cb(err, boolean)
hasElementById(value, cb) -> cb(err, boolean)
hasElementByName(value, cb) -> cb(err, boolean)
hasElementByLinkText(value, cb) -> cb(err, boolean)
hasElementByPartialLinkText(value, cb) -> cb(err, boolean)
hasElementByTagName(value, cb) -> cb(err, boolean)
hasElementByXPath(value, cb) -> cb(err, boolean)
hasElementByCss(value, cb) -> cb(err, boolean)

POST /session/:sessionId/element/active
Get the element on the page that currently has focus.
active(cb) -> cb(err, element)
POST /session/:sessionId/element/:id/element
Search for an element on the page, starting from the identified element.

element.element(using, value, cb) -> cb(err, element)

element.elementByClassName(value, cb) -> cb(err, element)
element.elementByCssSelector(value, cb) -> cb(err, element)
element.elementById(value, cb) -> cb(err, element)
element.elementByName(value, cb) -> cb(err, element)
element.elementByLinkText(value, cb) -> cb(err, element)
element.elementByPartialLinkText(value, cb) -> cb(err, element)
element.elementByTagName(value, cb) -> cb(err, element)
element.elementByXPath(value, cb) -> cb(err, element)
element.elementByCss(value, cb) -> cb(err, element)

POST /session/:sessionId/element/:id/elements
Search for multiple elements on the page, starting from the identified element.

element.elements(using, value, cb) -> cb(err, elements)

element.elementsByClassName(value, cb) -> cb(err, elements)
element.elementsByCssSelector(value, cb) -> cb(err, elements)
element.elementsById(value, cb) -> cb(err, elements)
element.elementsByName(value, cb) -> cb(err, elements)
element.elementsByLinkText(value, cb) -> cb(err, elements)
element.elementsByPartialLinkText(value, cb) -> cb(err, elements)
element.elementsByTagName(value, cb) -> cb(err, elements)
element.elementsByXPath(value, cb) -> cb(err, elements)
element.elementsByCss(value, cb) -> cb(err, elements)

POST /session/:sessionId/element/:id/click
Click on an element.

clickElement(element, cb) -> cb(err)

element.click(cb) -> cb(err)

POST /session/:sessionId/element/:id/submit
Submit a FORM element.

submit(element, cb) -> cb(err)
Submit a `FORM` element.

element.submit(cb) -> cb(err)

GET /session/:sessionId/element/:id/text
Returns the visible text for the element.

text(element, cb) -> cb(err, text)
element: specific element, 'body', or undefined

element.text(cb) -> cb(err, text)

Check if text is present:
textPresent(searchText, element, cb) -> cb(err, boolean)
element: specific element, 'body', or undefined

element.textPresent(searchText, cb) -> cb(err, boolean)

POST /session/:sessionId/element/:id/value
Send a sequence of key strokes to an element.

type(element, keys, cb) -> cb(err)
Type keys (all keys are up at the end of command).
special key map: wd.SPECIAL_KEYS (see lib/special-keys.js)

element.type(keys, cb) -> cb(err)

POST /session/:sessionId/keys
Send a sequence of key strokes to the active element.
keys(keys, cb) -> cb(err)
Press keys (keys may still be down at the end of command).
special key map: wd.SPECIAL_KEYS (see lib/special-keys.js)
GET /session/:sessionId/element/:id/name
Query for an element's tag name.

getTagName(element, cb) -> cb(err, name)

element.getTagName(cb) -> cb(err, name)

POST /session/:sessionId/element/:id/clear
Clear a TEXTAREA or text INPUT element's value.

clear(element, cb) -> cb(err)

element.clear(cb) -> cb(err)

GET /session/:sessionId/element/:id/selected
Determine if an OPTION element, or an INPUT element of type checkbox or radiobutton is currently selected.

isSelected(element, cb) -> cb(err, selected)

element.isSelected(cb) -> cb(err, selected)

GET /session/:sessionId/element/:id/enabled
Determine if an element is currently enabled.

isEnabled(element, cb) -> cb(err, enabled)

element.isEnabled(cb) -> cb(err, enabled)

GET /session/:sessionId/element/:id/attribute/:name
Get the value of an element's attribute.

getAttribute(element, attrName, cb) -> cb(err, value)

element.getAttribute(attrName, cb) -> cb(err, value)

Get element value (in value attribute):
getValue(element, cb) -> cb(err, value)

element.getValue(cb) -> cb(err, value)

GET /session/:sessionId/element/:id/equals/:other
Test if two element IDs refer to the same DOM element.

element.equals(other, cb) -> cb(err, value)

equalsElement(element, other , cb) -> cb(err, value)

GET /session/:sessionId/element/:id/displayed
Determine if an element is currently displayed.

isDisplayed(element, cb) -> cb(err, displayed)

element.isDisplayed(cb) -> cb(err, displayed)

GET /session/:sessionId/element/:id/location
Determine an element's location on the page.

getLocation(element, cb) -> cb(err, location)

element.getLocation(cb) -> cb(err, location)

element.getLocationInView(cb) -> cb(err, location)

GET /session/:sessionId/element/:id/location_in_view
Determine an element's location on the screen once it has been scrolled into view.
getLocationInView(element, cb) -> cb(err, location)
GET /session/:sessionId/element/:id/size
Determine an element's size in pixels.

getSize(element, cb) -> cb(err, size)

element.getSize(cb) -> cb(err, size)

GET /session/:sessionId/element/:id/css/:propertyName
Query the value of an element's computed CSS property.

getComputedCss(element, cssProperty , cb) -> cb(err, value)

element.getComputedCss(cssProperty , cb) -> cb(err, value)

element.getComputedCss(cssProperty , cb) -> cb(err, value)

GET /session/:sessionId/orientation
Get the current browser orientation.
getOrientation(cb) -> cb(err, orientation)
POST /session/:sessionId/orientation
Set the browser orientation.
setOrientation(cb) -> cb(err, orientation)
GET /session/:sessionId/alert_text
Gets the text of the currently displayed JavaScript alert(), confirm(), or prompt() dialog.
alertText(cb) -> cb(err, text)
POST /session/:sessionId/alert_text
Sends keystrokes to a JavaScript prompt() dialog.
alertKeys(keys, cb) -> cb(err)
POST /session/:sessionId/accept_alert
Accepts the currently displayed alert dialog.
acceptAlert(cb) -> cb(err)
POST /session/:sessionId/dismiss_alert
Dismisses the currently displayed alert dialog.
dismissAlert(cb) -> cb(err)
POST /session/:sessionId/moveto
Move the mouse by an offset of the specificed element.
moveTo(element, xoffset, yoffset, cb) -> cb(err)
Move to element, xoffset and y offset are optional.
POST /session/:sessionId/click
Click any mouse button (at the coordinates set by the last moveto command).
click(button, cb) -> cb(err)
Click on current element.
Buttons: {left: 0, middle: 1 , right: 2}
POST /session/:sessionId/buttondown
Click and hold the left mouse button (at the coordinates set by the last moveto command).
buttonDown(button ,cb) -> cb(err)
button is optional.
{LEFT = 0, MIDDLE = 1 , RIGHT = 2}.
LEFT if not specified.
POST /session/:sessionId/buttonup
Releases the mouse button previously held (where the mouse is currently at).
buttonUp(button, cb) -> cb(err)
button is optional.
{LEFT = 0, MIDDLE = 1 , RIGHT = 2}.
LEFT if not specified.
POST /session/:sessionId/doubleclick
Double-clicks at the current mouse coordinates (set by moveto).

doubleclick(cb) -> cb(err)

element.doubleClick(cb) -> cb(err)

POST /session/:sessionId/touch/click
Single tap on the touch enabled device.

tap(element) -> cb(err)
Taps element

element.tap(cb) -> cb(err)

POST /session/:sessionId/touch/flick
Flick on the touch screen using finger motion events.

flick(xSpeed, ySpeed, swipe, cb) -> cb(err)
Flicks, starting anywhere on the screen.
flick(element, xoffset, yoffset, speed, cb) -> cb(err)
Flicks, starting at element center.

element.flick(xoffset, yoffset, speed, cb) -> cb(err)

POST /session/:sessionId/local_storage
Set the storage item for the given key.
setLocalStorageKey(key, value, cb) -> cb(err)
# uses safeExecute() due to localStorage bug in Selenium
DELETE /session/:sessionId/local_storage
Clear the storage.
clearLocalStorage(cb) -> cb(err)
# uses safeExecute() due to localStorage bug in Selenium
GET /session/:sessionId/local_storage/key/:key
Get the storage item for the given key.
getLocalStorageKey(key, cb) -> cb(err)
# uses safeEval() due to localStorage bug in Selenium
DELETE /session/:sessionId/local_storage/key/:key
Remove the storage item for the given key.
removeLocalStorageKey(key, cb) -> cb(err)
# uses safeExecute() due to localStorage bug in Selenium
POST /session/:sessionId/log
Get the log for a given log type.
log(logType, cb) -> cb(err, arrayOfLogs)
GET /session/:sessionId/log/types
Get available log types.
logTypes(cb) -> cb(err, arrayOfLogTypes)
EXTRA Opens a new window (using Javascript window.open):
newWindow(url, name, cb) -> cb(err)
newWindow(url, cb) -> cb(err)
name: optional window name
Window can later be accessed by name with the window method,
or by getting the last handle returned by the windowHandles method.
EXTRA windowName(cb) -> cb(err, name)
EXTRA setHTTPInactivityTimeout(ms)
ms: how many milliseconds to wait for any communication with the WebDriver server (i.e. any command to complete) before the connection is considered lost
EXTRA waitForElement(using, value, timeout, cb) -> cb(err)
EXTRA waitForVisible(using, value, timeout, cb) -> cb(err)
EXTRA waitForElementByClassName(value, timeout, cb) -> cb(err)
waitForElementByCssSelector(value, timeout, cb) -> cb(err)
waitForElementById(value, timeout, cb) -> cb(err)
waitForElementByName(value, timeout, cb) -> cb(err)
waitForElementByLinkText(value, timeout, cb) -> cb(err)
waitForElementByPartialLinkText(value, timeout, cb) -> cb(err)
waitForElementByTagName(value, timeout, cb) -> cb(err)
waitForElementByXPath(value, timeout, cb) -> cb(err)
waitForElementByCss(value, timeout, cb) -> cb(err)
EXTRA waitForVisibleByClassName(value, timeout, cb) -> cb(err)
waitForVisibleByCssSelector(value, timeout, cb) -> cb(err)
waitForVisibleById(value, timeout, cb) -> cb(err)
waitForVisibleByName(value, timeout, cb) -> cb(err)
waitForVisibleByLinkText(value, timeout, cb) -> cb(err)
waitForVisibleByPartialLinkText(value, timeout, cb) -> cb(err)
waitForVisibleByTagName(value, timeout, cb) -> cb(err)
waitForVisibleByXPath(value, timeout, cb) -> cb(err)
waitForVisibleByCss(value, timeout, cb) -> cb(err)
EXTRA isVisible(element , cb) -> cb(err, boolean)
isVisible(queryType, querySelector, cb) -> cb(err, boolean)
EXTRA Retrieves the pageIndex element (added for Appium):
getPageIndex(element, cb) -> cb(err, pageIndex)
EXTRA Uploads a local file using undocumented
POST /session/:sessionId/file
uploadFile(filepath, cb) -> cb(err, filepath)
EXTRA Waits for JavaScript condition to be true (polling within wd client):
waitForCondition(conditionExpr, timeout, pollFreq, cb) -> cb(err, boolean)
waitForCondition(conditionExpr, timeout, cb) -> cb(err, boolean)
waitForCondition(conditionExpr, cb) -> cb(err, boolean)
conditionExpr: condition expression, should return a boolean
timeout: timeout (optional, default: 1000)
pollFreq: pooling frequency (optional, default: 100)
return true if condition satisfied, error otherwise.
EXTRA Waits for JavaScript condition to be true (async script polling within browser):
waitForConditionInBrowser(conditionExpr, timeout, pollFreq, cb) -> cb(err, boolean)
waitForConditionInBrowser(conditionExpr, timeout, cb) -> cb(err, boolean)
waitForConditionInBrowser(conditionExpr, cb) -> cb(err, boolean)
conditionExpr: condition expression, should return a boolean
timeout: timeout (optional, default: 1000)
pollFreq: pooling frequency (optional, default: 100)
return true if condition satisfied, error otherwise.
EXTRA Equivalent to the python sendKeys binding. Upload file if
a local file is detected, otherwise behaves like type.
element.sendKeys(keys, cb) -> cb(err)
EXTRA isVisible(cb) -> cb(err, boolean)

JsonWireProtocol mapping

supported mapping

full mapping

More docs!

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

Run the tests!

# Install the Selenium server and Chromedriver
node_modules/.bin/install_selenium
node_modules/.bin/install_chromedriver

#Run the selenium server with chromedriver:
node_modules/.bin/start_selenium_with_chromedriver

cd wd
npm install
make test

# look at the results!

Run the tests on Sauce Labs cloud!

cd wd
npm install
make test_e2e_sauce

Monkey patching

You may want to monkey patch the webdriver class in order to add custom functionalities. There is an example here.

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.

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/jsonwire-mapping.md
make full_mapping > doc/jsonwire-full-mapping.md
make unsupported_mapping > doc/jsonwire-unsupported-mapping.md

The content of doc/jsonwire-mapping.md should then be manually integrated into README.md.

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

Test Coverage

test coverage