Repository: nightwatchjs/nightwatch
Pull request #2144 (2019-06-27 15:08:19)

Expose status polling settings
This exposes settings for the selenium server connection, to allow the configuration of the `maxStatusPollTries` value as well and the `statusPollInterval` value.

We ran into issues when using a Selenium server for our Nightwatch tests on Travis because Nightwatch would time out trying to connect to the Selenium server. For now, we are making use of the  `check_process_delay` setting which gives our environment more time to spin up the Selenium server, but this relies on a javascript timeout and a set amount of attempts that cannot be configured. It would be good to let developers configure those values as well to give them more flexibility in their setup.

If anything is missing or this PR does not make sense, please comment and let me know what's wrong or needs to be changed.


Patch:
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index ca75974b..00000000
--- a/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,23 +0,0 @@
-__Please do not ask for assistance in the Issues list.__ Use the [Mailing List](https://groups.google.com/forum/#!forum/nightwatchjs) or [StackOverflow](http://stackoverflow.com/questions/tagged/nightwatch.js) to ask questions and seek help. 
-
-Before submitting a new issues, try searching for a similar one here: https://github.com/nightwatchjs/nightwatch/search?type=Issues and add your scenario there and anything else which you think will help with fixing it;
- 
-## Reporting a bug
-- [ ] Please write an elaborate title which explains the problem as accurate as possible
-  For instance:
-  - __not helpful__: "Issue with tags"
-  - __much better__: "Tags don't work when combined with --skiptags option"
-- [ ] Include a sample test which reproduces the problem you're experiencing. The test should be against a **public url**. The test and other info should be posted inline, attachments will be ignored;
-- [ ] Include the verbose output, if possible (run nightwatch with `--verbose` argument);
-- [ ] Include your configuration (try to leave out the irrelevant bits);
-- [ ] Also include: Nightwatch version, Node.js version, OS version and Webdriver/Selenium Server version;
-- [ ] Please try not to report issues you have with individual browser drivers which cannot or should not be solved in Nightwatch.
-
-## Requesting a feature
-Feature requests are welcome. 
-
-- [ ] Indicate in the issue title that it is a feature/enhancement request
-- [ ] Explain the use case and include a sample test case and/or usage, if possible 
-- [ ] Try to submit enhancements that you cannot build with custom commands/assertions and something that will benefit the community
-
-Please make sure you've formatted the code samples, verbose output, configuration and other inline debug information (use the __Preview__  functionality). Check out the GitHub Markdown guide: https://guides.github.com/features/mastering-markdown/
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..ecbedf68
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,67 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ""
+labels: ''
+assignees: ''
+
+---
+
+## Describe the bug
+<!--
+A clear and concise description of what the bug is. Please make sure to format the code samples, verbose output, configuration and other inline debug information (use the __Preview__  functionality). Check out the [GitHub Markdown guide](https://guides.github.com/features/mastering-markdown/).
+-->
+
+## How To Reproduce
+<!-- 
+Include a sample test which reproduces the problem you're experiencing. The test should be against a **public url**. The test and other info should be posted inline.
+-->
+
+**Sample test:**
+
+```js
+module.exports = {
+  sampleTest: function(browser) {
+
+  }
+}
+```
+
+**Run with command**
+<!--
+Include the command used to run the test, if applicable.
+-->
+```sh
+$ nightwatch test/sampleTest.js --your-other-arguments-here
+```
+
+**Verbose output**
+<!--
+Include the verbose output, if possible (run nightwatch with `--verbose` argument)
+-->
+```sh
+# your output here
+```
+
+**Configuration**
+<!-- try to leave out the irrelevant bits -->
+```js
+{
+  "your": { "config": "here" }
+}
+```
+
+## Expected behavior
+A clear and concise description of what you expected to happen.
+
+## Your Environment:
+Please include the following:
+ - Nightwatch version
+ - Node.js version
+ - OS: [e.g. Windows 10]
+ - Browser driver [chromedriver, safaridriver, geckodriver, or microsoftedge]
+ - Browser driver version [e.g. 75]
+ - Selenium server version (if applicable)
+
+## Additional context
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..672afc62
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,23 @@
+---
+name: Feature request
+about: Suggest an enhancement for Nightwatch
+title: "[Enhancement]"
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+<!-- A clear and concise description of what the problem is. -->
+
+**Describe the solution you'd like**
+<!-- Explain the use case in detail. -->
+
+**Describe how the solution will work**
+<!--And include a sample test case and/or usage, if applicable. -->
+
+**Describe alternatives you've considered**
+<!-- A clear and concise description of any alternative solutions or features you've considered, if there are any available.-->
+
+**Additional context**
+<!-- Add any other context or screenshots about the feature request here.-->
diff --git a/.gitignore b/.gitignore
index f07e6478..c3064447 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,6 @@ output
 /coverage/
 /.nyc_output/
 screenshot.png
+/sample
+/screens
+
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..c3bfa81f
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,57 @@
+# Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, gender, gender identity and expression, sex characteristics, disability, ethnicity, level of experience, education, socio-economic status, nationality, personal appearance, body size, race, religion (or lack thereof), or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language - please read the [inclusive language guidance](https://www.uua.org/lgbtq/welcoming/ways/200008.shtml) from the UUA
+* Being respectful of differing viewpoints and experiences
+* Showing empathy towards other community members
+* Gracefully accepting constructive criticism
+* Exercising consideration and respect in your speech and actions
+* Attempting collaboration before conflict or criticism
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, spamming, intentionally disrupting conversations, making insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing or threatening to publish others' private information, such as a physical or electronic address, without explicit permission
+* Advocating for, or encouraging, any of the above behavior
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@pineview.io. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html. 
+
+It's inspired among other things by:
+- [Citizen Code of Conduct](http://citizencodeofconduct.org/)
+- [Appim](https://github.com/appium/appium/blob/master/CONDUCT.md)
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq
diff --git a/README.md b/README.md
index 73ea6dba..1342faaa 100644
--- a/README.md
+++ b/README.md
@@ -1,21 +1,24 @@
-# Nightwatch
+# Nightwatch.js
 
-#### [Homepage](http://nightwatchjs.org) | [Getting Started](http://nightwatchjs.org/gettingstarted) | [Developer Guide](http://nightwatchjs.org/guide) | [API Reference](http://nightwatchjs.org/api) | [Twitter](https://twitter.com/nightwatchjs) |  [OpenCollective](https://opencollective.com/nightwatch)
+#### [Homepage](https://nightwatchjs.org) | [Getting Started](https://nightwatchjs.org/gettingstarted) | [Developer Guide](https://nightwatchjs.org/guide) | [API Reference](https://nightwatchjs.org/api) | [About](https://nightwatchjs.org/about)
 ***
-Automated testing framework powered by [Node.js](http://nodejs.org/) and using [W3C Webdriver](https://www.w3.org/TR/webdriver/) (formerly [Selenium](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol)).
+Automated end-to-end testing framework powered by [Node.js](http://nodejs.org/) and using [W3C Webdriver](https://www.w3.org/TR/webdriver/) (formerly [Selenium](https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol)).
 
 Nightwatch is a complete and integrated solution for end-to-end testing of web applications and websites, and also for Node.js unit and integration testing. 
 
 [![npm](https://img.shields.io/npm/v/nightwatch.svg)](https://www.npmjs.com/package/nightwatch)
 [![Build Status](https://travis-ci.org/nightwatchjs/nightwatch.svg?branch=master)](https://travis-ci.org/nightwatchjs/nightwatch) 
 [![Coverage Status](https://coveralls.io/repos/nightwatchjs/nightwatch/badge.svg?branch=master&service=github)](https://coveralls.io/github/nightwatchjs/nightwatch?branch=master)
-[![Greenkeeper badge](https://badges.greenkeeper.io/nightwatchjs/nightwatch.svg)](https://greenkeeper.io/)
+[![npm package](https://img.shields.io/npm/dm/nightwatch.svg)](https://www.npmjs.com/package/nightwatch)
+[![Twitter Follow](https://img.shields.io/twitter/follow/nightwatchjs.svg?style=social)](https://twitter.com/nightwatchjs)
+
+[Changelog](https://github.com/nightwatchjs/nightwatch/releases) | [Mailing List](https://groups.google.com/forum/#!forum/nightwatchjs) | [nightwatch.js tag on StackOverflow](https://stackoverflow.com/questions/tagged/nightwatch.js)
 ***
 
-## Nightwatch v1.1
-We're delighted to announce the release of __Nightwatch v1.1__. Please see the [upgrade guide](https://github.com/nightwatchjs/nightwatch/wiki/Migrating-to-Nightwatch-1.0) if you are upgrading from an pre v1.0 version. 
+## Nightwatch v1.2
+We're delighted to announce the release of __Nightwatch v1.2__. Please see the [upgrade guide](https://github.com/nightwatchjs/nightwatch/wiki/Migrating-to-Nightwatch-1.0) if you are upgrading from a pre v1.0 version. 
 
-## 1. Install Nightwatch
+### 1. Install Nightwatch
 
 __From [NPM](https://npmjs.com/package/nightwatch):__
 ```sh
@@ -30,7 +33,7 @@ $ cd nightwatch
 $ npm install
 ```
 
-## 2. Download WebDriver
+### 2. Download WebDriver
 
 Nightwatch uses a [WebDriver](https://www.w3.org/TR/webdriver/) compatible server to control the browser. WebDriver is a W3C specification and industry standard which provides a platform and HTTP protocol to interact with a browser.
    
@@ -59,16 +62,16 @@ desiredCapabilities : {
 
 > It's important to note that, while the Selenium Server was required with older Nightwatch versions (`v0.9` and prior), starting with version `1.0` Selenium is no longer necessary.
 
-## Setup Guides
 Specific WebDriver setup guides can be found on the [Docs website](http://nightwatchjs.org/gettingstarted/#browser-drivers-setup). Legacy Selenium drivers setup guides along with debugging instructions can be found on the [**Wiki**](https://github.com/nightwatchjs/nightwatch/wiki).
 
-### Example tests
-Various example tests are included in the [`examples`](https://github.com/nightwatchjs/nightwatch/tree/master/examples) folder which demonstrate the usage of several Nightwatch features. 
+## Examples
+Example tests are included in the [`examples`](https://github.com/nightwatchjs/nightwatch/tree/master/examples) folder which demonstrate the usage of several Nightwatch features. 
+
+You can also check out the [nightwatch-website-tests](https://github.com/nightwatchjs/nightwatch-website-tests) repo for example tests against the [nightwatchjs.org](https://nightwatchjs.org) website.
 
-#### Example configuration
 A sample [`nightwatch.json`](https://github.com/nightwatchjs/nightwatch/blob/master/bin/nightwatch.json) config file can be found in `bin` folder.
 
-#### Nightwatch unit tests
+## Nightwatch unit tests
 The tests for Nightwatch are written using [Mocha](http://mochajs.org/).
 
 To run the complete test suite:
@@ -84,16 +87,9 @@ $ npm run mocha-coverage
 ```
 and then open the generated _coverage/index.html_ file in your browser.
 
-## Changelog
-The release history and changelog is available on the [GitHub Releases](https://github.com/nightwatchjs/nightwatch/releases) page.
-
-#### Updates
-We use [Twitter](https://twitter.com/nightwatchjs) to communicate updates regarding development and to announce releases. Follow [@nightwatchjs](https://twitter.com/nightwatchjs) to get the latest or if you wish to get in touch. 
-
-#### Discuss / Support
-The [Mailing List/Google Group](https://groups.google.com/forum/#!forum/nightwatchjs) is the most appropriate tool for Nightwatch related discussions. In addition, there is a [StackOverflow Nightwatch.js tag](http://stackoverflow.com/questions/tagged/nightwatch.js) at your disposal.
+## Support Nightwatch
+Nightwatch is built by [@pineviewlabs](https://github.com/pineviewlabs/) - an independent software consultancy based in Oslo, Norway, with help from [our contributors](https://github.com/nightwatchjs/nightwatch/graphs/contributors). 
 
-## Support Nightwatch on OpenCollective
-Please consider supporting Nightwatch by becoming a backer on the [OpenCollective](https://opencollective.com/nightwatch/) platform.
+Please consider supporting Nightwatch by becoming a backer or sponsor on the [OpenCollective](https://opencollective.com/nightwatch/) platform.
 
 [![Open Collective](https://opencollective.com/nightwatch/tiers/backers.svg?avatarHeight=60)](https://opencollective.com/nightwatch/contribute/tier/7349-backers)
diff --git a/lib/api-loader/_base-loader.js b/lib/api-loader/_base-loader.js
index 47cb5e42..f36f05e3 100644
--- a/lib/api-loader/_base-loader.js
+++ b/lib/api-loader/_base-loader.js
@@ -155,6 +155,7 @@ class BaseLoader extends EventEmitter {
     }
 
     this.commandName = path.basename(fileName, VALID_FILENAME_EXT);
+    this.fileName = path.join(dirPath, fileName);
 
     try {
       this.module = require(path.join(dirPath, fileName));
diff --git a/lib/api-loader/assertion-loader.js b/lib/api-loader/assertion-loader.js
index abb2c17b..8f1ca308 100644
--- a/lib/api-loader/assertion-loader.js
+++ b/lib/api-loader/assertion-loader.js
@@ -3,6 +3,7 @@ const EventEmitter = require('events');
 const Utils = require('../util/utils.js');
 const BaseCommandLoader = require('./_base-loader.js');
 const AssertionRunner = require('./assertion-runner.js');
+const Element = require('../element/element.js');
 
 class AssertionLoader extends BaseCommandLoader {
   static get interfaceMethods() {
@@ -15,17 +16,34 @@ class AssertionLoader extends BaseCommandLoader {
     };
   }
 
-  static createInstance({nightwatchInstance, module, args}) {
+  static createInstance({nightwatchInstance, module, fileName, args}) {
     const AssertionModule = module.assertion;
     util.inherits(AssertionModule, EventEmitter);
 
     class AssertionInstance extends AssertionModule {
       constructor() {
         super(...args);
+
         this.message = String(this.message);
         EventEmitter.prototype.constructor.call(this);
       }
 
+      set args(value) {
+        throw new Error(`Attempting to override ".args" which is a reserved property in "${fileName}".`);
+      }
+
+      set elementSelector(value) {
+        throw new Error(`Attempting to override ".elementSelector" which is a reserved property in "${fileName}".`);
+      }
+
+      set api(value) {
+        throw new Error(`Attempting to override ".api" which is a reserved property in "${fileName}".`);
+      }
+
+      get args() {
+        return args;
+      }
+
       get api() {
         return nightwatchInstance.api;
       }
@@ -36,6 +54,18 @@ class AssertionLoader extends BaseCommandLoader {
       get client() {
         return nightwatchInstance.client;
       }
+
+      get elementSelector() {
+        if (this.args[0] instanceof Element) {
+          return this.args[0].toString();
+        }
+
+        if (Utils.isObject(this.args[0]) && this.args[0].selector) {
+          return this.args[0].selector || '';
+        }
+
+        return this.args[0];
+      }
     }
 
     const instance = new AssertionInstance();
@@ -93,10 +123,11 @@ class AssertionLoader extends BaseCommandLoader {
               args[0] = elementResult;
             }
 
-            const {nightwatchInstance, reporter, abortOnFailure, module} = this;
+            const {nightwatchInstance, reporter, abortOnFailure, module, fileName} = this;
             const instance = AssertionLoader.createInstance({
               nightwatchInstance,
               module,
+              fileName,
               args
             });
 
diff --git a/lib/api/assertions/attributeContains.js b/lib/api/assertions/attributeContains.js
index af20576b..5ed3104e 100644
--- a/lib/api/assertions/attributeContains.js
+++ b/lib/api/assertions/attributeContains.js
@@ -8,7 +8,7 @@
  * ```
  *
  * @method attributeContains
- * @param {string} selector The selector (CSS / Xpath) used to locate the element.
+ * @param {string|object} selector The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties).
  * @param {string} attribute The attribute name
  * @param {string} expected The expected contained value of the attribute to check.
  * @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
@@ -16,12 +16,13 @@
  */
 
 const util = require('util');
-exports.assertion = function(selector, attribute, expected, msg) {
+
+exports.assertion = function(definition, attribute, expected, msg) {
   const DEFAULT_MSG = 'Testing if attribute %s of <%s> contains "%s".';
   const MSG_ELEMENT_NOT_FOUND = `${DEFAULT_MSG} Element could not be located.`;
   const MSG_ATTR_NOT_FOUND = `${DEFAULT_MSG} Element does not have a ${attribute} attribute.`;
 
-  this.message = msg || util.format(DEFAULT_MSG, attribute, selector, expected);
+  this.message = msg || util.format(DEFAULT_MSG, attribute, this.elementSelector, expected);
 
   this.expected = function() {
     return expected;
@@ -41,7 +42,7 @@ exports.assertion = function(selector, attribute, expected, msg) {
       if (result && result.value === null) {
         defaultMsg = MSG_ATTR_NOT_FOUND;
       }
-      this.message = msg || util.format(defaultMsg, attribute, selector, expected);
+      this.message = msg || util.format(defaultMsg, attribute, this.elementSelector, expected);
     }
 
     return failed;
@@ -52,7 +53,7 @@ exports.assertion = function(selector, attribute, expected, msg) {
   };
 
   this.command = function(callback) {
-    return this.api.getAttribute(selector, attribute, callback);
+    return this.api.getAttribute(definition, attribute, callback);
   };
 
 };
diff --git a/lib/api/assertions/attributeEquals.js b/lib/api/assertions/attributeEquals.js
index 9884c6c0..f66a4414 100644
--- a/lib/api/assertions/attributeEquals.js
+++ b/lib/api/assertions/attributeEquals.js
@@ -21,7 +21,7 @@ exports.assertion = function(selector, attribute, expected, msg) {
   const MSG_ELEMENT_NOT_FOUND = `${DEFAULT_MSG} Element could not be located.`;
   const MSG_ATTR_NOT_FOUND = `${DEFAULT_MSG} Element does not have a ${attribute} attribute.`;
 
-  this.message = msg || util.format(DEFAULT_MSG, attribute, selector, expected);
+  this.message = msg || util.format(DEFAULT_MSG, attribute, this.elementSelector, expected);
 
   this.expected = function() {
     return expected;
@@ -41,7 +41,7 @@ exports.assertion = function(selector, attribute, expected, msg) {
       if (result && result.value === null) {
         defaultMsg = MSG_ATTR_NOT_FOUND;
       }
-      this.message = msg || util.format(defaultMsg, attribute, selector, expected);
+      this.message = msg || util.format(defaultMsg, attribute, this.elementSelector, expected);
     }
 
     return failed;
diff --git a/lib/api/assertions/containsText.js b/lib/api/assertions/containsText.js
index 7612a015..7567ea03 100644
--- a/lib/api/assertions/containsText.js
+++ b/lib/api/assertions/containsText.js
@@ -19,7 +19,7 @@ exports.assertion = function(selector, expectedText, msg) {
   const MSG_ELEMENT_NOT_FOUND = 'Testing if element <%s> contains text: "%s". ' +
     'Element could not be located.';
 
-  this.message = msg || util.format('Testing if element <%s> contains text: "%s".', selector, expectedText);
+  this.message = msg || util.format('Testing if element <%s> contains text: "%s".', this.elementSelector, expectedText);
 
   this.expected = function() {
     return expectedText;
@@ -32,7 +32,7 @@ exports.assertion = function(selector, expectedText, msg) {
   this.failure = function(result) {
     let failed = result === false || result && result.status === -1;
     if (failed) {
-      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector, expectedText);
+      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, this.elementSelector, expectedText);
     }
 
     return failed;
diff --git a/lib/api/assertions/cssClassNotPresent.js b/lib/api/assertions/cssClassNotPresent.js
index f662cd6e..ef08ffbe 100644
--- a/lib/api/assertions/cssClassNotPresent.js
+++ b/lib/api/assertions/cssClassNotPresent.js
@@ -19,7 +19,7 @@ exports.assertion = function(selector, className, msg) {
   const MSG_ELEMENT_NOT_FOUND = 'Testing if element <%s> does not have css class: "%s". ' +
     'Element could not be located.';
 
-  this.message = msg || util.format('Testing if element <%s> does not have css class: "%s".', selector, className);
+  this.message = msg || util.format('Testing if element <%s> does not have css class: "%s".', this.elementSelector, className);
 
   this.expected = function() {
     return 'without ' + className;
@@ -35,7 +35,7 @@ exports.assertion = function(selector, className, msg) {
     let failed = result === false || result && result.status === -1;
 
     if (failed) {
-      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector, className);
+      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, this.elementSelector, className);
     }
 
     return failed;
diff --git a/lib/api/assertions/cssClassPresent.js b/lib/api/assertions/cssClassPresent.js
index 557f879a..48033ef8 100644
--- a/lib/api/assertions/cssClassPresent.js
+++ b/lib/api/assertions/cssClassPresent.js
@@ -19,7 +19,7 @@ exports.assertion = function(selector, className, msg) {
   const MSG_ELEMENT_NOT_FOUND = 'Testing if element <%s> has css class: "%s". ' +
     'Element could not be located.';
 
-  this.message = msg || util.format('Testing if element <%s> has css class: "%s".', selector, className);
+  this.message = msg || util.format('Testing if element <%s> has css class: "%s".', this.elementSelector, className);
 
   this.expected = function() {
     return 'has ' + className;
@@ -34,7 +34,7 @@ exports.assertion = function(selector, className, msg) {
   this.failure = function(result) {
     let failed = result === false || result && result.status === -1;
     if (failed) {
-      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector, className);
+      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, this.elementSelector, className);
     }
 
     return failed;
diff --git a/lib/api/assertions/cssProperty.js b/lib/api/assertions/cssProperty.js
index e651240f..823a4cb3 100644
--- a/lib/api/assertions/cssProperty.js
+++ b/lib/api/assertions/cssProperty.js
@@ -20,7 +20,7 @@ exports.assertion = function(selector, cssProperty, expected, msg) {
   const MSG_ELEMENT_NOT_FOUND = 'Testing if element <%s> has css property %s. ' +
     'Element or attribute could not be located.';
 
-  this.message = msg || util.format('Testing if element <%s> has css property "%s: %s".', selector, cssProperty, expected);
+  this.message = msg || util.format('Testing if element <%s> has css property "%s: %s".', this.elementSelector, cssProperty, expected);
   this.expected = expected;
 
   this.pass = function(value) {
@@ -30,7 +30,7 @@ exports.assertion = function(selector, cssProperty, expected, msg) {
   this.failure = function(result) {
     let failed = result === false || result && result.status === -1;
     if (failed) {
-      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector, cssProperty);
+      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, this.elementSelector, cssProperty);
     }
 
     return failed;
diff --git a/lib/api/assertions/elementNotPresent.js b/lib/api/assertions/elementNotPresent.js
index 902ba938..2a29777f 100644
--- a/lib/api/assertions/elementNotPresent.js
+++ b/lib/api/assertions/elementNotPresent.js
@@ -19,7 +19,7 @@ const Element = require('../../element/element.js');
 exports.assertion = function(selector, msg) {
   this.expected = 'not present';
   this.element = Element.createFromSelector(selector, this.client.locateStrategy);
-  this.message = msg || util.format('Testing if element <%s> is not present.', selector);
+  this.message = msg || util.format('Testing if element <%s> is not present.', this.element);
 
   this.pass = function(value) {
     return value === 'not present';
diff --git a/lib/api/assertions/hidden.js b/lib/api/assertions/hidden.js
index 5a9b2539..9418ba51 100644
--- a/lib/api/assertions/hidden.js
+++ b/lib/api/assertions/hidden.js
@@ -18,7 +18,7 @@ const MSG_ELEMENT_NOT_FOUND = 'Testing if element <%s> is hidden. ' +
   'Element could not be located.';
 
 exports.assertion = function(selector, msg) {
-  this.message = msg || util.format('Testing if element <%s> is hidden.', selector);
+  this.message = msg || util.format('Testing if element <%s> is hidden.', this.elementSelector);
   this.expected = true;
 
   this.pass = function(value) {
@@ -28,7 +28,7 @@ exports.assertion = function(selector, msg) {
   this.failure = function(result) {
     let failed = result === false || result && result.status === -1;
     if (failed) {
-      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector);
+      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, this.elementSelector);
     }
 
     return failed;
diff --git a/lib/api/assertions/value.js b/lib/api/assertions/value.js
index c2a95fb7..97cafeec 100644
--- a/lib/api/assertions/value.js
+++ b/lib/api/assertions/value.js
@@ -19,7 +19,7 @@ exports.assertion = function(selector, expected, msg) {
   const MSG_ELEMENT_NOT_FOUND = 'Testing if value of <%s> equals: "%s". ' +
     'Element or attribute could not be located.';
 
-  this.message = msg || util.format('Testing if value of <%s> equals: "%s".', selector, expected);
+  this.message = msg || util.format('Testing if value of <%s> equals: "%s".', this.elementSelector, expected);
   this.expected = expected;
 
   this.pass = function(value) {
@@ -32,8 +32,9 @@ exports.assertion = function(selector, expected, msg) {
       result && result.status === -1 ||
       // element doesn't have a value attribute
       result && result.value === null;
+
     if (failed) {
-      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector, expected);
+      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, this.elementSelector, expected);
     }
 
     return failed;
diff --git a/lib/api/assertions/valueContains.js b/lib/api/assertions/valueContains.js
index 3291d48d..1362db04 100644
--- a/lib/api/assertions/valueContains.js
+++ b/lib/api/assertions/valueContains.js
@@ -15,12 +15,12 @@
  */
 
 const util = require('util');
-exports.assertion = function(selector, expected, msg) {
+exports.assertion = function(definition, expected, msg) {
   const DEFAULT_MSG = 'Testing if value of <%s> contains: "%s".';
   const MSG_ELEMENT_NOT_FOUND = DEFAULT_MSG + ' ' + 'Element could not be located.';
   const VALUE_ATTR_NOT_FOUND = DEFAULT_MSG + ' ' +  'Element does not have a value attribute.';
 
-  this.message = msg || util.format(DEFAULT_MSG, selector, expected);
+  this.message = msg || util.format(DEFAULT_MSG, this.elementSelector, expected);
   this.expected = true;
 
   this.pass = function(value) {
@@ -37,7 +37,7 @@ exports.assertion = function(selector, expected, msg) {
       if (result && result.value === null) {
         defaultMsg = VALUE_ATTR_NOT_FOUND;
       }
-      this.message = msg || util.format(defaultMsg, selector, expected);
+      this.message = msg || util.format(defaultMsg, this.elementSelector, expected);
     }
 
     return failed;
@@ -48,7 +48,7 @@ exports.assertion = function(selector, expected, msg) {
   };
 
   this.command = function(callback) {
-    return this.api.getValue(selector, callback);
+    return this.api.getValue(definition, callback);
   };
 
 };
diff --git a/lib/api/assertions/visible.js b/lib/api/assertions/visible.js
index a6de17a2..78e6465b 100644
--- a/lib/api/assertions/visible.js
+++ b/lib/api/assertions/visible.js
@@ -2,23 +2,24 @@
  * Checks if the given element is visible on the page.
  *
  * ```
- *    this.demoTest = function (client) {
- *      browser.assert.visible(".should_be_visible");
- *    };
+ * this.demoTest = function (client) {
+ *   browser.assert.visible('.should_be_visible');
+ *   browser.assert.visible({selector: '.should_be_visible'});
+ *   browser.assert.visible({selector: '.should_be_visible', suppressNotFoundErrors: true});
+ * };
  * ```
  *
  * @method visible
- * @param {string} selector The selector (CSS / Xpath) used to locate the element.
+ * @param {string|object} selector The selector (CSS / Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties).
  * @param {string} [message] Optional log message to display in the output. If missing, one is displayed by default.
  * @api assertions
  */
-
 const util = require('util');
 const MSG_ELEMENT_NOT_FOUND = 'Testing if element <%s> is visible. ' +
   'Element could not be located.';
 
-exports.assertion = function(selector, msg) {
-  this.message = msg || util.format('Testing if element <%s> is visible.', selector);
+exports.assertion = function(definition, msg) {
+  this.message = msg || util.format('Testing if element <%s> is visible.', this.elementSelector);
   this.expected = true;
 
   this.pass = function(value) {
@@ -28,7 +29,7 @@ exports.assertion = function(selector, msg) {
   this.failure = function(result) {
     let failed = result === false || result && result.status === -1;
     if (failed) {
-      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, selector);
+      this.message = msg || util.format(MSG_ELEMENT_NOT_FOUND, this.elementSelector);
     }
 
     return failed;
@@ -39,7 +40,7 @@ exports.assertion = function(selector, msg) {
   };
 
   this.command = function(callback) {
-    return this.api.isVisible(selector, callback);
+    return this.api.isVisible(definition, callback);
   };
 
 };
diff --git a/lib/api/client-commands/_baseCommand.js b/lib/api/client-commands/_baseCommand.js
index 20f4109e..9e02489b 100644
--- a/lib/api/client-commands/_baseCommand.js
+++ b/lib/api/client-commands/_baseCommand.js
@@ -8,7 +8,7 @@ module.exports = class ClientCommand {
    * @param {boolean} fullResultObject Weather to call the user-supplied callback with the entire result object or just the value
    * @return {Promise}
    */
-  static makePromise({performAction, userSuppliedCallback = function() {}, fullResultObject = true}) {
+  static makePromise({performAction, userSuppliedCallback = function() {}, fullResultObject = true, fullPromiseResolve = true}) {
     return new Promise(function(resolve, reject) {
       performAction(function(result) {
         try {
@@ -16,12 +16,14 @@ module.exports = class ClientCommand {
             Logger.error(new Error(result.error));
           }
 
-          let promise = userSuppliedCallback.call(this, fullResultObject ? result : result.value);
+          const resultValue = fullResultObject ? result : result.value;
+          let promise = userSuppliedCallback.call(this, resultValue);
           if (!(promise instanceof Promise)) {
             promise = Promise.resolve(promise);
           }
 
-          promise.then(_ => resolve(result)).catch(err => reject(err));
+          const resolveValue = fullPromiseResolve ? result : result.value;
+          promise.then(_ => resolve(resolveValue)).catch(err => reject(err));
         } catch (e) {
           reject(e);
         }
@@ -30,7 +32,11 @@ module.exports = class ClientCommand {
   }
 
   get returnsFullResultObject() {
-    return false;
+    return true;
+  }
+
+  get resolvesWithFullResultObject() {
+    return true;
   }
 
   command(userSuppliedCallback) {
@@ -39,7 +45,8 @@ module.exports = class ClientCommand {
     return ClientCommand.makePromise({
       performAction: performAction.bind(this),
       userSuppliedCallback,
-      fullResultObject: this.returnsFullResultObject
+      fullResultObject: this.returnsFullResultObject,
+      fullPromiseResolve: this.resolvesWithFullResultObject
     });
   }
 };
diff --git a/lib/api/client-commands/getCookie.js b/lib/api/client-commands/getCookie.js
index 26f3d864..ce8d9f44 100644
--- a/lib/api/client-commands/getCookie.js
+++ b/lib/api/client-commands/getCookie.js
@@ -23,6 +23,14 @@ const ClientCommand = require('./_baseCommand.js');
  * @returns {object|null} The cookie object as a selenium cookie JSON object or null if the cookie wasn't found.
  */
 class GetCookie extends ClientCommand {
+  get returnsFullResultObject() {
+    return false;
+  }
+
+  get resolvesWithFullResultObject() {
+    return false;
+  }
+
   /**
    * Perform the .cookie() protocol action and pass the result to the supplied callback
    *  with the original "this" context
diff --git a/lib/api/client-commands/getCookies.js b/lib/api/client-commands/getCookies.js
index 0f43f3bf..4ea68e05 100644
--- a/lib/api/client-commands/getCookies.js
+++ b/lib/api/client-commands/getCookies.js
@@ -23,10 +23,6 @@ const ClientCommand = require('./_baseCommand.js');
  */
 
 class GetCookies extends ClientCommand {
-  get returnsFullResultObject() {
-    return true;
-  }
-
   performAction(callback) {
     this.api.cookie('GET', callback);
   }
diff --git a/lib/api/client-commands/getLog.js b/lib/api/client-commands/getLog.js
index 5d934ba5..1ef428f2 100644
--- a/lib/api/client-commands/getLog.js
+++ b/lib/api/client-commands/getLog.js
@@ -22,6 +22,14 @@ const ClientCommand = require('./_baseCommand.js');
  * @see getLogTypes
  */
 class GetLog extends ClientCommand {
+  get returnsFullResultObject() {
+    return false;
+  }
+
+  get resolvesWithFullResultObject() {
+    return false;
+  }
+
   performAction(actionCallback) {
     this.api.sessionLog(this.typeString, actionCallback);
   }
diff --git a/lib/api/client-commands/getLogTypes.js b/lib/api/client-commands/getLogTypes.js
index e805c8e5..a6c3c68a 100644
--- a/lib/api/client-commands/getLogTypes.js
+++ b/lib/api/client-commands/getLogTypes.js
@@ -19,6 +19,13 @@ const ClientCommand = require('./_baseCommand.js');
  * @see sessionLogTypes
  */
 class GetLogTypes extends ClientCommand {
+  get returnsFullResultObject() {
+    return false;
+  }
+
+  get resolvesWithFullResultObject() {
+    return false;
+  }
 
   performAction(actionCallback) {
     this.api.sessionLogTypes(actionCallback);
diff --git a/lib/api/client-commands/getWindowPosition.js b/lib/api/client-commands/getWindowPosition.js
new file mode 100644
index 00000000..aadcc340
--- /dev/null
+++ b/lib/api/client-commands/getWindowPosition.js
@@ -0,0 +1,45 @@
+const ClientCommand = require('./_baseCommand.js');
+
+/**
+ * Retrieves the current window position.
+ *
+ * For clients which are compatible with the [W3C Webdriver API](https://w3c.github.io/webdriver/), `getWindowPosition` is an alias of `getWindowRect`.
+ *
+ * The `getWindowRect` command returns both dimensions and position of the window, using the `windowRect` protocol command.
+ *
+ * @example
+ * module.exports = {
+ *   'demo test .getWindowPosition()': function(browser) {
+ *      // Retrieve the attributes
+ *      browser.getWindowPosition(function(value) {
+ *        console.log(value);
+ *      });
+ *   },
+ *
+ *   'getWindowPosition ES6 demo test': async function(browser) {
+ *      const value = await browser.getWindowPosition();
+ *      console.log('value', value);
+ *   }
+ * }
+ *
+ * @method getWindowPosition
+ * @syntax .getWindowPosition([callback])
+ * @param {function} callback Callback function to be called when the command finishes.
+ * @see windowRect
+ * @api protocol.contexts
+ */
+class GetWindowPosition extends ClientCommand {
+  get returnsFullResultObject() {
+    return false;
+  }
+
+  get resolvesWithFullResultObject() {
+    return false;
+  }
+
+  performAction(callback) {
+    this.api.windowPosition('current', callback);
+  }
+}
+
+module.exports = GetWindowPosition;
diff --git a/lib/api/client-commands/getWindowRect.js b/lib/api/client-commands/getWindowRect.js
new file mode 100644
index 00000000..58ee7871
--- /dev/null
+++ b/lib/api/client-commands/getWindowRect.js
@@ -0,0 +1,50 @@
+const ClientCommand = require('./_baseCommand.js');
+
+/**
+ * Change or get the [window rect](https://w3c.github.io/webdriver/#dfn-window-rect). This is defined as a dictionary of the `screenX`, `screenY`, `outerWidth` and `outerHeight` attributes of the window.
+ *
+ * Its JSON representation is the following:
+ * - `x` - window's screenX attribute;
+ * - `y` - window's screenY attribute;
+ * - `width` - outerWidth attribute;
+ * - `height` - outerHeight attribute.
+ *
+ * All attributes are in in CSS pixels. To change the window react, you can either specify `width` and `height`, `x` and `y` or all properties together.
+ *
+ * @example
+ * module.exports = {
+ *   'demo test .getWindowRect()': function(browser) {
+ *      // Retrieve the attributes
+ *      browser.getWindowRect(function(value) {
+ *        console.log(value);
+ *      });
+ *   },
+ *
+ *   'getWindowRect ES6 demo test': async function(browser) {
+ *      const resultValue = await browser.getWindowRect();
+ *      console.log('result value', resultValue);
+ *   }
+ * }
+ *
+ * @w3c
+ * @method getWindowRect
+ * @link /#dfn-get-window-rect
+ * @param {function} callback Callback function to be called when the command finishes.
+ * @see windowRect
+ * @api protocol.contexts
+ */
+class GetWindowRect extends ClientCommand {
+  get returnsFullResultObject() {
+    return false;
+  }
+
+  get resolvesWithFullResultObject() {
+    return false;
+  }
+
+  performAction(callback) {
+    this.api.windowRect(null, callback);
+  }
+}
+
+module.exports = GetWindowRect;
diff --git a/lib/api/client-commands/getWindowSize.js b/lib/api/client-commands/getWindowSize.js
new file mode 100644
index 00000000..22de64c1
--- /dev/null
+++ b/lib/api/client-commands/getWindowSize.js
@@ -0,0 +1,46 @@
+const ClientCommand = require('./_baseCommand.js');
+
+/**
+ * Retrieves the current window size.
+ *
+ * For clients which are compatible with the [W3C Webdriver API](https://w3c.github.io/webdriver/), `getWindowSize` is an alias of `getWindowRect`.
+ *
+ * The `getWindowRect` command returns both dimensions and position of the window, using the `windowRect` protocol command.
+ *
+ * @example
+ * module.exports = {
+ *   'demo test .getWindowSize()': function(browser) {
+ *      // Retrieve the attributes
+ *      browser.getWindowSize(function(value) {
+ *        console.log(value);
+ *      });
+ *   },
+ *
+ *   'getWindowSize ES6 demo test': async function(browser) {
+ *      const value = await browser.getWindowSize();
+ *      console.log('value', value);
+ *   }
+ * }
+ *
+ *
+ * @method getWindowSize
+ * @syntax .getWindowSize([callback])
+ * @param {function} callback Callback function to be called when the command finishes.
+ * @see windowRect
+ * @api protocol.contexts
+ */
+class GetWindowSize extends ClientCommand {
+  get returnsFullResultObject() {
+    return false;
+  }
+
+  get resolvesWithFullResultObject() {
+    return false;
+  }
+
+  performAction(callback) {
+    this.api.windowSize('current', callback);
+  }
+}
+
+module.exports = GetWindowSize;
diff --git a/lib/api/client-commands/init.js b/lib/api/client-commands/init.js
index 8bd4bf86..c141ef53 100644
--- a/lib/api/client-commands/init.js
+++ b/lib/api/client-commands/init.js
@@ -17,9 +17,6 @@ const ClientCommand = require('./_baseCommand.js');
  * @api protocol.navigation
  */
 class Init extends ClientCommand {
-  get returnsFullResultObject() {
-    return true;
-  }
 
   performAction(callback) {
     this.api.url(this.url, callback);
diff --git a/lib/api/client-commands/injectScript.js b/lib/api/client-commands/injectScript.js
index fb52157c..cb3befc7 100644
--- a/lib/api/client-commands/injectScript.js
+++ b/lib/api/client-commands/injectScript.js
@@ -19,9 +19,6 @@ const ClientCommand = require('./_baseCommand.js');
  * @returns {HTMLScriptElement} The newly created script tag.
  */
 class InjectScript extends ClientCommand {
-  get returnsFullResultObject() {
-    return true;
-  }
 
   performAction(callback) {
     // eslint-disable-next-line no-undef
diff --git a/lib/api/client-commands/maximizeWindow.js b/lib/api/client-commands/maximizeWindow.js
index d79f96e5..8f1a85a3 100644
--- a/lib/api/client-commands/maximizeWindow.js
+++ b/lib/api/client-commands/maximizeWindow.js
@@ -15,9 +15,6 @@ const ClientCommand = require('./_baseCommand.js');
  * @api protocol.contexts
  */
 class WindowMaximize extends ClientCommand {
-  get returnsFullResultObject() {
-    return true;
-  }
 
   performAction(callback) {
     this.api.windowMaximize('current', callback);
diff --git a/lib/api/client-commands/perform.js b/lib/api/client-commands/perform.js
index 9ec9fdb9..92589d23 100644
--- a/lib/api/client-commands/perform.js
+++ b/lib/api/client-commands/perform.js
@@ -52,8 +52,8 @@ class Perform extends EventEmitter {
     let doneCallback;
     let asyncHookTimeout = this.client.settings.globals.asyncHookTimeout;
 
-    this.timeoutId = setTimeout(function() {
-      throw new Error(`Timeout while waiting (${asyncHookTimeout}ms) for the .perform() command callback to be called.`);
+    this.timeoutId = setTimeout(() => {
+      this.emit('error', new Error(`Timeout while waiting (${asyncHookTimeout}ms) for the .perform() command callback to be called.`));
     }, asyncHookTimeout);
 
     if (callback.length === 0) {
diff --git a/lib/api/client-commands/resizeWindow.js b/lib/api/client-commands/resizeWindow.js
index ef2c589d..0871467a 100644
--- a/lib/api/client-commands/resizeWindow.js
+++ b/lib/api/client-commands/resizeWindow.js
@@ -17,9 +17,6 @@ const ClientCommand = require('./_baseCommand.js');
  * @api protocol.contexts
  */
 class ResizeWindow extends ClientCommand {
-  get returnsFullResultObject() {
-    return true;
-  }
 
   performAction(callback) {
     this.api.windowSize('current', this.width, this.height, callback);
diff --git a/lib/api/client-commands/saveScreenshot.js b/lib/api/client-commands/saveScreenshot.js
index 67373add..2a6f17c2 100644
--- a/lib/api/client-commands/saveScreenshot.js
+++ b/lib/api/client-commands/saveScreenshot.js
@@ -17,10 +17,6 @@ const Screenshots = require('../../testsuite/screenshots.js');
  * @api protocol.screens
  */
 class SaveScreenshot extends ClientCommand {
-  get returnsFullResultObject() {
-    return true;
-  }
-
   performAction(callback) {
     const {fileName} = this;
 
diff --git a/lib/api/client-commands/setCookie.js b/lib/api/client-commands/setCookie.js
index 51ad2d53..d0605cc3 100644
--- a/lib/api/client-commands/setCookie.js
+++ b/lib/api/client-commands/setCookie.js
@@ -27,10 +27,6 @@ const ClientCommand = require('./_baseCommand.js');
  * @see cookie
  */
 class SetCookie extends ClientCommand {
-  get returnsFullResultObject() {
-    return true;
-  }
-
   performAction(callback) {
     this.api.cookie('POST', this.cookie, callback);
   }
diff --git a/lib/api/client-commands/setWindowPosition.js b/lib/api/client-commands/setWindowPosition.js
index 97ebeacc..d60ef41a 100644
--- a/lib/api/client-commands/setWindowPosition.js
+++ b/lib/api/client-commands/setWindowPosition.js
@@ -17,10 +17,6 @@ const ClientCommand = require('./_baseCommand.js');
  * @api protocol.contexts
  */
 class SetWindowPosition extends ClientCommand {
-  get returnsFullResultObject() {
-    return true;
-  }
-
   performAction(callback) {
     this.api.windowPosition('current', this.offsetX, this.offsetY, callback);
   }
diff --git a/lib/api/client-commands/setWindowRect.js b/lib/api/client-commands/setWindowRect.js
new file mode 100644
index 00000000..2e6fcb96
--- /dev/null
+++ b/lib/api/client-commands/setWindowRect.js
@@ -0,0 +1,61 @@
+const ClientCommand = require('./_baseCommand.js');
+
+/**
+ * Change the [window rect](https://w3c.github.io/webdriver/#dfn-window-rect). This is defined as a dictionary of the `screenX`, `screenY`, `outerWidth` and `outerHeight` attributes of the window.
+ *
+ * Its JSON representation is the following:
+ * - `x` - window's screenX attribute;
+ * - `y` - window's screenY attribute;
+ * - `width` - outerWidth attribute;
+ * - `height` - outerHeight attribute.
+ *
+ * All attributes are in in CSS pixels. To change the window react, you can either specify `width` and `height`, `x` and `y` or all properties together.
+ *
+ * @example
+ * module.exports = {
+ *   'demo test .setWindowRect()': function(browser) {
+ *
+ *      // Change the screenX and screenY attributes of the window rect.
+ *      browser.setWindowRect({x: 500, y: 500});
+ *
+ *      // Change the width and height attributes of the window rect.
+ *      browser.setWindowRect({width: 600, height: 300});
+ *
+ *      // Retrieve the attributes
+ *      browser.setWindowRect(function(result) {
+ *        console.log(result.value);
+ *      });
+ *   },
+ *
+ *   'setWindowRect ES6 demo test': async function(browser) {
+ *      await browser.setWindowRect({
+ *        width: 600,
+ *        height: 300,
+ *        x: 100,
+ *        y: 100
+ *      });
+ *   }
+ * }
+ *
+ * @w3c
+ * @link /#dfn-get-window-rect
+ * @method setWindowRect
+ * @syntax .setWindowRect({width, height, x, y}, [callback]);
+ * @param {object} options An object specifying either `width` and `height`, `x` and `y`, or all together to set properties for the [window rect](https://w3c.github.io/webdriver/#dfn-window-rect).
+ * @param {function} [callback] Optional callback function to be called when the command finishes.
+ * @see windowRect
+ * @api protocol.contexts
+ */
+class SetWindowRect extends ClientCommand {
+  performAction(callback) {
+    this.api.windowRect(this.options, callback);
+  }
+
+  command(options, callback) {
+    this.options = options;
+
+    return super.command(callback);
+  }
+}
+
+module.exports = SetWindowRect;
diff --git a/lib/api/client-commands/setWindowSize.js b/lib/api/client-commands/setWindowSize.js
new file mode 100644
index 00000000..e1d57203
--- /dev/null
+++ b/lib/api/client-commands/setWindowSize.js
@@ -0,0 +1,32 @@
+const ClientCommand = require('./_baseCommand.js');
+
+/**
+ * Sets the current window size in CSS pixels.
+ *
+ * @example
+ *  this.demoTest = function (browser) {
+ *    browser.setWindowSize(400, 600);
+ *  };
+ *
+ *
+ * @method setWindowSize
+ * @param {number} width The new window width in CSS pixels
+ * @param {number} height The new window height in CSS pixels
+ * @param {function} [callback] Optional callback function to be called when the command finishes.
+ * @see windowSize
+ * @api protocol.contexts
+ */
+class SetWindowSize extends ClientCommand {
+  performAction(callback) {
+    this.api.windowSize('current', this.width, this.height, callback);
+  }
+
+  command(width, height, callback) {
+    this.width = width;
+    this.height = height;
+
+    return super.command(callback);
+  }
+}
+
+module.exports = SetWindowSize;
diff --git a/lib/api/client-commands/switchWindow.js b/lib/api/client-commands/switchWindow.js
index 9a5c55dd..74e367e1 100644
--- a/lib/api/client-commands/switchWindow.js
+++ b/lib/api/client-commands/switchWindow.js
@@ -27,10 +27,6 @@ const ClientCommand = require('./_baseCommand.js');
  * @api protocol.contexts
  */
 class SwitchWindow extends ClientCommand {
-  get returnsFullResultObject() {
-    return true;
-  }
-
   performAction(callback) {
     this.api.window('POST', this.handleOrName, callback);
   }
diff --git a/lib/api/element-commands/_baseElementCommand.js b/lib/api/element-commands/_baseElementCommand.js
index d16ecf1b..5147f574 100644
--- a/lib/api/element-commands/_baseElementCommand.js
+++ b/lib/api/element-commands/_baseElementCommand.js
@@ -32,8 +32,17 @@ class BaseElementCommand extends ElementCommand {
           return !this.transport.invalidWindowReference(response.result);
         },
         validate,
-        errorHandler: (err) => {
-          return this.actionErrorHandler(err);
+        errorHandler: err => {
+          const result = err.response && err.response.result || {};
+
+          if (this.suppressNotFoundErrors) {
+            return this.complete(null, result);
+          }
+
+          const error = this.noSuchElementError();
+          error.result = result;
+
+          return this.elementLocateError(error);
         }
       })
       .queueAction({
diff --git a/lib/api/element-commands/_waitFor.js b/lib/api/element-commands/_waitFor.js
index 2f0d1ef4..613e8601 100644
--- a/lib/api/element-commands/_waitFor.js
+++ b/lib/api/element-commands/_waitFor.js
@@ -17,6 +17,12 @@ class WaitForElement extends ElementCommand {
     return result.value === true;
   }
 
+  constructor(opts) {
+    super(opts);
+
+    this.expectedValue = 'found';
+  }
+
   validateArgsCount() {}
 
   setupActions() {
@@ -186,6 +192,18 @@ class WaitForElement extends ElementCommand {
   formatMessage(defaultMsg, timeMs) {
     return Utils.format(this.message || defaultMsg, this.element.selector, timeMs || this.ms);
   }
+
+  elementNotFound(response) {
+    const defaultMsg = 'Timed out while waiting for element <%s> to be present for %d milliseconds.';
+
+    return this.fail({
+      result: {
+        value: false,
+        status: -1,
+        err: response
+      }
+    }, 'not found', this.expectedValue, defaultMsg);
+  }
 }
 
 module.exports = WaitForElement;
diff --git a/lib/api/element-commands/_waitForDisplayed.js b/lib/api/element-commands/_waitForDisplayed.js
index a1c29a11..95fbe639 100644
--- a/lib/api/element-commands/_waitForDisplayed.js
+++ b/lib/api/element-commands/_waitForDisplayed.js
@@ -9,15 +9,6 @@ class WaitForDisplayed extends WaitForElement {
     throw new Error('Override');
   }
 
-  elementNotFound(err) {
-    if (!(err instanceof WaitForDisplayed.NoSuchElementError)) {
-      err = this.noSuchElementError();
-      err.detailedLogging = false;
-    }
-
-    return this.complete(err, {});
-  }
-
   setupActions() {
     const isResultStale = (result) => this.transport.staleElementReference(result);
     const validate = (result) => this.isResultSuccess(result);
diff --git a/lib/api/element-commands/clearValue.js b/lib/api/element-commands/clearValue.js
index cb270865..d4a1d947 100644
--- a/lib/api/element-commands/clearValue.js
+++ b/lib/api/element-commands/clearValue.js
@@ -1,20 +1,49 @@
 const BaseElementCommand = require('./_baseElementCommand.js');
 
 /**
- * Clear a textarea or a text input element's value. Uses `elementIdValue` protocol action internally.
+ * Clear a textarea or a text input element's value. Starting with v1.1 `clearValue()` will wait for the element to be present (until the specified timeout).
+ *
+ * If the element is not found, an error is thrown which will cause the test to fail. Starting with `v1.2` you can suppress element not found errors by specifying the `suppressNotFoundErrors` flag.
  *
  * @example
  * this.demoTest = function (browser) {
  *   browser.clearValue('input[type=text]');
  * };
  *
+ * @example
+ * module.exports = {
+ *   demoTest(browser) {
+ *     browser.clearValue('#login input[type=text]');
+ *
+ *     browser.clearValue('#login input[type=text]', function(result) {
+ *       console.log('clearValue result', result);
+ *     });
+ *
+ *     // with explicit locate strategy
+ *     browser.clearValue('css selector', '#login input[type=text]');
+ *
+ *     // with selector object - see https://nightwatchjs.org/guide#element-properties
+ *     browser.clearValue({
+ *       selector: '#login input[type=text]',
+ *       index: 1,
+ *       suppressNotFoundErrors: true
+ *     });
+ *
+ *     browser.clearValue({
+ *       selector: '#login input[type=text]',
+ *       timeout: 2000 // overwrite the default timeout (in ms) to check if the element is present
+ *     });
+ *   }
+ * }
  *
  * @method clearValue
  * @syntax .clearValue(selector, [callback])
- * @param {string} selector The CSS/Xpath selector used to locate the element.
+ * @param {string} [using] The locator strategy to use. See [W3C Webdriver - locator strategies](https://www.w3.org/TR/webdriver/#locator-strategies)
+ * @param {string|object} selector The selector (CSS/Xpath) used to locate the element. Can either be a string or an object which specifies [element properties](https://nightwatchjs.org/guide#element-properties).
  * @param {function} [callback] Optional callback function to be called when the command finishes.
  * @see elementIdClear
  * @api protocol.elementinteraction
+ * @link /#dfn-element-clear
  */
 class ClearValue extends BaseElementCommand {
   get extraArgsCount() {
diff --git a/lib/api/element-commands/click.js b/lib/api/element-commands/click.js
index a4c31f74..726417cc 100644
--- a/lib/api/element-commands/click.js
+++ b/lib/api/element-commands/click.js
@@ -1,11 +1,9 @@
 const BaseElementCommand = require('./_baseElementCommand.js');
 
 /**
- * Simulates a click event on the given DOM element.
+ * Simulates a click event on the given DOM element. The element is scrolled into view if it is not already pointer-interactable. See the WebDriver specification for <a href="https://www.w3.org/TR/webdriver/#element-interactability" target="_blank">element interactability</a>.
  *
- * The element is scrolled into view if it is not already pointer-interactable. See the WebDriver specification for <a href="https://www.w3.org/TR/webdriver/#element-interactability" target="_blank">element interactability</a>. Starting with v1.1 `click()` will also wait for the element to be present (until the specified timeout).
- *
- * Uses `elementIdClick` protocol action internally.
+ * Starting with v1.1 `click()` will also wait for the element to be present (until the specified timeout). * If the element is not found, an error is thrown which will cause the test to fail. Starting with `v1.2` you can suppress element not found errors by specifying the `suppressNotFoundErrors` flag.
  *
  * @example
  * module.exports = {
@@ -22,7 +20,8 @@ const BaseElementCommand = require('./_baseElementCommand.js');
  *     // with selector object - see https://nightwatchjs.org/guide#element-properties
  *     browser.click({
  *       selector: '#main ul li a',
- *       index: 1
+ *       index: 1,
+ *       suppressNotFoundErrors: true
  *     });
  *
  *     browser.click({
@@ -37,7 +36,6 @@ const BaseElementCommand = require('./_baseElementCommand.js');
  *   }
  * }
  *
- *
  * @method click
  * @syntax .click(selector, [callback])
  * @syntax .click(using, selector, [callback])
diff --git a/lib/api/element-commands/isVisible.js b/lib/api/element-commands/isVisible.js
index 00363534..0465e0de 100644
--- a/lib/api/element-commands/isVisible.js
+++ b/lib/api/element-commands/isVisible.js
@@ -1,7 +1,7 @@
 const BaseElementCommand = require('./_baseElementCommand.js');
 
 /**
- * Determine if an element is currently displayed. Uses `elementIdDisplayed` protocol command.
+ * Determine if an element is currently displayed. Starting with `v1.2` you can suppress element not found errors, in case the element is not found on the page, by specifying the `suppressNotFoundErrors` flag.
  *
  * @example
  * this.demoTest = function (browser) {
@@ -12,6 +12,36 @@ const BaseElementCommand = require('./_baseElementCommand.js');
  *   });
  * };
  *
+ * @example
+ * module.exports = {
+ *   demoTest(browser) {
+ *     browser.isVisible('#main ul li a.first', function(result) {
+ *       this.assert.equal(typeof result, "object");
+ *       this.assert.equal(result.status, 0);
+ *       this.assert.equal(result.value, true);
+ *     });
+ *
+ *     // with explicit locate strategy
+ *     browser.isVisible('css selector', '#main ul li a.first');
+ *
+ *     // with selector object - see https://nightwatchjs.org/guide#element-properties
+ *     browser.isVisible({
+ *       selector: '#main ul li a',
+ *       index: 1,
+ *       suppressNotFoundErrors: true
+ *     });
+ *
+ *     browser.isVisible({
+ *       selector: '#main ul li a.first',
+ *       timeout: 2000 // overwrite the default timeout (in ms) to check if the element is present
+ *     });
+ *   },
+ *
+ *   demoTestAsync: async function(browser) {
+ *     const result = await browser.isVisible('#main ul li a.first');
+ *     console.log('isVisible result', result);
+ *   }
+ * }
  *
  * @method isVisible
  * @syntax .isVisible(selector, callback)
diff --git a/lib/api/element-commands/waitForElementNotPresent.js b/lib/api/element-commands/waitForElementNotPresent.js
index 7451aa9d..52f26dcf 100644
--- a/lib/api/element-commands/waitForElementNotPresent.js
+++ b/lib/api/element-commands/waitForElementNotPresent.js
@@ -78,7 +78,8 @@ const WaitForElement = require('./_waitFor.js');
  * @param {function} [callback] Optional callback function to be called when the command finishes.
  * @param {string} [message] Optional message to be shown in the output; the message supports two placeholders: %s for current selector and %d for the time (e.g. Element %s was not in the page for %d ms).
  * @see waitForElementPresent
- * @api protocol.elements
+ * @sortIndex 10
+ * @api protocol.waitforelements
  */
 class WaitForElementNotPresent extends WaitForElement {
   get retryOnSuccess() {
diff --git a/lib/api/element-commands/waitForElementNotVisible.js b/lib/api/element-commands/waitForElementNotVisible.js
index 23065243..35bbd57f 100644
--- a/lib/api/element-commands/waitForElementNotVisible.js
+++ b/lib/api/element-commands/waitForElementNotVisible.js
@@ -78,7 +78,8 @@ const WaitForDisplayed = require('./_waitForDisplayed.js');
  * @param {function} [callback] Optional callback function to be called when the command finishes.
  * @param {string} [message] Optional message to be shown in the output; the message supports two placeholders: %s for current selector and %d for the time (e.g. Element %s was not in the page for %d ms).
  * @see waitForElementVisible
- * @api protocol.elements
+ * @sortIndex 30
+ * @api protocol.waitforelements
  */
 class WaitForElementNotVisible extends WaitForDisplayed {
   constructor(opts) {
diff --git a/lib/api/element-commands/waitForElementPresent.js b/lib/api/element-commands/waitForElementPresent.js
index ddc82b01..bac65230 100644
--- a/lib/api/element-commands/waitForElementPresent.js
+++ b/lib/api/element-commands/waitForElementPresent.js
@@ -77,36 +77,19 @@ const WaitForElement = require('./_waitFor.js');
  * @param {boolean} [abortOnFailure=abortOnAssertionFailure] By the default if the element is not found the test will fail. Set this to false if you wish for the test to continue even if the assertion fails. To set this globally you can define a property `abortOnAssertionFailure` in your globals.
  * @param {function} [callback] Optional callback function to be called when the command finishes.
  * @param {string} [message] Optional message to be shown in the output; the message supports two placeholders: %s for current selector and %d for the time (e.g. Element %s was not in the page for %d ms).
- * @api protocol.elements
+ * @sortIndex 0
+ * @api protocol.waitforelements
  */
 class WaitForElementPresent extends WaitForElement {
   get retryOnSuccess() {
     return false;
   }
 
-  constructor(opts) {
-    super(opts);
-
-    this.expectedValue = 'found';
-  }
-
   elementFound(response) {
     const defaultMsg = 'Element <%s> was present after %d milliseconds.';
 
     return this.pass(response, defaultMsg, this.executor.elapsedTime);
   }
-
-  elementNotFound(response) {
-    const defaultMsg = 'Timed out while waiting for element <%s> to be present for %d milliseconds.';
-
-    return this.fail({
-      result: {
-        value: false,
-        status: -1,
-        err: response
-      }
-    }, 'not found', this.expectedValue, defaultMsg);
-  }
 }
 
 module.exports = WaitForElementPresent;
diff --git a/lib/api/element-commands/waitForElementVisible.js b/lib/api/element-commands/waitForElementVisible.js
index 24001173..f68c16f7 100644
--- a/lib/api/element-commands/waitForElementVisible.js
+++ b/lib/api/element-commands/waitForElementVisible.js
@@ -2,9 +2,11 @@ const WaitForDisplayed = require('./_waitForDisplayed.js');
 
 /**
  * Waits a given time in milliseconds (default 5000ms) for an element to be visible in the page before performing any other commands or assertions.
+ *
  * If the element fails to be present and visible in the specified amount of time, the test fails. You can change this by setting `abortOnFailure` to `false`.
  *
  * You can change the polling interval by defining a `waitForConditionPollInterval` property (in milliseconds) in as a global property in your `nightwatch.json` or in your external globals file.
+ *
  * Similarly, a default timeout can be specified as a global `waitForConditionTimeout` property (in milliseconds).
  *
  * @example
@@ -77,7 +79,8 @@ const WaitForDisplayed = require('./_waitForDisplayed.js');
  * @param {boolean} [abortOnFailure=abortOnAssertionFailure] By the default if the element is not found the test will fail. Set this to false if you wish for the test to continue even if the assertion fails. To set this globally you can define a property `abortOnAssertionFailure` in your globals.
  * @param {function} [callback] Optional callback function to be called when the command finishes.
  * @param {string} [message] Optional message to be shown in the output; the message supports two placeholders: %s for current selector and %d for the time (e.g. Element %s was not in the page for %d ms).
- * @api protocol.elements
+ * @sortIndex 20
+ * @api protocol.waitforelements
  */
 class WaitForElementVisible extends WaitForDisplayed {
   constructor(opts) {
diff --git a/lib/api/protocol.js b/lib/api/protocol.js
index bf71f696..c12bc47b 100644
--- a/lib/api/protocol.js
+++ b/lib/api/protocol.js
@@ -1,5 +1,6 @@
 const LocateStrategy = require('../element/strategy.js');
 const Element = require('../element/element.js');
+const Utils = require('../util/utils.js');
 
 module.exports = class ProtocolActions {
   static get ScreenOrientation() {
@@ -26,16 +27,15 @@ module.exports = class ProtocolActions {
     return [
       'script',
       'implicit',
-      'page load'
+      'page load',
+      'pageLoad'
     ];
   }
 
   static makePromise(cb, context, result) {
     const cbResult = cb.call(context, result);
     if (cbResult instanceof Promise) {
-      return cbResult.then(_ => {
-        return result;
-      });
+      return cbResult;
     }
 
     return result;
@@ -69,7 +69,7 @@ module.exports = class ProtocolActions {
         return function (...args) {
           const callback = args.pop() || function () {};
           const definition = {
-            args: args
+            args
           };
 
           let method;
@@ -176,26 +176,37 @@ module.exports = class ProtocolActions {
       },
 
       /**
-       * 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.
+       * Configure or retrieve 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.
+       *
+       * If called with only a callback as argument, the command will return the existing configured timeout values.
        *
        * @example
        *  this.demoTest = function (browser) {
        *    browser.timeouts('script', 10000, function(result) {
        *      console.log(result);
        *    });
+       *
+       *    browser.timeouts(function(result) {
+       *      console.log('timeouts', result);
+       *    });
        * }
        *
        * @link /#set-timeout
        * @editline L188
+       * @syntax .timeouts([callback])
        * @syntax .timeouts(type, ms, [callback])
        * @section sessions
-       * @param {string} type The type of operation to set the timeout for. Valid values are "script" for script timeouts, "implicit" for modifying the implicit wait timeout and "page load" for setting a page load timeout.
+       * @param {string} type The type of operation to set the timeout for. Valid values are "script" for script timeouts, "implicit" for modifying the implicit wait timeout and "pageLoad" (or "page load" for legacy JsonWire) for setting a page load timeout.
        * @param {number} ms The amount of time, in milliseconds, that time-limited commands are permitted to run.
        * @param {function} [callback] Optional callback function to be called when the command finishes.
        * @api protocol.sessions
        */
       timeouts(type, ms, callback) {
-        if (ProtocolActions.TimeoutTypes.indexOf(type) === -1) {
+        if (Utils.isFunction(type) && arguments.length === 1 || arguments.length === 0) {
+          return this.TransportActions.getTimeouts(type);
+        }
+
+        if (!ProtocolActions.TimeoutTypes.includes(type)) {
           throw new Error(`Invalid timeouts type value: ${type}. Accepted values are: ${ProtocolActions.TimeoutTypes.join(', ')}`);
         }
 
@@ -217,6 +228,7 @@ module.exports = class ProtocolActions {
        * }
        *
        * @syntax .timeoutsAsyncScript(ms, [callback])
+       * @jsonwire
        * @param {number} ms The amount of time, in milliseconds, that time-limited commands are permitted to run.
        * @param {function} [callback] Optional callback function to be called when the command finishes.
        * @api protocol.sessions
@@ -239,7 +251,7 @@ module.exports = class ProtocolActions {
        *    });
        * }
        *
-       * @link
+       * @jsonwire
        * @syntax .timeoutsImplicitWait(ms, [callback])
        * @param {number} ms The amount of time, in milliseconds, that time-limited commands are permitted to run.
        * @param {function} [callback] Optional callback function to be called when the command finishes.
@@ -407,7 +419,7 @@ module.exports = class ProtocolActions {
        * @param {string} method The HTTP method to use. Can be either `POST` (change focus) or `DELETE` (close window).
        * @param {string} handleOrName The window to change focus to.
        * @param {function} [callback] Optional callback function to be called when the command finishes.
-       * @api protocol.contexts
+       * @api protocol.window
        */
       window(method, handleOrName, callback) {
         method = method.toUpperCase();
@@ -440,7 +452,7 @@ module.exports = class ProtocolActions {
        *
        * @link /#get-window-handle
        * @param {function} callback Callback function which is called with the result value.
-       * @api protocol.contexts
+       * @api protocol.window
        */
       windowHandle(callback) {
         return this.TransportActions.getWindowHandle(callback);
@@ -459,7 +471,7 @@ module.exports = class ProtocolActions {
        *
        * @link /#get-window-handles
        * @param {function} callback Callback function which is called with the result value.
-       * @api protocol.contexts
+       * @api protocol.window
        */
       windowHandles(callback) {
         return this.TransportActions.getAllWindowHandles(callback);
@@ -469,21 +481,197 @@ module.exports = class ProtocolActions {
        * Increases the window to the maximum available size without going full-screen.
        *
        * @example
-       *  this.demoTest = function (browser) {
-       *    browser.windowMaximize('current', function(result) {
-       *      console.log(result);
-       *    });
+       * module.exports = {
+       *  'demo Test with W3C Webdriver clients': function(browser) {
+       *     // W3C Webdriver API doesn't require the window handle parameter anymore
+       *     browser.windowMaximize(function(result) {
+       *       console.log(result);
+       *     });
+       *   },
+       *
+       *   'ES6 async demo Test': async function(browser) {
+       *     const result = await browser.windowMaximize();
+       *     console.log('result value is:', result.value);
+       *   },
+       *
+       *   'when using JSONWire (deprecated) clients': function(browser) {
+       *      browser.windowMaximize('current', function(result) {
+       *        console.log(result);
+       *      });
+       *   }
        * }
        *
-       * @link /#maximize-window
-       * @param {string} [handleOrName] windowHandle URL parameter; if it is "current", the currently active window will be maximized.
+       * @link /#dfn-maximize-window
+       * @param {string} [handleOrName] Only required when using non-W3C Webdriver protocols (such as JSONWire). windowHandle URL parameter; if it is "current", the currently active window will be maximized.
        * @param {function} [callback] Optional callback function to be called when the command finishes.
-       * @api protocol.contexts
+       * @api protocol.window
        */
-      windowMaximize(handleOrName, callback) {
+      windowMaximize(handleOrName = 'current', callback) {
         return this.TransportActions.maximizeWindow(handleOrName, callback);
       },
 
+      /**
+       * Hides the window in the system tray. If the window happens to be in fullscreen mode, it is restored the normal state then it will be "iconified" - minimize or hide the window from the visible screen.
+       *
+       * @example
+       * module.exports = {
+       *  'demo Test': function(browser) {
+       *     browser.minimizeWindow(function(result) {
+       *       console.log(result);
+       *     });
+       *   },
+       *
+       *   'ES6 async demo Test': async function(browser) {
+       *     const result = await browser.minimizeWindow();
+       *     console.log('result value is:', result.value);
+       *   }
+       * }
+       *
+       * @link /#dfn-minimize-window
+       * @param {function} [callback] Optional callback function to be called when the command finishes.
+       * @api protocol.contexts
+       */
+      minimizeWindow(callback) {
+        return this.TransportActions.minimizeWindow(callback);
+      },
+
+      /**
+       * Sets the current window state to fullscreen.
+       *
+       * @example
+       * module.exports = {
+       *  'demo Test': function(browser) {
+       *     browser.fullscreenWindow(function(result) {
+       *       console.log(result);
+       *     });
+       *   },
+       *
+       *   'ES6 async demo Test': async function(browser) {
+       *     const result = await browser.fullscreenWindow();
+       *     console.log('result value is:', result.value);
+       *   }
+       * }
+       *
+       * @link /#dfn-fullscreen-window
+       * @param {function} [callback] Optional callback function to be called when the command finishes.
+       * @api protocol.contexts
+       */
+      fullscreenWindow(callback) {
+        return this.TransportActions.fullscreenWindow(callback);
+      },
+
+      /**
+       * Opens a new top-level browser window, which can be either a tab (default) or a separate new window.
+       *
+       * This command is only available for W3C Webdriver compatible browsers.
+       *
+       * @example
+       * module.exports = {
+       *  'demo Test': function(browser) {
+       *     // open a new window tab (default)
+       *     browser.openNewWindow(function(result) {
+       *       console.log(result);
+       *     });
+       *
+       *     // open a new window
+       *     browser.openNewWindow('window', function(result) {
+       *       console.log(result);
+       *     });
+       *   },
+       *
+       *   'ES6 async demo Test': async function(browser) {
+       *     const result = await browser.fullscreenWindow();
+       *     console.log('result value is:', result.value);
+       *   }
+       * }
+       *
+       * @link /#dfn-new-window
+       * @param {string} [type] Can be either "tab" or "window", with "tab" set to default if none is specified.
+       * @param {function} [callback] Optional callback function to be called when the command finishes.
+       * @api protocol.contexts
+       */
+      openNewWindow(type = 'tab', callback) {
+        return this.TransportActions.openNewWindow(type, callback);
+      },
+
+      /**
+       * Change or get the [window rect](https://w3c.github.io/webdriver/#dfn-window-rect). This is defined as a dictionary of the `screenX`, `screenY`, `outerWidth` and `outerHeight` attributes of the window.
+       *
+       * Its JSON representation is the following:
+       * - `x` - window's screenX attribute;
+       * - `y` - window's screenY attribute;
+       * - `width` - outerWidth attribute;
+       * - `height` - outerHeight attribute.
+       *
+       * All attributes are in in CSS pixels. To change the window react, you can either specify `width` and `height`, `x` and `y` or all properties together.
+       *
+       * @example
+       * module.exports = {
+       *   'demo test .windowRect()': function(browser) {
+       *
+       *      // Change the screenX and screenY attributes of the window rect.
+       *      browser.windowRect({x: 500, y: 500});
+       *
+       *      // Change the width and height attributes of the window rect.
+       *      browser.windowRect({width: 600, height: 300});
+       *
+       *      // Retrieve the attributes
+       *      browser.windowRect(function(result) {
+       *        console.log(result.value);
+       *      });
+       *   },
+       *
+       *   'windowRect ES6 demo test': async function(browser) {
+       *      const resultValue = await browser.windowRect();
+       *      console.log('result value', resultValue);
+       *   }
+       * }
+       *
+       * @w3c
+       * @link /#dfn-get-window-rect
+       * @syntax .windowRect({width, height, x, y}, [callback]);
+       * @param {object} options An object specifying either `width` and `height`, `x` and `y`, or all together to set properties for the [window rect](https://w3c.github.io/webdriver/#dfn-window-rect).
+       * @param {function} [callback] Optional callback function to be called when the command finishes.
+       * @api protocol.window
+       */
+      windowRect(options, callback = function() {}) {
+        if (arguments[0] === null) {
+          return this.TransportActions.getWindowRect(callback);
+        }
+
+        const {width, height, x, y} = options;
+
+        if (!Utils.isUndefined(width) && !Utils.isNumber(width)) {
+          throw new Error(`Width argument passed to .windowRect() must be a number; received: ${typeof width} (${width}).`);
+        }
+
+        if (!Utils.isUndefined(height) && !Utils.isNumber(height)) {
+          throw new Error(`Height argument passed to .windowRect() must be a number; received: ${typeof height} (${height}).`);
+        }
+
+        if (Utils.isNumber(width) && !Utils.isNumber(height) ||
+          !Utils.isNumber(width) && Utils.isNumber(height)
+        ) {
+          throw new Error('Attributes "width" and "height" must be specified together.');
+        }
+
+        if (!Utils.isUndefined(x) && !Utils.isNumber(x)) {
+          throw new Error(`X position argument passed to .windowRect() must be a number; received: ${typeof x} (${x}).`);
+        }
+
+        if (!Utils.isUndefined(y) && !Utils.isNumber(y)) {
+          throw new Error(`Y position argument passed to .windowRect() must be a number; received: ${typeof y} (${y}).`);
+        }
+
+        if (Utils.isNumber(x) && !Utils.isNumber(y) ||
+          !Utils.isNumber(x) && Utils.isNumber(y)
+        ) {
+          throw new Error('Attributes "x" and "y" must be specified together.');
+        }
+
+        return this.TransportActions.setWindowRect(arguments[0], callback);
+      },
+
       /**
        * Change or get the position of the specified window. If the second argument is a function it will be used as a callback and the call will perform a get request to retrieve the existing window position.
        *
@@ -503,13 +691,13 @@ module.exports = class ProtocolActions {
        *    });
        * }
        *
-       *
-       * @link /#get-window-position
+       * @see windowRect
+       * @jsonwire
        * @param {string} windowHandle
        * @param {number} offsetX
        * @param {number} offsetY
        * @param {function} callback Callback function which is called with the result value.
-       * @api protocol.contexts
+       * @api protocol.window
        */
       windowPosition(windowHandle, offsetX, offsetY, callback) {
         if (typeof windowHandle !== 'string') {
@@ -556,12 +744,13 @@ module.exports = class ProtocolActions {
        *    });
        * }
        *
-       * @link /#get-window-size
+       * @see windowRect
+       * @jsonwire
        * @param {string} windowHandle
        * @param {number} width
        * @param {number} height
        * @param {function} [callback] Optional callback function to be called when the command finishes.
-       * @api protocol.contexts
+       * @api protocol.window
        */
       windowSize(windowHandle, width, height, callback) {
         if (typeof windowHandle !== 'string') {
@@ -603,7 +792,7 @@ module.exports = class ProtocolActions {
        * @link /#switch-to-frame
        * @param {string|number|null} [frameId] Identifier for the frame to change focus to.
        * @param {function} [callback] Optional callback function to be called when the command finishes.
-       * @api protocol.contexts
+       * @api protocol.frames
        */
       frame(frameId, callback) {
         if (arguments.length === 1 && typeof frameId === 'function') {
@@ -628,7 +817,7 @@ module.exports = class ProtocolActions {
        * @link /#switch-to-parent-frame
        * @param {function} [callback] Optional callback function to be called when the command finishes.
        * @since v0.4.8
-       * @api protocol.contexts
+       * @api protocol.frames
        */
       frameParent(callback) {
         return this.TransportActions.switchToParentFrame(callback);
@@ -689,7 +878,7 @@ module.exports = class ProtocolActions {
        * Search for multiple elements on the page, starting from the document root. The located elements will be returned as web element JSON objects.
        * First argument to be passed is the locator strategy, which is detailed on the [WebDriver docs](https://www.w3.org/TR/webdriver/#locator-strategies).
        *
-       * * The locator strategy can be one of:
+       * The locator strategy can be one of:
        * - `css selector`
        * - `link text`
        * - `partial link text`
@@ -941,7 +1130,6 @@ module.exports = class ProtocolActions {
       /**
        * Retrieve the computed value of the given CSS property of the given element.
        *
-       *
        * The CSS property to query should be specified using the CSS property name, not the JavaScript property name (e.g. background-color instead of backgroundColor).
        *
        * @link /#get-element-css-value
@@ -960,7 +1148,7 @@ module.exports = class ProtocolActions {
       /**
        * Scrolls into view a submittable element excluding buttons or editable element, and then attempts to clear its value, reset the checked state, or text content.
        *
-       * @link /#element-clear
+       * @link /#dfn-element-clear
        * @param {string} webElementId The [Web Element ID](https://www.w3.org/TR/webdriver1/#dfn-web-elements) of the element to route the command to.
        * @param {function} [callback] Optional callback function to be called when the command finishes.
        * @api protocol.elementinternal
@@ -990,7 +1178,7 @@ module.exports = class ProtocolActions {
       /**
        * Determine if an element is currently displayed.
        *
-       * @link
+       * @link /#element-displayedness
        * @param {string} webElementId The [Web Element ID](https://www.w3.org/TR/webdriver1/#dfn-web-elements) of the element to route the command to.
        * @param {function} callback Callback function which is called with the result value.
        * @api protocol.elementinternal
diff --git a/lib/core/assertion.js b/lib/core/assertion.js
index bb015bba..e3c1b62b 100644
--- a/lib/core/assertion.js
+++ b/lib/core/assertion.js
@@ -14,6 +14,7 @@ class NightwatchAssertion {
   constructor(message) {
     this.__err = new NightwatchAssertError(message);
     this.__stackTraceTitle = message;
+    this.__abortOnFailure = true;
 
     this.failureMessage = '';
 
@@ -37,6 +38,15 @@ class NightwatchAssertion {
     return this.__stackTraceTitle;
   }
 
+  set abortOnFailure(value) {
+    this.__abortOnFailure = value;
+    this.__err.abortOnFailure = value;
+  }
+
+  get abortOnFailure() {
+    return this.__abortOnFailure;
+  }
+
   buildStackTrace() {
     let stackTrace = this.stackTrace || this.captureStackTrace(this.calleeFn);
     let sections = stackTrace.split('\n');
@@ -135,4 +145,3 @@ class NightwatchAssertion {
 
 module.exports = NightwatchAssertion;
 module.exports.AssertionError = NightwatchAssertError;
-
diff --git a/lib/element/command.js b/lib/element/command.js
index 9d3cd998..7db1c14b 100644
--- a/lib/element/command.js
+++ b/lib/element/command.js
@@ -93,6 +93,15 @@ class ElementCommand extends EventEmitter {
   set abortOnFailure(value) {
     this.__abortOnFailure = Utils.convertBoolean(value);
   }
+
+  get suppressNotFoundErrors() {
+    return this.__suppressNotFoundErrors;
+  }
+
+  set suppressNotFoundErrors(value) {
+    this.__suppressNotFoundErrors = Utils.convertBoolean(value);
+  }
+
   /**
    * @override
    * @returns {*}
@@ -105,14 +114,6 @@ class ElementCommand extends EventEmitter {
     return this.transport.isResultSuccess(result) && result.value !== null;
   }
 
-  actionErrorHandler(err) {
-    const error = new NoSuchElementError(this.element, this.ms);
-
-    error.result = err.response && err.response.result || {};
-
-    return this.elementLocateError(error);
-  }
-
   protocolActionHandler() {
     return Promise.resolve();
   }
@@ -126,6 +127,7 @@ class ElementCommand extends EventEmitter {
     this.retries = 0;
     this.setStrategy();
 
+    this.suppressNotFoundErrors = false;
     this.abortOnFailure = this.api.globals.abortOnAssertionFailure;
     this.throwOnMultipleElementsReturned = this.api.globals.throwOnMultipleElementsReturned;
     this.elementId = null;
@@ -265,13 +267,17 @@ class ElementCommand extends EventEmitter {
   setOptionsFromSelector() {
     if (Utils.isObject(this.selector)) {
       const {
-        abortOnFailure, retryInterval, message, timeout, locateStrategy, retryAction
+        abortOnFailure, retryInterval, message, timeout, locateStrategy, suppressNotFoundErrors, retryAction
       } = this.selector;
 
       if (!Utils.isUndefined(abortOnFailure)) {
         this.abortOnFailure = abortOnFailure;
       }
 
+      if (!Utils.isUndefined(suppressNotFoundErrors)) {
+        this.suppressNotFoundErrors = suppressNotFoundErrors;
+      }
+
       if (!Utils.isUndefined(retryInterval)) {
         this.setRescheduleInterval(retryInterval);
       }
@@ -359,18 +365,21 @@ class ElementCommand extends EventEmitter {
   }
 
   noSuchElementError() {
-    return new NoSuchElementError(this.element, this.ms);
+    const {element, ms, abortOnFailure} = this;
+
+    return new NoSuchElementError({element, ms, abortOnFailure});
   }
 }
 
 class NoSuchElementError extends Error {
-  constructor(element, timeoutMs) {
+  constructor({element, ms, abortOnFailure}) {
     super();
 
     this.selector = element.selector;
+    this.abortOnFailure = abortOnFailure;
     this.name = 'NoSuchElementError';
     this.strategy = element.locateStrategy;
-    this.message = `Timed out while waiting for element "${this.selector}" with "${this.strategy}" to be present for ${timeoutMs} milliseconds.`;
+    this.message = `Timed out while waiting for element "${this.selector}" with "${this.strategy}" to be present for ${ms} milliseconds.`;
   }
 }
 
diff --git a/lib/element/element.js b/lib/element/element.js
index cc052e36..bd40f73d 100644
--- a/lib/element/element.js
+++ b/lib/element/element.js
@@ -10,6 +10,7 @@ class Element {
       'locateStrategy',
       'index',
       'abortOnFailure',
+      'suppressNotFoundErrors',
       'timeout',
       'retryInterval',
       'message',
@@ -80,6 +81,10 @@ class Element {
       this.abortOnFailure = Utils.convertBoolean(definition.abortOnFailure);
     }
 
+    if (!Utils.isUndefined(definition.suppressNotFoundErrors)) {
+      this.suppressNotFoundErrors = Utils.convertBoolean(definition.suppressNotFoundErrors);
+    }
+
     if (!Utils.isUndefined(definition.retryInterval)) {
       this.retryInterval = definition.retryInterval;
     }
diff --git a/lib/page-object/command-wrapper.js b/lib/page-object/command-wrapper.js
index a91c5cc9..4c0e821a 100644
--- a/lib/page-object/command-wrapper.js
+++ b/lib/page-object/command-wrapper.js
@@ -23,7 +23,11 @@ class Command {
       return false;
     }
 
-    return Utils.isObject(item) || Utils.isString(item);
+    if (Utils.isObject(item)) {
+      return item.hasOwnProperty('selector') && Utils.isString(item.selector);
+    }
+
+    return Utils.isString(item);
   }
 
   constructor(parent, commandName, isChaiAssertion) {
diff --git a/lib/runner/cli/cli.js b/lib/runner/cli/cli.js
index efc74787..b2ec3ca0 100644
--- a/lib/runner/cli/cli.js
+++ b/lib/runner/cli/cli.js
@@ -66,6 +66,7 @@ class CliRunner {
   setLoggingOptions() {
     Logger.setOutputEnabled(this.test_settings.output);
     Logger.setDetailedOutput(this.test_settings.detailed_output);
+    Logger.setErrorLog(this.test_settings.disable_error_log);
 
     if (this.test_settings.disable_colors) {
       Logger.disableColors();
diff --git a/lib/runner/global-reporter.js b/lib/runner/global-reporter.js
index 4e104173..2a399e4c 100644
--- a/lib/runner/global-reporter.js
+++ b/lib/runner/global-reporter.js
@@ -278,6 +278,7 @@ class GlobalReporter {
         Object.keys(testSuite.completed).forEach(testcaseName => {
           let testcase = testSuite.completed[testcaseName];
 
+          // FIXME: remove duplicate error reporting
           if (testcase.failed > 0 || testcase.errors > 0) {
             let triesCount = testcase.retries > 0 ? testcase.retries + 1 : '';
             let triesContent = testcase.retries > 0 ? ` - ${triesCount} tries` : '';
diff --git a/lib/runner/wd-instances/base-wd-server.js b/lib/runner/wd-instances/base-wd-server.js
index f8b93a7b..af75f0d0 100644
--- a/lib/runner/wd-instances/base-wd-server.js
+++ b/lib/runner/wd-instances/base-wd-server.js
@@ -54,20 +54,6 @@ class BaseWDServer {
     return 10000;
   }
 
-  /**
-   * @return {number}
-   */
-  static get maxStatusPollTries() {
-    return 5;
-  }
-
-  /**
-   * @return {number}
-   */
-  static get statusPollInterval() {
-    return 100;
-  }
-
   /**
    * @return {number}
    */
@@ -108,6 +94,24 @@ class BaseWDServer {
     });
   }
 
+  /**
+   * Maximum number of ping status check attempts before returning an error
+   * 
+   * @return {number}
+   */
+  get maxStatusPollTries() {
+    return this.settings.max_status_poll_tries || 5;
+  }
+
+  /**
+   * Interval (in ms) to use between 2 ping status checks
+   * 
+   * @return {number}
+   */
+  get statusPollInterval() {
+    return this.settings.status_poll_interval || 100;
+  }
+
   /**
    * Time to wait (in ms) before starting to check the process if it's online
    *
diff --git a/lib/transport/actions.js b/lib/transport/actions.js
index ea5d0110..ed0c0d93 100644
--- a/lib/transport/actions.js
+++ b/lib/transport/actions.js
@@ -65,6 +65,7 @@ class TransportActions {
       errorMsg = result.error;
     }
 
+    // FIXME: report this error so it can be added to the error results?
     if (this.transport.shouldRegisterError(errorMsg)) {
       Logger.error(`Error while running .${commandName}() protocol action: ${errorMsg}\n`);
     }
diff --git a/lib/transport/jsonwire/actions.js b/lib/transport/jsonwire/actions.js
index c92a2c64..e7de688a 100644
--- a/lib/transport/jsonwire/actions.js
+++ b/lib/transport/jsonwire/actions.js
@@ -52,6 +52,8 @@ module.exports = {
       });
     },
 
+    getTimeouts: '/timeouts',
+
     ///////////////////////////////////////////////////////////
     // Session log
     ///////////////////////////////////////////////////////////
@@ -124,6 +126,18 @@ module.exports = {
       return TransportActions.post(`/window/${windowHandle}/maximize`);
     },
 
+    minimizeWindow() {
+      return TransportActions.post('/window/minimize');
+    },
+
+    fullscreenWindow() {
+      return TransportActions.post('/window/fullscreen');
+    },
+
+    openNewWindow() {
+      return TransportActions.post('/window/new');
+    },
+
     setWindowPosition(windowHandle, offsetX, offsetY) {
       return TransportActions.post({
         path: `/window/${windowHandle}/position`,
@@ -148,6 +162,17 @@ module.exports = {
       });
     },
 
+    // windowRect commands are not available in JsonWire protocol but are used in W3C Webdriver actions
+    // defining them here removes the need for error handlers in the case of JsonWire
+    getWindowRect: '/window/rect',
+
+    setWindowRect(data) {
+      return TransportActions.post({
+        path: '/window/rect',
+        data
+      });
+    },
+
     ///////////////////////////////////////////////////////////
     // Frames
     ///////////////////////////////////////////////////////////
diff --git a/lib/transport/webdriver/actions.js b/lib/transport/webdriver/actions.js
index 0851bc9c..a7325f93 100644
--- a/lib/transport/webdriver/actions.js
+++ b/lib/transport/webdriver/actions.js
@@ -2,13 +2,47 @@ const lodashMerge = require('lodash.merge');
 const TransportActions = require('../actions.js');
 const JsonWireActions = require('../jsonwire/actions.js');
 
+const setTimeoutType = function (type, value) {
+  const TYPES = [
+    'script', 'pageLoad', 'implicit'
+  ];
+  const data = {};
+
+  if (TYPES.includes(type)) {
+    data[type] = value;
+  }
+
+  return TransportActions.post({
+    path: '/timeouts',
+    data
+  });
+};
+
 module.exports = lodashMerge({}, JsonWireActions, {
   session: {
+    ///////////////////////////////////////////////////////////
+    // Timeouts
+    ///////////////////////////////////////////////////////////
+    /**
+     * https://w3c.github.io/webdriver/#dfn-timeouts-configuration
+     * @param type
+     * @param value
+     */
+    setTimeoutType,
+
+    setTimeoutsAsyncScript(value) {
+      return setTimeoutType('script', value);
+    },
+
+    setTimeoutsImplicitWait(value) {
+      return setTimeoutType('implicit', value);
+    },
+
     clickElement(id) {
       return TransportActions.post({
         path: `/element/${id}/click`,
         data: {
-          id: id
+          id
         }
       });
     },
@@ -17,7 +51,7 @@ module.exports = lodashMerge({}, JsonWireActions, {
       return TransportActions.post({
         path: `/element/${id}/clear`,
         data: {
-          id: id
+          id
         }
       });
     },
@@ -29,43 +63,48 @@ module.exports = lodashMerge({}, JsonWireActions, {
       return TransportActions.post({
         path: '/window',
         data: {
-          handle: handle
+          handle
         }
       });
     },
 
-    getWindowHandle: '/window/handle',
-
+    getWindowHandle: '/window',
     getAllWindowHandles: '/window/handles',
 
-    getWindowPosition(windowHandle) {
-      return `/window/${windowHandle}/position`;
+    openNewWindow(type = 'tab') {
+      return TransportActions.post({
+        path: '/window/new',
+        data: {
+          type
+        }
+      });
     },
 
-    maximizeWindow(windowHandle) {
-      return TransportActions.post(`/window/${windowHandle}/maximize`);
+    getWindowPosition: '/window/rect',
+    getWindowSize: '/window/rect',
+
+    maximizeWindow() {
+      return TransportActions.post({
+        path: '/window/maximize'
+      });
     },
 
-    setWindowPosition(windowHandle, offsetX, offsetY) {
+    setWindowPosition(windowHandle, x, y) {
       return TransportActions.post({
-        path: `/window/${windowHandle}/position`,
+        path: '/window/rect',
         data: {
-          x : offsetX,
-          y : offsetY
+          x,
+          y
         }
       });
     },
 
-    getWindowSize(windowHandle) {
-      return `/window/${windowHandle}/size`;
-    },
-
     setWindowSize(windowHandle, width, height) {
       return TransportActions.post({
-        path: `/window/${windowHandle}/size`,
+        path: '/window/rect',
         data: {
-          width : width,
-          height : height
+          width,
+          height
         }
       });
     },
@@ -73,12 +112,12 @@ module.exports = lodashMerge({}, JsonWireActions, {
     ///////////////////////////////////////////////////////////
     // Frames
     ///////////////////////////////////////////////////////////
-    switchToFrame(frameId) {
-      if (frameId) {
+    switchToFrame(id) {
+      if (id) {
         return TransportActions.post({
           path: '/frame',
           data: {
-            id: frameId
+            id
           }
         });
       }
@@ -90,31 +129,31 @@ module.exports = lodashMerge({}, JsonWireActions, {
       return TransportActions.post('/frame/parent');
     },
 
-    setElementValue(id, value) {
+    setElementValue(id, text) {
       return TransportActions.post({
         path: `/element/${id}/value`,
         data: {
-          text: value
+          text
         }
       });
     },
 
-    executeScript(fn, args) {
+    executeScript(script, args) {
       return TransportActions.post({
         path: '/execute/sync',
         data: {
-          script: fn,
-          args: args
+          script,
+          args
         }
       });
     },
 
-    executeScriptAsync(fn, args) {
+    executeScriptAsync(script, args) {
       return TransportActions.post({
         path: '/execute/async',
         data: {
-          script: fn,
-          args: args
+          script,
+          args
         }
       });
     },
@@ -132,11 +171,11 @@ module.exports = lodashMerge({}, JsonWireActions, {
 
     getAlertText: '/alert/text',
 
-    setAlertText(value) {
+    setAlertText(text) {
       return TransportActions.post({
         path: '/alert/text',
         data: {
-          text: value
+          text
         }
       });
     },
diff --git a/lib/util/logger.js b/lib/util/logger.js
index deb7c196..8ca7c738 100644
--- a/lib/util/logger.js
+++ b/lib/util/logger.js
@@ -3,6 +3,7 @@ const util = require('util');
 const Settings = {
   outputEnabled: true,
   detailedOutput: true,
+  disable_error_log: false,
   log_timestamp : false,
   colors : true,
   enabled : true
@@ -180,7 +181,7 @@ function logError(severity, errOrMessage, args) {
     errOrMessage = Utils.errorToStackTrace(errOrMessage);
   }
 
-  let alwaysDisplay = severity === Severity.ERROR;
+  let alwaysDisplay = !Settings.disable_error_log && severity === Severity.ERROR;
 
   logMessage(severity, errOrMessage, args, alwaysDisplay);
 }
@@ -241,6 +242,14 @@ const Logger = {
     return Settings.enabled;
   },
 
+  setErrorLog(val = false) {
+    Settings.disable_error_log = val;
+  },
+
+  isErrorLogDisabled() {
+    return Settings.disable_error_log;
+  },
+
   logDetailedMessage(message, type = 'log') {
     if (!Settings.outputEnabled || !Settings.detailedOutput) {
       return;
diff --git a/lib/util/utils.js b/lib/util/utils.js
index 3d6c6384..2a4c6e52 100644
--- a/lib/util/utils.js
+++ b/lib/util/utils.js
@@ -177,88 +177,6 @@ class Utils {
     });
   }
 
-  static get MAX_CONCURRENT_PROMISES() {
-    return 8;
-  }
-
-  /**
-   * Run several promises concurrently
-   *
-   * @param {Array<Promise>} promises
-   * @return {Array}
-   */
-  static runPromises(promises) {
-    let allResults = [];
-    function handleResult(result) {
-      allResults.push(result);
-    }
-
-    return Utils.processAsyncQueue(Utils.MAX_CONCURRENT_PROMISES, promises, function(promise, index, next) {
-      promise.then(handleResult).catch(handleResult).then(function () {
-        next(index);
-      });
-    }).then(function() {
-      return allResults;
-    });
-  }
-
-  /**
-   * @param {Number} concurrency
-   * @param {Array} items
-   * @param {function} fn
-   * @return {Promise}
-   */
-  static processAsyncQueue(concurrency, items, fn) {
-    let maxWorkers = Math.min(concurrency, items.length);
-    let queue = items.slice(0);
-    let workers = 0;
-    let index = 0;
-    let finished = false;
-
-    const isQueueEmpty = function(queue) {
-      return queue.reduce(function(prev, val) {
-        if (val) {
-          prev++;
-        }
-
-        return prev;
-      }, 0) === 0;
-    };
-
-    const next = function(done = function() {}, currentIndex) {
-      queue[currentIndex] = null;
-
-      if (isQueueEmpty(queue)) {
-        done();
-        finished = true;
-      } else if (!finished) {
-        workers -= 1;
-        process();
-      }
-    };
-
-    const process = function(done) {
-      while (workers < maxWorkers) {
-        workers += 1;
-
-        if (queue[index]) {
-          let item = queue[index];
-          fn(item, index, function(idx) {
-            next(done, idx);
-          });
-          index++;
-        }
-
-      }
-    };
-
-    return new Promise(function(resolve, reject) {
-      process(function() {
-        resolve();
-      });
-    });
-  }
-
   static getModuleKey(filePath, srcFolders, fullPaths) {
     let modulePathParts = filePath.split(path.sep);
     let diffInFolder = '';
@@ -511,7 +429,7 @@ class Utils {
   }
 
   static relativeUrl(url) {
-    return !(url.startsWith('http://') || url.startsWith('https://'));
+    return !(url.includes('://'));
   }
 
   static uriJoin(baseUrl, uriPath) {
diff --git a/package-lock.json b/package-lock.json
index c8bde373..c9aa7a1f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "nightwatch",
-  "version": "1.1.12",
+  "version": "1.2.1",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -26,12 +26,6 @@
         "trim-right": "^1.0.1"
       },
       "dependencies": {
-        "lodash": {
-          "version": "4.17.11",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-          "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
-          "dev": true
-        },
         "source-map": {
           "version": "0.5.7",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@@ -131,12 +125,6 @@
             "ms": "^2.1.1"
           }
         },
-        "lodash": {
-          "version": "4.17.11",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-          "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
-          "dev": true
-        },
         "ms": {
           "version": "2.1.1",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
@@ -154,14 +142,6 @@
         "esutils": "^2.0.2",
         "lodash": "^4.17.11",
         "to-fast-properties": "^2.0.0"
-      },
-      "dependencies": {
-        "lodash": {
-          "version": "4.17.11",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-          "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
-          "dev": true
-        }
       }
     },
     "acorn": {
@@ -1708,9 +1688,9 @@
       }
     },
     "lodash": {
-      "version": "4.17.11",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
       "dev": true
     },
     "lodash._arraycopy": {
@@ -1781,9 +1761,9 @@
       }
     },
     "lodash.defaultsdeep": {
-      "version": "4.6.0",
-      "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz",
-      "integrity": "sha1-vsECT4WxvZbL6kBbI8FK1kQ6b4E="
+      "version": "4.6.1",
+      "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz",
+      "integrity": "sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA=="
     },
     "lodash.flattendeep": {
       "version": "4.4.0",
@@ -1812,9 +1792,9 @@
       }
     },
     "lodash.merge": {
-      "version": "4.6.1",
-      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz",
-      "integrity": "sha1-rcJdnLmbk5HFliTzefu6YNcRHVQ="
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
     },
     "log-driver": {
       "version": "1.2.7",
diff --git a/package.json b/package.json
index 338aae43..6bd23a82 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
   "name": "nightwatch",
   "description": "Easy to use Node.js based End-to-End testing solution for browser based apps and websites, using the W3C WebDriver API.",
-  "version": "1.1.12",
+  "version": "1.2.1",
   "author": {
     "name": "Andrei Rusu",
     "email": "andrei@nightwatchjs.org"
@@ -20,8 +20,8 @@
     "dotenv": "7.0.0",
     "ejs": "^2.5.9",
     "lodash.clone": "3.0.3",
-    "lodash.defaultsdeep": "^4.6.0",
-    "lodash.merge": "^4.6.1",
+    "lodash.defaultsdeep": "^4.6.1",
+    "lodash.merge": "^4.6.2",
     "minimatch": "3.0.4",
     "mkpath": "1.0.0",
     "optimist": "^0.6.1",


Test patch:
diff --git a/test/lib/nightwatch.js b/test/lib/nightwatch.js
index 1a55c35c..066e35c6 100644
--- a/test/lib/nightwatch.js
+++ b/test/lib/nightwatch.js
@@ -86,8 +86,8 @@ module.exports = new function () {
     _client.startSession();
   };
 
-  this.initAsync = function(options) {
-    _client = this.createClient(options);
+  this.initAsync = function(options, reporter) {
+    _client = this.createClient(options, reporter);
     _client.start = function() {
       return this.queue.run().then(err => {
         if (err instanceof Error) {
diff --git a/test/sampletests/es6await/selenium/getlog/getLogTestES6.js b/test/sampletests/es6await/selenium/getlog/getLogTestES6.js
index e8709876..ec5dfb30 100644
--- a/test/sampletests/es6await/selenium/getlog/getLogTestES6.js
+++ b/test/sampletests/es6await/selenium/getlog/getLogTestES6.js
@@ -5,14 +5,14 @@ module.exports = {
     client.url('http://localhost');
 
     const logResult = await client.getLog();
-    assert.strictEqual(Array.isArray(logResult.value), true);
-    assert.strictEqual(logResult.value.length, 2);
+    assert.strictEqual(Array.isArray(logResult), true);
+    assert.strictEqual(logResult.length, 2);
 
     const logResultCallback = await client.getLog('browser', function(result) {
       return result;
     });
-    assert.strictEqual(Array.isArray(logResultCallback.value), true);
-    assert.strictEqual(logResultCallback.value.length, 2);
+    assert.strictEqual(Array.isArray(logResultCallback), true);
+    assert.strictEqual(logResultCallback.length, 2);
 
     let interval = new Date().getTime();
     const logResultBrowser = await client.getLog(function(result) {
@@ -24,8 +24,8 @@ module.exports = {
       });
     });
 
-    assert.strictEqual(Array.isArray(logResultBrowser.value), true);
-    assert.strictEqual(logResultBrowser.value.length, 2);
+    assert.strictEqual(Array.isArray(logResultBrowser), true);
+    assert.strictEqual(logResultBrowser.length, 2);
     assert.strictEqual(interval >= 20, true, `Expected interval greater than 20 ms but got ${interval}`);
 
     await client.end();
diff --git a/test/sampletests/withverify/verifySampleFailures.js b/test/sampletests/withverify/verifySampleFailures.js
new file mode 100644
index 00000000..2164d7d6
--- /dev/null
+++ b/test/sampletests/withverify/verifySampleFailures.js
@@ -0,0 +1,18 @@
+module.exports = {
+  before(client) {
+    client.globals.calls++;
+  },
+
+  demoTest(client) {
+    client.url('http://localhost')
+      .verify.equal(0, 1, 'custom message')
+      .verify.elementPresent('#badElement')
+      .verify.elementPresent('#weblogin')
+      .end();
+  },
+
+  after(client, callback) {
+    client.globals.calls++;
+    callback();
+  }
+};
diff --git a/test/src/api/assertions/testAttributeContains.js b/test/src/api/assertions/testAttributeContains.js
index d3147aed..7b78a0b1 100644
--- a/test/src/api/assertions/testAttributeContains.js
+++ b/test/src/api/assertions/testAttributeContains.js
@@ -24,6 +24,27 @@ describe('assert.attributeContains', function () {
     }, done);
   });
 
+  it('attributeContains assertion passed with selector object', function (done) {
+    Globals.assertionTest({
+      assertionName: 'attributeContains',
+      args: [{
+        selector: '.test_element'
+      }, 'href', 'google'],
+      api: {
+        getAttribute(cssSelector, attribute, callback) {
+          assert.deepStrictEqual(cssSelector, {selector: '.test_element'});
+          callback({
+            value: 'http://www.google.com'
+          });
+        }
+      },
+      assertion(passed, value, calleeFn, message) {
+        assert.strictEqual(passed, true);
+        assert.ok(message.startsWith('Testing if attribute href of <.test_element> contains "google"'));
+      }
+    }, done);
+  });
+
   it('attributeContains assertion failed', function (done) {
     Globals.assertionTest({
       assertionName: 'attributeContains',
diff --git a/test/src/api/assertions/testAttributeEquals.js b/test/src/api/assertions/testAttributeEquals.js
index 02105d71..b268b3d8 100644
--- a/test/src/api/assertions/testAttributeEquals.js
+++ b/test/src/api/assertions/testAttributeEquals.js
@@ -8,16 +8,35 @@ describe('assert.attributeEquals', function () {
       args: ['.test_element', 'role', 'main', 'Test message'],
       api: {
         getAttribute(cssSelector, attribute, callback) {
-          assert.equal(cssSelector, '.test_element');
-          assert.equal(attribute, 'role');
+          assert.strictEqual(cssSelector, '.test_element');
+          assert.strictEqual(attribute, 'role');
           callback({
             value: 'main'
           });
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, true);
-        assert.equal(value, 'main');
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'main');
+      }
+    }, done);
+  });
+
+  it('attributeEquals assertion passed with selector object', function (done) {
+    Globals.assertionTest({
+      assertionName: 'attributeEquals',
+      args: [{selector: '.test_element'}, 'role', 'main'],
+      api: {
+        getAttribute(cssSelector, attribute, callback) {
+          assert.deepStrictEqual(cssSelector, {selector: '.test_element'});
+          callback({
+            value: 'main'
+          });
+        }
+      },
+      assertion(passed, value, calleeFn, message) {
+        assert.strictEqual(passed, true);
+        assert.ok(message.startsWith('Testing if attribute role of <.test_element> equals "main"'));
       }
     }, done);
   });
@@ -34,8 +53,8 @@ describe('assert.attributeEquals', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, 'not_expected');
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, 'not_expected');
       }
     }, done);
   });
@@ -52,8 +71,8 @@ describe('assert.attributeEquals', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, null);
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, null);
       }
     }, done);
   });
@@ -71,8 +90,8 @@ describe('assert.attributeEquals', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, null);
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, null);
         assert.ok(message.startsWith('Testing if attribute role of <.test_element> equals "main". Element does not have a role attribute'));
       }
     }, done);
diff --git a/test/src/api/assertions/testContainsText.js b/test/src/api/assertions/testContainsText.js
index 0d00e081..a37c6686 100644
--- a/test/src/api/assertions/testContainsText.js
+++ b/test/src/api/assertions/testContainsText.js
@@ -8,15 +8,34 @@ describe('assert.containsText', function () {
       args: ['.test_element', 'text result', 'Test message'],
       api: {
         getText(cssSelector, callback) {
-          assert.equal(cssSelector, '.test_element');
+          assert.strictEqual(cssSelector, '.test_element');
           callback({
             value: 'expected text result'
           });
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, true);
-        assert.equal(value, 'expected text result');
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'expected text result');
+      }
+    }, done);
+  });
+
+  it('containsText assertion passed with selector object', function (done) {
+    Globals.assertionTest({
+      assertionName: 'containsText',
+      args: [{selector: '.test_element'}, 'text result'],
+      api: {
+        getText(cssSelector, callback) {
+          assert.deepStrictEqual(cssSelector, {selector: '.test_element'});
+          callback({
+            value: 'expected text result'
+          });
+        }
+      },
+      assertion(passed, value, calleeFn, message) {
+        assert.strictEqual(passed, true);
+        assert.ok(message.startsWith('Testing if element <.test_element> contains text: "text result"'));
       }
     }, done);
   });
@@ -33,8 +52,8 @@ describe('assert.containsText', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, 'not_expected');
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, 'not_expected');
       }
     }, done);
   });
@@ -51,8 +70,8 @@ describe('assert.containsText', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, null);
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, null);
       }
     }, done);
   });
diff --git a/test/src/api/assertions/testCssClassNotPresent.js b/test/src/api/assertions/testCssClassNotPresent.js
index 048c94e5..ca58b78f 100644
--- a/test/src/api/assertions/testCssClassNotPresent.js
+++ b/test/src/api/assertions/testCssClassNotPresent.js
@@ -8,16 +8,35 @@ describe('assert.cssClassNotPresent', function () {
       args: ['.test_element', 'test-css-class'],
       api: {
         getAttribute(cssSelector, attribute, callback) {
-          assert.equal(cssSelector, '.test_element');
-          assert.equal(attribute, 'class');
+          assert.strictEqual(cssSelector, '.test_element');
+          assert.strictEqual(attribute, 'class');
           callback({
             value: 'other-css-class some-css-class'
           });
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, true);
-        assert.equal(value, 'other-css-class some-css-class');
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'other-css-class some-css-class');
+        assert.ok(message.startsWith('Testing if element <.test_element> does not have css class: "test-css-class"'));
+      }
+    }, done);
+  });
+
+  it('cssClassNotPresent assertion passed with selector object', function (done) {
+    Globals.assertionTest({
+      assertionName: 'cssClassNotPresent',
+      args: [{selector: '.test_element'}, 'test-css-class'],
+      api: {
+        getAttribute(cssSelector, attribute, callback) {
+          assert.deepStrictEqual(cssSelector, {selector: '.test_element'});
+          callback({
+            value: 'other-css-class some-css-class'
+          });
+        }
+      },
+      assertion(passed, value, calleeFn, message) {
+        assert.strictEqual(passed, true);
         assert.ok(message.startsWith('Testing if element <.test_element> does not have css class: "test-css-class"'));
       }
     }, done);
@@ -35,8 +54,8 @@ describe('assert.cssClassNotPresent', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, 'test-css-class other-css-class');
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, 'test-css-class other-css-class');
       }
     }, done);
   });
@@ -53,8 +72,8 @@ describe('assert.cssClassNotPresent', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, null);
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, null);
       }
     }, done);
   });
diff --git a/test/src/api/assertions/testCssClassPresent.js b/test/src/api/assertions/testCssClassPresent.js
index dc94d080..cd328a10 100644
--- a/test/src/api/assertions/testCssClassPresent.js
+++ b/test/src/api/assertions/testCssClassPresent.js
@@ -8,8 +8,28 @@ describe('assert.cssClassPresent', function () {
       args: ['.test_element', 'test-css-class'],
       api: {
         getAttribute(cssSelector, attribute, callback) {
-          assert.equal(cssSelector, '.test_element');
-          assert.equal(attribute, 'class');
+          assert.strictEqual(cssSelector, '.test_element');
+          assert.strictEqual(attribute, 'class');
+          callback({
+            value: 'other-css-class test-css-class'
+          });
+        }
+      },
+      assertion(passed, value, calleeFn, message) {
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'other-css-class test-css-class');
+        assert.ok(message.startsWith('Testing if element <.test_element> has css class: "test-css-class"'));
+      }
+    }, done);
+  });
+
+  it('cssClassPresent assertion passed with selector object', function (done) {
+    Globals.assertionTest({
+      assertionName: 'cssClassPresent',
+      args: [{selector: '.test_element'}, 'test-css-class'],
+      api: {
+        getAttribute(cssSelector, attribute, callback) {
+          assert.deepStrictEqual(cssSelector, {selector: '.test_element'});
           callback({
             value: 'other-css-class test-css-class'
           });
@@ -17,7 +37,6 @@ describe('assert.cssClassPresent', function () {
       },
       assertion(passed, value, calleeFn, message) {
         assert.strictEqual(passed, true);
-        assert.equal(value, 'other-css-class test-css-class');
         assert.ok(message.startsWith('Testing if element <.test_element> has css class: "test-css-class"'));
       }
     }, done);
@@ -36,7 +55,7 @@ describe('assert.cssClassPresent', function () {
       },
       assertion(passed, value, calleeFn, message) {
         assert.strictEqual(passed, false);
-        assert.equal(value, 'other-css-class');
+        assert.strictEqual(value, 'other-css-class');
       }
     }, done);
   });
@@ -53,8 +72,8 @@ describe('assert.cssClassPresent', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, null);
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, null);
       }
     }, done);
   });
diff --git a/test/src/api/assertions/testCssProperty.js b/test/src/api/assertions/testCssProperty.js
index 1455951a..54e66317 100644
--- a/test/src/api/assertions/testCssProperty.js
+++ b/test/src/api/assertions/testCssProperty.js
@@ -8,16 +8,36 @@ describe('assert.cssProperty', function () {
       args: ['.test_element', 'display', 'none'],
       api: {
         getCssProperty(cssSelector, property, callback) {
-          assert.equal(cssSelector, '.test_element');
-          assert.equal(property, 'display');
+          assert.strictEqual(cssSelector, '.test_element');
+          assert.strictEqual(property, 'display');
           callback({
             value: 'none'
           });
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, true);
-        assert.equal(value, 'none');
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'none');
+        assert.ok(message.startsWith('Testing if element <.test_element> has css property "display: none"'));
+      }
+    }, done);
+  });
+
+  it('cssProperty assertion passed with selector object', function (done) {
+    Globals.assertionTest({
+      assertionName: 'cssProperty',
+      args: [{selector: '.test_element'}, 'display', 'none'],
+      api: {
+        getCssProperty(cssSelector, property, callback) {
+          assert.deepStrictEqual(cssSelector, {selector: '.test_element'});
+          callback({
+            value: 'none'
+          });
+        }
+      },
+      assertion(passed, value, calleeFn, message) {
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'none');
         assert.ok(message.startsWith('Testing if element <.test_element> has css property "display: none"'));
       }
     }, done);
@@ -29,16 +49,16 @@ describe('assert.cssProperty', function () {
       args: ['.test_element', 'display', 'none'],
       api: {
         getCssProperty(cssSelector, property, callback) {
-          assert.equal(cssSelector, '.test_element');
-          assert.equal(property, 'display');
+          assert.strictEqual(cssSelector, '.test_element');
+          assert.strictEqual(property, 'display');
           callback({
             value: 'block'
           });
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, 'block');
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, 'block');
       }
     }, done);
   });
@@ -55,8 +75,8 @@ describe('assert.cssProperty', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, null);
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, null);
         assert.ok(message.startsWith('Testing if element <.test_element> has css property display. Element or attribute could not be located'));
       }
     }, done);
diff --git a/test/src/api/assertions/testElementNotPresent.js b/test/src/api/assertions/testElementNotPresent.js
index f46b4286..c4b5bf0e 100644
--- a/test/src/api/assertions/testElementNotPresent.js
+++ b/test/src/api/assertions/testElementNotPresent.js
@@ -8,8 +8,8 @@ describe('assert.elementNotPresent', function () {
       args: ['.test_element'],
       api: {
         elements(using, selector, callback) {
-          assert.equal(selector, '.test_element');
-          assert.equal(using, 'css selector');
+          assert.strictEqual(selector.selector, '.test_element');
+          assert.strictEqual(using, 'css selector');
           callback({
             status: 0,
             value: []
@@ -17,8 +17,30 @@ describe('assert.elementNotPresent', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, true);
-        assert.equal(value, 'not present');
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'not present');
+        assert.ok(message.startsWith('Testing if element <.test_element> is not present'));
+      }
+    }, done);
+  });
+
+  it('elementNotPresent assertion passed with selector object', function (done) {
+    Globals.assertionTest({
+      assertionName: 'elementNotPresent',
+      args: [{selector: '.test_element'}],
+      api: {
+        elements(using, selector, callback) {
+          assert.strictEqual(selector.selector, '.test_element');
+
+          callback({
+            status: 0,
+            value: []
+          });
+        }
+      },
+      assertion(passed, value, calleeFn, message) {
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'not present');
         assert.ok(message.startsWith('Testing if element <.test_element> is not present'));
       }
     }, done);
@@ -30,8 +52,8 @@ describe('assert.elementNotPresent', function () {
       args: ['.test_element'],
       api: {
         elements(using, selector, callback) {
-          assert.equal(selector, '.test_element');
-          assert.equal(using, 'css selector');
+          assert.strictEqual(selector.selector, '.test_element');
+          assert.strictEqual(using, 'css selector');
           callback({
             value: []
           });
@@ -39,7 +61,7 @@ describe('assert.elementNotPresent', function () {
       },
       assertion(passed, value, calleeFn, message) {
         assert.strictEqual(passed, true);
-        assert.equal(value, 'not present');
+        assert.strictEqual(value, 'not present');
         assert.ok(message.startsWith('Testing if element <.test_element> is not present'));
       }
     }, done);
@@ -51,8 +73,8 @@ describe('assert.elementNotPresent', function () {
       args: ['.test_element'],
       api: {
         elements(using, selector, callback) {
-          assert.equal(selector, '.test_element');
-          assert.equal(using, 'css selector');
+          assert.strictEqual(selector.selector, '.test_element');
+          assert.strictEqual(using, 'css selector');
           callback({
             status: -1,
             value: null
@@ -60,8 +82,8 @@ describe('assert.elementNotPresent', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, true);
-        assert.equal(value, 'not present');
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'not present');
         assert.ok(message.startsWith('Testing if element <.test_element> is not present'));
       }
     }, done);
@@ -73,8 +95,8 @@ describe('assert.elementNotPresent', function () {
       args: ['.test_element'],
       api: {
         elements(using, selector, callback) {
-          assert.equal(selector, '.test_element');
-          assert.equal(using, 'css selector');
+          assert.strictEqual(selector.selector, '.test_element');
+          assert.strictEqual(using, 'css selector');
           callback({
             status: 0,
             value: [{
@@ -84,8 +106,8 @@ describe('assert.elementNotPresent', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, 'present');
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, 'present');
       }
     }, done);
   });
diff --git a/test/src/api/assertions/testElementPresent.js b/test/src/api/assertions/testElementPresent.js
index e5ccfc18..ee98151f 100644
--- a/test/src/api/assertions/testElementPresent.js
+++ b/test/src/api/assertions/testElementPresent.js
@@ -8,8 +8,8 @@ describe('assert.elementPresent', function() {
       args: ['.test_element'],
       api: {
         elements(using, selector, callback) {
-          assert.equal(selector, '.test_element');
-          assert.equal(using, 'css selector');
+          assert.strictEqual(selector.selector, '.test_element');
+          assert.strictEqual(using, 'css selector');
           callback({
             status : 0,
             value : [{
@@ -20,7 +20,31 @@ describe('assert.elementPresent', function() {
       },
       assertion(passed, value, calleeFn, message) {
         assert.strictEqual(passed, true);
-        assert.equal(value, 'present');
+        assert.strictEqual(value, 'present');
+        assert.ok(message.startsWith('Testing if element <.test_element> is present'));
+      }
+    }, done);
+  });
+
+  it('elementPresent assertion passed with selector object', function(done) {
+    Globals.assertionTest({
+      assertionName: 'elementPresent',
+      args: [{selector: '.test_element'}],
+      api: {
+        elements(using, selector, callback) {
+          assert.strictEqual(selector.selector, '.test_element');
+          assert.strictEqual(using, 'css selector');
+          callback({
+            status : 0,
+            value : [{
+              ELEMENT : '0'
+            }]
+          });
+        }
+      },
+      assertion(passed, value, calleeFn, message) {
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'present');
         assert.ok(message.startsWith('Testing if element <.test_element> is present'));
       }
     }, done);
@@ -32,8 +56,8 @@ describe('assert.elementPresent', function() {
       args: ['.test_element'],
       api: {
         elements(using, selector, callback) {
-          assert.equal(selector, '.test_element');
-          assert.equal(using, 'css selector');
+          assert.strictEqual(selector.selector, '.test_element');
+          assert.strictEqual(using, 'css selector');
           callback({
             value:
               [{'element-6066-11e4-a52e-4f735466cecf': 'b8461b6b-7c4b-ac46-8b1a-7071c3b111f1'}]
@@ -42,7 +66,7 @@ describe('assert.elementPresent', function() {
       },
       assertion(passed, value, calleeFn, message) {
         assert.strictEqual(passed, true);
-        assert.equal(value, 'present');
+        assert.strictEqual(value, 'present');
         assert.ok(message.startsWith('Testing if element <.test_element> is present'));
       }
     }, done);
@@ -54,8 +78,8 @@ describe('assert.elementPresent', function() {
       args: ['.test_element'],
       api: {
         elements(using, selector, callback) {
-          assert.equal(selector, '.test_element');
-          assert.equal(using, 'css selector');
+          assert.strictEqual(selector.selector, '.test_element');
+          assert.strictEqual(using, 'css selector');
           callback({
             status : 0,
             value : []
@@ -64,7 +88,7 @@ describe('assert.elementPresent', function() {
       },
       assertion(passed, value, calleeFn, message) {
         assert.strictEqual(passed, false);
-        assert.equal(value, 'not present');
+        assert.strictEqual(value, 'not present');
         assert.ok(message.startsWith('Testing if element <.test_element> is present'));
       }
     }, done);
diff --git a/test/src/api/assertions/testHidden.js b/test/src/api/assertions/testHidden.js
index 42ef1786..32cae165 100644
--- a/test/src/api/assertions/testHidden.js
+++ b/test/src/api/assertions/testHidden.js
@@ -8,7 +8,7 @@ describe('assert.hidden', function () {
       args: ['.test_element'],
       api: {
         isVisible(cssSelector, callback) {
-          assert.equal(cssSelector, '.test_element');
+          assert.strictEqual(cssSelector, '.test_element');
           callback({
             status: 0,
             value: false
@@ -16,8 +16,29 @@ describe('assert.hidden', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, true);
-        assert.equal(value, true);
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, true);
+        assert.ok(message.startsWith('Testing if element <.test_element> is hidden'));
+      }
+    }, done);
+  });
+
+  it('hidden assertion passed with selector object', function (done) {
+    Globals.assertionTest({
+      assertionName: 'hidden',
+      args: [{selector: '.test_element'}],
+      api: {
+        isVisible(cssSelector, callback) {
+          assert.deepStrictEqual(cssSelector, {selector: '.test_element'});
+          callback({
+            status: 0,
+            value: false
+          });
+        }
+      },
+      assertion(passed, value, calleeFn, message) {
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, true);
         assert.ok(message.startsWith('Testing if element <.test_element> is hidden'));
       }
     }, done);
@@ -29,7 +50,7 @@ describe('assert.hidden', function () {
       args: ['.test_element'],
       api: {
         isVisible(cssSelector, callback) {
-          assert.equal(cssSelector, '.test_element');
+          assert.strictEqual(cssSelector, '.test_element');
           callback({
             status: 0,
             value: true
@@ -37,8 +58,8 @@ describe('assert.hidden', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, false);
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, false);
       }
     }, done);
   });
@@ -49,15 +70,15 @@ describe('assert.hidden', function () {
       args: ['.test_element'],
       api: {
         isVisible(cssSelector, callback) {
-          assert.equal(cssSelector, '.test_element');
+          assert.strictEqual(cssSelector, '.test_element');
           callback({
             status: -1
           });
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, null);
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, null);
         assert.ok(message.startsWith('Testing if element <.test_element> is hidden. Element could not be located'));
       }
     }, done);
diff --git a/test/src/api/assertions/testValue.js b/test/src/api/assertions/testValue.js
index 22d3adbc..85130987 100644
--- a/test/src/api/assertions/testValue.js
+++ b/test/src/api/assertions/testValue.js
@@ -8,7 +8,7 @@ describe('assert.value', function () {
       args: ['.test_element', 'some-value'],
       api: {
         getValue(cssSelector, callback) {
-          assert.equal(cssSelector, '.test_element');
+          assert.strictEqual(cssSelector, '.test_element');
           callback({
             status: 0,
             value: 'some-value'
@@ -16,8 +16,29 @@ describe('assert.value', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, true);
-        assert.equal(value, 'some-value');
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'some-value');
+        assert.ok(message.startsWith('Testing if value of <.test_element> equals: "some-value"'));
+      }
+    }, done);
+  });
+
+  it('value assertion passed with selector object', function (done) {
+    Globals.assertionTest({
+      assertionName: 'value',
+      args: [{selector: '.test_element'}, 'some-value'],
+      api: {
+        getValue(cssSelector, callback) {
+          assert.deepStrictEqual(cssSelector, {selector: '.test_element'});
+          callback({
+            status: 0,
+            value: 'some-value'
+          });
+        }
+      },
+      assertion(passed, value, calleeFn, message) {
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'some-value');
         assert.ok(message.startsWith('Testing if value of <.test_element> equals: "some-value"'));
       }
     }, done);
@@ -29,7 +50,7 @@ describe('assert.value', function () {
       args: ['.test_element', 'some-value'],
       api: {
         getValue(cssSelector, callback) {
-          assert.equal(cssSelector, '.test_element');
+          assert.strictEqual(cssSelector, '.test_element');
           callback({
             status: 0,
             value: 'wrong-value'
@@ -37,8 +58,8 @@ describe('assert.value', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, 'wrong-value');
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, 'wrong-value');
       }
     }, done);
   });
@@ -55,8 +76,8 @@ describe('assert.value', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, null);
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, null);
         assert.ok(message.startsWith('Testing if value of <.test_element> equals: "some-value". Element or attribute could not be located'));
       }
     }, done);
diff --git a/test/src/api/assertions/testValueContains.js b/test/src/api/assertions/testValueContains.js
index cc2fbf43..d77ae000 100644
--- a/test/src/api/assertions/testValueContains.js
+++ b/test/src/api/assertions/testValueContains.js
@@ -8,7 +8,7 @@ describe('assert.valueContains', function () {
       args: ['.test_element', 'some-value'],
       api: {
         getValue(cssSelector, callback) {
-          assert.equal(cssSelector, '.test_element');
+          assert.strictEqual(cssSelector, '.test_element');
           callback({
             status: 0,
             value: 'contains-some-value'
@@ -16,8 +16,29 @@ describe('assert.valueContains', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, true);
-        assert.equal(value, 'contains-some-value');
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'contains-some-value');
+        assert.ok(message.startsWith('Testing if value of <.test_element> contains: "some-value"'));
+      }
+    }, done);
+  });
+
+  it('valueContains assertion passed with selector object', function (done) {
+    Globals.assertionTest({
+      assertionName: 'valueContains',
+      args: [{selector: '.test_element'}, 'some-value'],
+      api: {
+        getValue(cssSelector, callback) {
+          assert.deepStrictEqual(cssSelector, {selector: '.test_element'});
+          callback({
+            status: 0,
+            value: 'contains-some-value'
+          });
+        }
+      },
+      assertion(passed, value, calleeFn, message) {
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'contains-some-value');
         assert.ok(message.startsWith('Testing if value of <.test_element> contains: "some-value"'));
       }
     }, done);
@@ -29,7 +50,7 @@ describe('assert.valueContains', function () {
       args: ['.test_element', 'some-value'],
       api: {
         getValue(cssSelector, callback) {
-          assert.equal(cssSelector, '.test_element');
+          assert.strictEqual(cssSelector, '.test_element');
           callback({
             status: 0,
             value: 'wrong-value'
@@ -37,8 +58,8 @@ describe('assert.valueContains', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, 'wrong-value');
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, 'wrong-value');
       }
     }, done);
   });
@@ -49,15 +70,15 @@ describe('assert.valueContains', function () {
       args: ['.test_element', 'some-value'],
       api: {
         getValue(cssSelector, callback) {
-          assert.equal(cssSelector, '.test_element');
+          assert.strictEqual(cssSelector, '.test_element');
           callback({
             status: -1
           });
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, null);
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, null);
         assert.ok(message.startsWith('Testing if value of <.test_element> contains: "some-value". Element could not be located'));
       }
     }, done);
@@ -98,9 +119,9 @@ describe('assert.valueContains', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, true);
-        assert.equal(value, 'contains-some-value');
-        assert.equal(calls, 2);
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, 'contains-some-value');
+        assert.strictEqual(calls, 2);
         assert.ok(message.startsWith('Testing if value of <.test_element> contains: "some-value". Element could not be located'));
       }
     }, done);
@@ -119,8 +140,8 @@ describe('assert.valueContains', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, null);
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, null);
         assert.ok(message.startsWith('Testing if value of <.test_element> contains: "some-value". Element does not have a value attribute'));
       }
     }, done);
diff --git a/test/src/api/assertions/testVisible.js b/test/src/api/assertions/testVisible.js
index 2193fdd8..4ed8c596 100644
--- a/test/src/api/assertions/testVisible.js
+++ b/test/src/api/assertions/testVisible.js
@@ -8,7 +8,7 @@ describe('assert.visible', function () {
       args: ['.test_element'],
       api: {
         isVisible(cssSelector, callback) {
-          assert.equal(cssSelector, '.test_element');
+          assert.strictEqual(cssSelector, '.test_element');
           callback({
             status: 0,
             value: true
@@ -16,8 +16,29 @@ describe('assert.visible', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, true);
-        assert.equal(value, true);
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, true);
+        assert.ok(message.startsWith('Testing if element <.test_element> is visible'));
+      }
+    }, done);
+  });
+
+  it('visible assertion passed with selector object', function (done) {
+    Globals.assertionTest({
+      assertionName: 'visible',
+      args: [{selector: '.test_element'}],
+      api: {
+        isVisible(cssSelector, callback) {
+          assert.deepStrictEqual(cssSelector, {selector: '.test_element'});
+          callback({
+            status: 0,
+            value: true
+          });
+        }
+      },
+      assertion(passed, value, calleeFn, message) {
+        assert.strictEqual(passed, true);
+        assert.strictEqual(value, true);
         assert.ok(message.startsWith('Testing if element <.test_element> is visible'));
       }
     }, done);
@@ -29,7 +50,7 @@ describe('assert.visible', function () {
       args: ['.test_element'],
       api: {
         isVisible(cssSelector, callback) {
-          assert.equal(cssSelector, '.test_element');
+          assert.strictEqual(cssSelector, '.test_element');
           callback({
             status: 0,
             value: false
@@ -37,13 +58,13 @@ describe('assert.visible', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false);
-        assert.equal(value, false);
+        assert.strictEqual(passed, false);
+        assert.strictEqual(value, false);
       }
     }, done);
   });
 
-  it('visible assertion not found', function (done) {
+  it('visible assertion not - element not found', function (done) {
     Globals.assertionTest({
       assertionName: 'visible',
       args: ['.test_element'],
@@ -55,8 +76,8 @@ describe('assert.visible', function () {
         }
       },
       assertion(passed, value, calleeFn, message) {
-        assert.equal(passed, false, 'Assertion failed');
-        assert.equal(value, null);
+        assert.strictEqual(passed, false, 'Assertion failed');
+        assert.strictEqual(value, null);
         assert.ok(message.startsWith('Testing if element <.test_element> is visible. Element could not be located'));
       }
     }, done);
diff --git a/test/src/api/commands/testWaitForElementVisible.js b/test/src/api/commands/testWaitForElementVisible.js
index 81d2474e..b4bbeebf 100644
--- a/test/src/api/commands/testWaitForElementVisible.js
+++ b/test/src/api/commands/testWaitForElementVisible.js
@@ -189,8 +189,9 @@ describe('waitForElementVisible', function() {
     });
   });
 
-  it('client.waitForElementVisible() with element not found', function () {
+  it('client.waitForElementVisible() with element not found', function (done) {
     const assertion = [];
+    let result;
 
     NightwatchAssertion.create = function(...args) {
       assertion.unshift(...args);
@@ -204,12 +205,23 @@ describe('waitForElementVisible', function() {
 
     this.client.api.globals.abortOnAssertionFailure = false;
     this.client.api.globals.waitForConditionPollInterval = 5;
-    this.client.api.waitForElementVisible('.weblogin', 11, function (result, instance) {
-      NightwatchAssertion.create = createOrig;
+    this.client.api.waitForElementVisible('.weblogin', 11, function (res, instance) {
+      result = res;
     });
 
-    return this.client.start(function(err) {
-      assert.strictEqual(err.name, 'NoSuchElementError');
+    this.client.start(function(e) {
+      try {
+        assert.strictEqual(result.value, false);
+        assert.strictEqual(result.status, -1);
+        assert.strictEqual(result.err.value, null);
+        assert.strictEqual(assertion[0], false);
+        assert.deepStrictEqual(assertion[1], { actual: 'not found', expected: 'visible' });
+
+        NightwatchAssertion.create = createOrig;
+        done();
+      } catch (err) {
+        done(err);
+      }
     });
   });
 
diff --git a/test/src/api/commands/testWindowCommands.js b/test/src/api/commands/testWindowCommands.js
index f80254cf..96a6143a 100644
--- a/test/src/api/commands/testWindowCommands.js
+++ b/test/src/api/commands/testWindowCommands.js
@@ -49,4 +49,59 @@ describe('window', function () {
 
     this.client.start(done);
   });
+
+  it('client.setWindowRect()', function (done) {
+    MockServer.addMock({
+      url : '/wd/hub/session/1352110219202/window/rect',
+      method:'POST',
+      response : JSON.stringify({
+        sessionId: '1352110219202',
+        status:0
+      })
+    });
+
+    this.client.api.setWindowRect({width: 100, height: 100}, function(res) {
+      assert.strictEqual(res.status, 0);
+    });
+
+    this.client.start(done);
+  });
+
+  it('client.getWindowRect()', function (done) {
+    MockServer.addMock({
+      url : '/wd/hub/session/1352110219202/window/rect',
+      method:'GET',
+      response : JSON.stringify({
+        value: {
+          width: 1000,
+          height: 1000,
+          x: 100,
+          y: 100
+        }
+      })
+    });
+
+    this.client.api.getWindowRect(function(value) {
+      assert.deepStrictEqual(value, {width: 1000, height: 1000, x: 100, y: 100});
+    });
+
+    this.client.start(done);
+  });
+
+  it('client.setWindowSize()', function (done) {
+    MockServer.addMock({
+      url : '/wd/hub/session/1352110219202/window/current/size',
+      method:'POST',
+      response : JSON.stringify({
+        sessionId: '1352110219202',
+        status:0
+      })
+    });
+
+    this.client.api.setWindowSize(100, 100, function(res) {
+      assert.strictEqual(res.status, 0);
+    });
+
+    this.client.start(done);
+  });
 });
diff --git a/test/src/api/protocol/testTimeouts.js b/test/src/api/protocol/testTimeouts.js
index a155328a..2813c95a 100644
--- a/test/src/api/protocol/testTimeouts.js
+++ b/test/src/api/protocol/testTimeouts.js
@@ -25,7 +25,7 @@ describe('timeouts commands', function() {
       commandName: 'timeouts',
       args: ['nonscript', 1000]
     }).catch(err => {
-      assert.equal(err.message, 'Invalid timeouts type value: nonscript. Accepted values are: script, implicit, page load');
+      assert.equal(err.message, 'Invalid timeouts type value: nonscript. Accepted values are: script, implicit, page load, pageLoad');
 
       return true;
     }).then(result => assert.strictEqual(result, true));
diff --git a/test/src/api/protocol/testWindowCommands.js b/test/src/api/protocol/testWindowCommands.js
index 01cd65a9..83ddede4 100644
--- a/test/src/api/protocol/testWindowCommands.js
+++ b/test/src/api/protocol/testWindowCommands.js
@@ -6,43 +6,22 @@ describe('window commands', function() {
     Globals.protocolBefore.call(this);
   });
 
-  it('testWindowHandle', function() {
+  it('test .windowHandle()', function() {
     return Globals.protocolTest.call(this, {
       assertion: function(opts) {
-        assert.equal(opts.method, 'GET');
-        assert.equal(opts.path, '/session/1352110219202/window_handle');
+        assert.strictEqual(opts.method, 'GET');
+        assert.strictEqual(opts.path, '/session/1352110219202/window_handle');
       },
       commandName: 'windowHandle',
       args: []
     });
   });
 
-  it('testWindowHandle W3C WebDriver', function() {
-    return Globals.protocolTestWebdriver.call(this, {
-      assertion: function(opts) {
-        assert.equal(opts.path, '/session/1352110219202/window/handle');
-      },
-      commandName: 'windowHandle',
-      args: []
-    });
-  });
-
-  it('testWindowHandlePlural', function() {
+  it('test .windowHandles()', function() {
     return Globals.protocolTest.call(this, {
       assertion: function(opts) {
-        assert.equal(opts.method, 'GET');
-        assert.equal(opts.path, '/session/1352110219202/window_handles');
-      },
-      commandName: 'windowHandles',
-      args: []
-    });
-  });
-
-  it('testWindowHandlePlural W3C WebDriver', function() {
-    return Globals.protocolTestWebdriver.call(this, {
-      assertion: function(opts) {
-        assert.equal(opts.method, 'GET');
-        assert.equal(opts.path, '/session/1352110219202/window/handles');
+        assert.strictEqual(opts.method, 'GET');
+        assert.strictEqual(opts.path, '/session/1352110219202/window_handles');
       },
       commandName: 'windowHandles',
       args: []
@@ -52,8 +31,8 @@ describe('window commands', function() {
   it('testCloseWindow', function() {
     return Globals.protocolTest.call(this, {
       assertion: function(opts) {
-        assert.equal(opts.method, 'DELETE');
-        assert.equal(opts.path, '/session/1352110219202/window');
+        assert.strictEqual(opts.method, 'DELETE');
+        assert.strictEqual(opts.path, '/session/1352110219202/window');
       },
       commandName: 'window',
       args: ['DELETE']
@@ -63,8 +42,8 @@ describe('window commands', function() {
   it('testSwitchWindow', function() {
     return Globals.protocolTest.call(this, {
       assertion: function(opts) {
-        assert.equal(opts.method, 'POST');
-        assert.equal(opts.path, '/session/1352110219202/window');
+        assert.strictEqual(opts.method, 'POST');
+        assert.strictEqual(opts.path, '/session/1352110219202/window');
         assert.deepEqual(opts.data, {name: 'other-window'});
       },
       commandName: 'window',
@@ -72,17 +51,6 @@ describe('window commands', function() {
     });
   });
 
-  it('testSwitchWindow W3C WebDriver', function() {
-    return Globals.protocolTestWebdriver.call(this, {
-      assertion: function(opts) {
-        assert.equal(opts.path, '/session/1352110219202/window');
-        assert.deepEqual(opts.data, {handle: 'other-window'});
-      },
-      commandName: 'window',
-      args: ['POST', 'other-window']
-    });
-  });
-
   it('testWindowCommand', function() {
     let protocol = this.protocol;
 
@@ -97,7 +65,107 @@ describe('window commands', function() {
         protocol.window('GET');
       }, 'GET method throws an error'
     );
+  });
+
+  it('test .minimizeWindow()', function() {
+    return Globals.protocolTest.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.method, 'POST');
+        assert.strictEqual(opts.path, '/session/1352110219202/window/minimize');
+      },
+      commandName: 'minimizeWindow'
+    });
+  });
 
+  ////////////////////////////////////////////////////////////////////////
+  // W3C Webdriver
+  ////////////////////////////////////////////////////////////////////////
+  it('testSwitchWindow W3C WebDriver', function() {
+    return Globals.protocolTestWebdriver.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.path, '/session/1352110219202/window');
+        assert.deepEqual(opts.data, {handle: 'other-window'});
+      },
+      commandName: 'window',
+      args: ['POST', 'other-window']
+    });
+  });
+
+  it('test .windowHandle() W3C WebDriver', function() {
+    return Globals.protocolTestWebdriver.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.path, '/session/1352110219202/window');
+      },
+      commandName: 'windowHandle',
+      args: []
+    });
+  });
+
+  it('test .windowMaximize()', function() {
+    return Globals.protocolTest.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.path, '/session/1352110219202/window/current/maximize');
+      },
+      commandName: 'windowMaximize',
+      args: []
+    });
+  });
+
+  it('test .windowMaximize() W3C WebDriver', function() {
+    return Globals.protocolTestWebdriver.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.method, 'POST');
+        assert.strictEqual(opts.path, '/session/1352110219202/window/maximize');
+      },
+      commandName: 'windowMaximize',
+      args: []
+    });
+  });
+
+  it('test .windowHandles() W3C WebDriver', function() {
+    return Globals.protocolTestWebdriver.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.method, 'GET');
+        assert.strictEqual(opts.path, '/session/1352110219202/window/handles');
+      },
+      commandName: 'windowHandles',
+      args: []
+    });
+  });
+
+  it('test .minimizeWindow() W3C WebDriver', function() {
+    return Globals.protocolTestWebdriver.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.method, 'POST');
+        assert.strictEqual(opts.path, '/session/1352110219202/window/minimize');
+      },
+      commandName: 'minimizeWindow',
+      args: []
+    });
+  });
+
+  it('test .openNewWindow() W3C WebDriver', function() {
+    return Globals.protocolTestWebdriver.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.method, 'POST');
+        assert.deepEqual(opts.data, {type: 'tab'});
+        assert.strictEqual(opts.path, '/session/1352110219202/window/new');
+      },
+      commandName: 'openNewWindow',
+      args: []
+    });
+  });
+
+  it('test .openNewWindow() W3C WebDriver with specified type=window', function() {
+    return Globals.protocolTestWebdriver.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.method, 'POST');
+        assert.deepEqual(opts.data, {type: 'window'});
+        assert.strictEqual(opts.path, '/session/1352110219202/window/new');
+      },
+      commandName: 'openNewWindow',
+      args: ['window']
+    });
   });
 
 });
diff --git a/test/src/api/protocol/testWindowPosition.js b/test/src/api/protocol/testWindowPosition.js
index c2eafd9b..507e0d6b 100644
--- a/test/src/api/protocol/testWindowPosition.js
+++ b/test/src/api/protocol/testWindowPosition.js
@@ -6,7 +6,7 @@ describe('windowPosition', function() {
     Globals.protocolBefore.call(this);
   });
 
-  it('testWindowPositionGet without offsets and callback', function(done) {
+  it('test .windowPosition() without offsets and callback', function(done) {
     Globals.protocolTest.call(this, {
       assertion: function(opts) {
         assert.equal(opts.method, 'GET');
@@ -20,7 +20,7 @@ describe('windowPosition', function() {
     }).catch(err => done(err));
   });
 
-  it('testWindowPositionErrors', function() {
+  it('test .windowPosition() validation errors', function() {
     assert.throws(function() {
       Globals.runApiCommand.call(this, null, 'windowPosition', [function() {}]);
     }.bind(this), /First argument must be a window handle string/);
@@ -38,7 +38,7 @@ describe('windowPosition', function() {
     );
   });
 
-  it('testWindowPositionGet', function(done) {
+  it('test .windowPosition() GET', function(done) {
     Globals.protocolTest.call(this, {
       assertion: function(opts) {
         assert.equal(opts.method, 'GET');
@@ -49,7 +49,7 @@ describe('windowPosition', function() {
     }).then(_ => done()).catch(err => done(err));
   });
 
-  it('testWindowPositionPost', function() {
+  it('test .windowPosition() POST', function() {
     return Globals.protocolTest.call(this, {
       assertion: function(opts) {
         assert.equal(opts.method, 'POST');
@@ -60,4 +60,26 @@ describe('windowPosition', function() {
     });
   });
 
+  it('test .windowPosition() with W3C Webdriver API - POST', function() {
+    return Globals.protocolTestWebdriver.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.method, 'POST');
+        assert.deepEqual(opts.data, { x: 10, y: 10 });
+        assert.strictEqual(opts.path, '/session/1352110219202/window/rect');
+      },
+      commandName: 'windowPosition',
+      args: ['current', 10, 10]
+    });
+  });
+
+  it('test .windowPosition() with W3C Webdriver API - GET', function() {
+    return Globals.protocolTestWebdriver.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.method, 'GET');
+        assert.strictEqual(opts.path, '/session/1352110219202/window/rect');
+      },
+      commandName: 'windowPosition',
+      args: ['current', function() {}]
+    });
+  });
 });
diff --git a/test/src/api/protocol/testWindowRect.js b/test/src/api/protocol/testWindowRect.js
new file mode 100644
index 00000000..2d50cac3
--- /dev/null
+++ b/test/src/api/protocol/testWindowRect.js
@@ -0,0 +1,70 @@
+const assert = require('assert');
+const Globals = require('../../../lib/globals.js');
+
+describe('windowRect', function() {
+  before(function() {
+    Globals.protocolBefore.call(this);
+  });
+
+  it('test .windowRect() validation errors', function() {
+    assert.throws(
+      function() {
+        Globals.runApiCommand(null, 'windowRect', [{width: 'a', height: 10}]);
+      }.bind(this), /Width argument passed to \.windowRect\(\) must be a number; received: string \(a\)\.$/
+    );
+
+    assert.throws(
+      function() {
+        Globals.runApiCommand(null, 'windowRect', [{width: 10, height: 'a'}]);
+      }.bind(this), /Height argument passed to \.windowRect\(\) must be a number; received: string \(a\)\.$/
+    );
+
+    assert.throws(
+      function() {
+        Globals.runApiCommand(null, 'windowRect', [{width: 10}]);
+      }.bind(this), /Attributes "width" and "height" must be specified together\.$/
+    );
+
+    assert.throws(
+      function() {
+        Globals.runApiCommand(null, 'windowRect', [{x: 'a', y: 10}]);
+      }.bind(this), /X position argument passed to \.windowRect\(\) must be a number; received: string \(a\)\.$/
+    );
+
+    assert.throws(
+      function() {
+        Globals.runApiCommand(null, 'windowRect', [{x: 10, y: 'a'}]);
+      }.bind(this), /Y position argument passed to \.windowRect\(\) must be a number; received: string \(a\)\.$/
+    );
+
+    assert.throws(
+      function() {
+        Globals.runApiCommand(null, 'windowRect', [{x: 10}]);
+      }.bind(this), /Attributes "x" and "y" must be specified together\.$/
+    );
+  });
+
+  it('test .windowRect() GET', function() {
+    return Globals.protocolTest.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.method, 'GET');
+        assert.strictEqual(opts.path, '/session/1352110219202/window/rect');
+      },
+      commandName: 'windowRect',
+      args: [null, function() {}]
+    });
+  });
+
+  it('test .windowRect() POST', function() {
+    return Globals.protocolTest.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.method, 'POST');
+        assert.strictEqual(opts.path, '/session/1352110219202/window/rect');
+        assert.deepEqual(opts.data, { width: 10, height: 10, x: 10, y: 10 } );
+      },
+      commandName: 'windowRect',
+      args: [{width: 10, height: 10, x: 10, y: 10}]
+    });
+  });
+
+});
diff --git a/test/src/api/protocol/testWindowSize.js b/test/src/api/protocol/testWindowSize.js
index 8bca0a23..738231df 100644
--- a/test/src/api/protocol/testWindowSize.js
+++ b/test/src/api/protocol/testWindowSize.js
@@ -6,9 +6,7 @@ describe('windowSize', function() {
     Globals.protocolBefore.call(this);
   });
 
-  it('testWindowSizeErrors', function() {
-    const protocol = this.protocol;
-
+  it('test .windowSize() errors', function() {
     assert.throws(
       function() {
         Globals.runApiCommand(null, 'windowSize', [function() {}]);
@@ -34,11 +32,11 @@ describe('windowSize', function() {
     );
   });
 
-  it('testWindowSizeGet', function(done) {
+  it('test .windowSize() GET', function(done) {
     Globals.protocolTest.call(this, {
       assertion: function(opts) {
-        assert.equal(opts.method, 'GET');
-        assert.equal(opts.path, '/session/1352110219202/window/current/size');
+        assert.strictEqual(opts.method, 'GET');
+        assert.strictEqual(opts.path, '/session/1352110219202/window/current/size');
       },
       commandName: 'windowSize',
       args: ['current', function() {
@@ -47,11 +45,11 @@ describe('windowSize', function() {
     });
   });
 
-  it('testWindowSizePost', function() {
+  it('test .windowSize() POST', function() {
     return Globals.protocolTest.call(this, {
       assertion: function(opts) {
-        assert.equal(opts.method, 'POST');
-        assert.equal(opts.path, '/session/1352110219202/window/current/size');
+        assert.strictEqual(opts.method, 'POST');
+        assert.strictEqual(opts.path, '/session/1352110219202/window/current/size');
         assert.deepEqual(opts.data, {width: 10, height: 10});
       },
       commandName: 'windowSize',
@@ -59,4 +57,26 @@ describe('windowSize', function() {
     });
   });
 
+  it('test .windowSize() with W3C Webdriver API - POST', function() {
+    return Globals.protocolTestWebdriver.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.method, 'POST');
+        assert.deepEqual(opts.data, { width: 10, height: 10 });
+        assert.strictEqual(opts.path, '/session/1352110219202/window/rect');
+      },
+      commandName: 'windowSize',
+      args: ['current', 10, 10]
+    });
+  });
+
+  it('test .windowSize() with W3C Webdriver API - GET', function() {
+    return Globals.protocolTestWebdriver.call(this, {
+      assertion: function(opts) {
+        assert.strictEqual(opts.method, 'GET');
+        assert.strictEqual(opts.path, '/session/1352110219202/window/rect');
+      },
+      commandName: 'windowSize',
+      args: ['current', function() {}]
+    });
+  });
 });
diff --git a/test/src/core/testPageObjectCustomCommands.js b/test/src/core/testPageObjectCustomCommands.js
index 0f7626df..ff60dd58 100644
--- a/test/src/core/testPageObjectCustomCommands.js
+++ b/test/src/core/testPageObjectCustomCommands.js
@@ -67,6 +67,18 @@ describe('test PageObject Commands', function () {
     return this.client.start();
   });
 
+  it('testPageObject - custom command with args[0] as Object', function () {
+    MockServer.addMock({
+      url: '/wd/hub/session/1352110219202/execute',
+      method: 'POST'
+    });
+    let api = this.client.api;
+
+    const page = api.page.simplePageObjWithCommandsObject().customExecute({ prop: true });
+
+    return this.client.start();
+  });
+
   it('testPageObject - error loading custom commands', function (done) {
     let api = this.client.api;
 
diff --git a/test/src/element/testElementCommands.js b/test/src/element/testElementCommands.js
index 6a2b90d8..8d1f2801 100644
--- a/test/src/element/testElementCommands.js
+++ b/test/src/element/testElementCommands.js
@@ -28,7 +28,7 @@ describe('element base commands', function() {
     return Nightwatch.start();
   });
 
-  it('client.element() W3C Webdriver prototcol', async function() {
+  it('client.element() W3C Webdriver protocol', async function() {
     await Nightwatch.initAsync({
       output: false,
       silent: false,
@@ -84,7 +84,7 @@ describe('element base commands', function() {
     return Nightwatch.start();
   });
 
-  it('client.element() NOT FOUND with W3C Webdriver prototcol', async function() {
+  it('client.element() NOT FOUND with W3C Webdriver protocol', async function() {
     Nightwatch.addMock({
       url : '/session/13521-10219-202/element',
       postdata: {
@@ -144,7 +144,7 @@ describe('element base commands', function() {
     return Nightwatch.start();
   });
 
-  it('client.elements() W3C Webdriver prototcol', async function() {
+  it('client.elements() W3C Webdriver protocol', async function() {
     await Nightwatch.initAsync({
       output: false,
       silent: false,
@@ -326,4 +326,139 @@ describe('element base commands', function() {
     assert.ok(thrown instanceof Error);
     assert.ok(thrown.message.includes('No selector property for selector object'));
   });
+
+  //////////////////////////////////////////////////////////////////////////////////////
+  // .isVisible({selector, suppressNotFoundErrors})
+  //////////////////////////////////////////////////////////////////////////////////////
+  it('client.isVisible() NOT FOUND with W3C Webdriver protocol', async function() {
+    Nightwatch.addMock({
+      url : '/session/13521-10219-202/elements',
+      postdata: {
+        using: 'css selector',
+        value: '.not_found'
+      },
+      statusCode: 404,
+      response: {
+        value: {
+          error: 'no such element',
+          message: 'Unable to locate element: .not_found',
+          stacktrace: ''
+        }
+      }
+    }, true);
+
+    Nightwatch.addMock({
+      url : '/session/13521-10219-202/elements',
+      postdata: {
+        using: 'css selector',
+        value: '.not_found'
+      },
+      statusCode: 404,
+      response: {
+        value: {
+          error: 'no such element',
+          message: 'Unable to locate element: .not_found',
+          stacktrace: ''
+        }
+      }
+    }, true);
+
+    let expectedError;
+
+    await Nightwatch.initAsync({
+      output: false,
+      silent: false,
+      selenium : {
+        start_process: false,
+      },
+      webdriver:{
+        start_process: true
+      }
+    }, {
+      registerTestError(err) {
+        expectedError = err;
+      }
+    });
+
+    Nightwatch.api().isVisible({selector: '.not_found', timeout: 10, retryInterval: 100, suppressNotFoundErrors: false}, function(result, instance) {
+      assert.ok(expectedError instanceof Error);
+      assert.strictEqual(expectedError.name, 'NoSuchElementError');
+      assert.strictEqual(instance.suppressNotFoundErrors, false);
+      assert.strictEqual(result.status, -1);
+      assert.strictEqual(result.value.error,'An error occurred while running .isVisible() command on <.not_found>:');
+    });
+
+    return Nightwatch.start();
+  });
+
+  it('client.isVisible() NOT FOUND with suppressed errors', async function() {
+    Nightwatch.addMock({
+      url : '/session/13521-10219-202/elements',
+      postdata: {
+        using: 'css selector',
+        value: '.not_found'
+      },
+      statusCode: 404,
+      response: {
+        value: {
+          error: 'no such element',
+          message: 'Unable to locate element: .not_found',
+          stacktrace: ''
+        }
+      }
+    }, true);
+
+    Nightwatch.addMock({
+      url : '/session/13521-10219-202/elements',
+      postdata: {
+        using: 'css selector',
+        value: '.not_found'
+      },
+      statusCode: 404,
+      response: {
+        value: {
+          error: 'no such element',
+          message: 'Unable to locate element: .not_found',
+          stacktrace: ''
+        }
+      }
+    }, true);
+
+    let expectedError;
+
+    await Nightwatch.initAsync({
+      output: false,
+      silent: false,
+      selenium : {
+        start_process: false,
+      },
+      webdriver:{
+        start_process: true
+      }
+    }, {
+      registerTestError(err) {
+        expectedError = err;
+      }
+    });
+
+    Nightwatch.api().isVisible({selector: '.not_found', timeout: 10, retryInterval: 100, suppressNotFoundErrors: true}, function(result, instance) {
+      assert.strictEqual(typeof expectedError, 'undefined');
+      assert.strictEqual(instance.suppressNotFoundErrors, true);
+      assert.deepStrictEqual(result, {
+        status: -1,
+        value:
+          {
+            error: 'no such element',
+            message: 'Unable to locate element: .not_found',
+            stacktrace: ''
+          },
+        errorStatus: '',
+        error: 'Unable to locate element: .not_found',
+        httpStatusCode: 404
+      });
+
+    });
+
+    return Nightwatch.start();
+  });
 });
diff --git a/test/src/element/testPageObjectElementSelectors.js b/test/src/element/testPageObjectElementSelectors.js
index a36d6049..39d6e635 100644
--- a/test/src/element/testPageObjectElementSelectors.js
+++ b/test/src/element/testPageObjectElementSelectors.js
@@ -3,6 +3,13 @@ const assert = require('assert');
 const nocks = require('../../lib/nockselements.js');
 const Nightwatch = require('../../lib/nightwatch.js');
 
+// FIXME:
+// TypeError: Cannot read property 'args' of undefined (and Mocha's done() called multiple times)
+// at AsyncTree.<anonymous> (test/src/element/testPageObjectElementSelectors.js:233:36)
+//   at AsyncTree.done (lib/core/asynctree.js:111:10)
+//   at AsyncTree.traverse (lib/core/asynctree.js:47:19)
+//   at CommandQueue.traverse (lib/core/queue.js:82:8)
+//   at Timeout.scheduleTimeoutId.setTimeout [as _onTimeout] (lib/core/queue.js:59:52)
 describe('test page object element selectors', function() {
 
   before(function() {
diff --git a/test/src/runner/cli/testParallelExecution.js b/test/src/runner/cli/testParallelExecution.js
index 4cc7571c..5b96a4f4 100644
--- a/test/src/runner/cli/testParallelExecution.js
+++ b/test/src/runner/cli/testParallelExecution.js
@@ -92,7 +92,7 @@ describe('test Parallel Execution', function() {
     assert.ok(runner.test_settings.test_workers);
 
     return runner.runTests().then(_ => {
-      assert.strictEqual(allArgs.length, 31);
+      assert.strictEqual(allArgs.length, 32);
       assert.strictEqual(runner.concurrency.globalExitCode, 0);
     });
   });
@@ -134,7 +134,7 @@ describe('test Parallel Execution', function() {
     });
 
     return runner.runTests().then(_ => {
-      assert.strictEqual(allArgs.length, 31);
+      assert.strictEqual(allArgs.length, 32);
     });
   });
 
@@ -163,7 +163,7 @@ describe('test Parallel Execution', function() {
     });
 
     return runner.runTests().then(_ => {
-      assert.strictEqual(allArgs.length, 31);
+      assert.strictEqual(allArgs.length, 32);
     });
   });
 
diff --git a/test/src/runner/testRunWithCustomCommands.js b/test/src/runner/testRunWithCustomCommands.js
index 06d399c6..755f95cc 100644
--- a/test/src/runner/testRunWithCustomCommands.js
+++ b/test/src/runner/testRunWithCustomCommands.js
@@ -97,7 +97,7 @@ describe('testRunWithCustomCommands', function() {
     }, settings).then(_ => {
       process.exit = origExit;
       assert.strictEqual(globals.increment, 3);
-      assert.deepEqual(globals.logResult.value, [
+      assert.deepEqual(globals.logResult, [
         {level: 'info', timestamp: 534547832, message: 'Test log'},
         {level: 'info', timestamp: 534547442, message: 'Test log2'}
       ]);
diff --git a/test/src/runner/testRunWithVerify.js b/test/src/runner/testRunWithVerify.js
new file mode 100644
index 00000000..0a57a306
--- /dev/null
+++ b/test/src/runner/testRunWithVerify.js
@@ -0,0 +1,63 @@
+const path = require('path');
+const assert = require('assert');
+const common = require('../../common.js');
+const CommandGlobals = require('../../lib/globals/commands.js');
+const MockServer = require('../../lib/mockserver.js');
+const NightwatchClient = common.require('index.js');
+
+const originalCwd = process.cwd();
+const defaultSettings = {
+  selenium: {
+    port: 10195,
+    version2: true,
+    start_process: true
+  },
+  silent: false,
+  output: true,
+  output_folder: false,
+};
+
+describe('testRunWithVerify', function() {
+  before(function(done) {
+    this.server = MockServer.init();
+    this.server.on('listening', () => done());
+  });
+
+  beforeEach(function(done) {
+    process.chdir(path.join(__dirname, '../../sampletests/'));
+    done();
+  });
+
+  afterEach(function(done) {
+    process.chdir(originalCwd);
+    done();
+  });
+
+  after(function(done) {
+    CommandGlobals.afterEach.call(this, done);
+  });
+
+  it('using verify in tests', function() {
+    const settings = Object.assign({
+      globals: {
+        waitForConditionPollInterval: 20,
+        waitForConditionTimeout: 50,
+        retryAssertionTimeout: 50,
+        reporter(results, cb) {
+          assert.ok('verifySampleFailures' in results.modules);
+          assert.strictEqual(results.passed, 1);
+          assert.strictEqual(results.failed, 2);
+          assert.strictEqual(results.assertions, 3);
+
+          cb();
+        },
+      }
+    }, defaultSettings);
+
+    return NightwatchClient.runTests({
+      _source: ['./withverify']
+    }, settings);
+  });
+
+
+});
diff --git a/test/src/util/testUtils.js b/test/src/util/testUtils.js
index 274f4845..1fa7f1a4 100644
--- a/test/src/util/testUtils.js
+++ b/test/src/util/testUtils.js
@@ -109,4 +109,13 @@ describe('test Utils', function() {
       'rendered output\rrendered output\rrendered output'
     );
   });
+
+  it('testRelativeUrl', function() {
+    assert.equal(Utils.relativeUrl('https://nightwatchjs.org'), false);
+    assert.equal(Utils.relativeUrl('http://nightwatchjs.org'), false);
+    assert.equal(Utils.relativeUrl('chrome-extension://pkehgijcmpdhfbdbbnkijodmdjhbjlgp/skin/options.html'), false);
+    assert.equal(Utils.relativeUrl('nightwatchjs.org'), true);
+    assert.equal(Utils.relativeUrl('nightwatchjs.org/guide'), true);
+    assert.equal(Utils.relativeUrl('/guide'), true);
+  });
 });
diff --git a/test/src/wd-manager/testSelenium.js b/test/src/wd-manager/testSelenium.js
index 7ce19c6a..a3fcc87e 100644
--- a/test/src/wd-manager/testSelenium.js
+++ b/test/src/wd-manager/testSelenium.js
@@ -135,6 +135,8 @@ describe('Webdriver Manager', function () {
       let settings = Settings.parse({
         selenium: {
           check_process_delay: 1000,
+          max_status_poll_tries: 10,
+          status_poll_interval: 200,
           start_process: true,
           server_path: './selenium.jar',
           log_path: false,