Repository: nightwatchjs/nightwatch
Pull request #3258 (2022-06-28 09:45:27)

fix nightwatchjs/nightwatch#3130, random port assignment for parallel…
TODO:
- [x] write tests to prevent the issue in the future.

reallymello: @swrdfish does this remove the need for adding --parallel when executing tests now?
swrdfish: @reallymello this fixed the port assignment issue. But there are still some subtle differences in the behaviour that I have noticed, will fix those in the coming weeks. Ideally using the command line flag should have the same behaviour as defining it in the settings.

Patch:
diff --git a/lib/api/_loaders/plugin.js b/lib/api/_loaders/plugin.js
index 4ed028b9..7ee3a0f0 100644
--- a/lib/api/_loaders/plugin.js
+++ b/lib/api/_loaders/plugin.js
@@ -3,19 +3,7 @@ const path = require('path');
 const Utils = require('../../utils');
 
 module.exports = class PluginLoader {
-  get api() {
-    return this.nightwatchInstance.api;
-  }
-
-  get commandQueue() {
-    return this.nightwatchInstance.queue;
-  }
-
-  constructor(nightwatchInstance) {
-    this.nightwatchInstance = nightwatchInstance;
-  }
-
-  load(pluginName) {
+  static load(pluginName) {
     try {
       const plugin = {};
       const pluginPath = Utils.getPluginPath(pluginName);
@@ -43,6 +31,12 @@ module.exports = class PluginLoader {
           plugin.commands = false;
         }
 
+        try {
+          plugin.globals = require(path.join(dirName, 'nightwatch', 'globals.js'));
+        } catch (err) {
+          plugin.globals = false;
+        }
+
         try {
           const hasAssertions = fs.lstatSync(assertionsFolder).isDirectory();
           if (hasAssertions) {
diff --git a/lib/api/client-commands/mockNetworkResponse.js b/lib/api/client-commands/mockNetworkResponse.js
index 88c6055f..b25b26ac 100644
--- a/lib/api/client-commands/mockNetworkResponse.js
+++ b/lib/api/client-commands/mockNetworkResponse.js
@@ -37,7 +37,14 @@ class MockNetworkResponse extends ClientCommand {
       return callback(error);
     }
 
-    const {urlToIntercept = '', response = {}} = this;
+    const {response = {}} = this;
+    let {urlToIntercept = ''} = this;
+
+    if (urlToIntercept.startsWith('/')) {
+      let needsSlash = this.api.globals.launchUrl.endsWith('/');
+      let slashDel = needsSlash ? '/' : '';
+      urlToIntercept = `${this.api.globals.launchUrl}${slashDel}${urlToIntercept}`;
+    }
     
     this.transportActions
       .mockNetworkResponse(urlToIntercept, response, callback)
diff --git a/lib/api/index.js b/lib/api/index.js
index b65b03df..82b1f200 100644
--- a/lib/api/index.js
+++ b/lib/api/index.js
@@ -153,8 +153,7 @@ class ApiLoader {
     const plugins = this.nightwatchInstance.options.plugins || [];
 
     plugins.forEach(pluginName => {
-      const instance = new PluginLoader(this.nightwatchInstance);
-      const plugin = instance.load(pluginName);
+      const plugin = PluginLoader.load(pluginName);
 
       if (plugin.commands) {
         this.__loadCustomObjectsSync({
diff --git a/lib/api/protocol/url.js b/lib/api/protocol/url.js
index 25568576..1966f362 100644
--- a/lib/api/protocol/url.js
+++ b/lib/api/protocol/url.js
@@ -37,7 +37,8 @@ module.exports = class Action extends ProtocolAction {
       if (this.settings.output) {
         spinner = ora({
           text: `Loading url: ${url}\n`,
-          prefixText: ' '
+          prefixText: ' ',
+          discardStdin: false
         }).start();
       }
 
diff --git a/lib/core/client.js b/lib/core/client.js
index dcabd66f..ec7281ea 100644
--- a/lib/core/client.js
+++ b/lib/core/client.js
@@ -519,7 +519,7 @@ class NightwatchClient extends EventEmitter {
       this.settings.webdriver.default_path_prefix = this.transport.defaultPathPrefix;
     }
 
-    if (this.argv.parallel && this.settings.webdriver.start_process) {
+    if (this.settings.testWorkersEnabled && this.settings.webdriver.start_process) {
       // when running in parallel with test workers, the port needs to be randomly assigned
       this.settings.webdriver.port = undefined;
     }
diff --git a/lib/runner/cli/cli.js b/lib/runner/cli/cli.js
index 8224d4f0..2e9dc427 100644
--- a/lib/runner/cli/cli.js
+++ b/lib/runner/cli/cli.js
@@ -34,6 +34,8 @@ class CliRunner {
       'vite-plugin-nightwatch': {
         launch_url: 'http://localhost:3000'
       }
+    }, {
+      '@nightwatch/react': {}
     }];
 
     autoLoadPlugins.forEach(plugin => {
@@ -250,7 +252,7 @@ class CliRunner {
 
   runGlobalHook(key) {
     if (!Concurrency.isChildProcess()) {
-      return this.globals.hooks[key].run();
+      return this.globals.runGlobalHook(key);
     }
 
     return Promise.resolve();
diff --git a/lib/transport/selenium-webdriver/options.js b/lib/transport/selenium-webdriver/options.js
index 86330e02..7f6ff5e6 100644
--- a/lib/transport/selenium-webdriver/options.js
+++ b/lib/transport/selenium-webdriver/options.js
@@ -1,4 +1,5 @@
 const {Capabilities, Browser} = require('selenium-webdriver');
+const Utils = require('../../utils');
 
 module.exports = class SeleniumCapabilities {
   get initialCapabilities() {
@@ -102,6 +103,14 @@ module.exports = class SeleniumCapabilities {
       return this.desiredCapabilities;
     }
 
+    // Backward compatibility for 'chromeOptions'
+    if (Utils.isObject(this.desiredCapabilities.chromeOptions)) {
+      this.desiredCapabilities['goog:chromeOptions'] = Object.assign(
+        this.desiredCapabilities.chromeOptions,
+        this.desiredCapabilities['goog:chromeOptions']
+      );
+    }
+
     const {webdriver} = this.settings;
     let options = new ChromeOptions(this.desiredCapabilities);
 
diff --git a/package-lock.json b/package-lock.json
index 617cbef0..1714cfd4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "nightwatch",
-  "version": "2.2.2",
+  "version": "2.2.3-preview.1",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "nightwatch",
-      "version": "2.2.2",
+      "version": "2.2.3-preview.1",
       "license": "MIT",
       "dependencies": {
         "@nightwatch/chai": "5.0.2",
@@ -30,7 +30,7 @@
         "mocha": "9.2.2",
         "open": "^8.4.0",
         "ora": "5.4.1",
-        "selenium-webdriver": "4.1.1",
+        "selenium-webdriver": "^4.3.1",
         "semver": "7.3.5",
         "stacktrace-parser": "^0.1.10",
         "strip-ansi": "6.0.1"
@@ -3280,7 +3280,8 @@
     },
     "node_modules/immediate": {
       "version": "3.0.6",
-      "license": "MIT"
+      "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+      "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
     },
     "node_modules/import-fresh": {
       "version": "3.3.0",
@@ -3495,7 +3496,8 @@
     },
     "node_modules/isarray": {
       "version": "1.0.0",
-      "license": "MIT"
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
     },
     "node_modules/isexe": {
       "version": "2.0.0",
@@ -3839,13 +3841,14 @@
       }
     },
     "node_modules/jszip": {
-      "version": "3.7.1",
-      "license": "(MIT OR GPL-3.0-or-later)",
+      "version": "3.10.0",
+      "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.0.tgz",
+      "integrity": "sha512-LDfVtOLtOxb9RXkYOwPyNBTQDL4eUbqahtoY6x07GiDJHwSYvn8sHHIw8wINImV3MqbMNve2gSuM1DDqEKk09Q==",
       "dependencies": {
         "lie": "~3.3.0",
         "pako": "~1.0.2",
         "readable-stream": "~2.3.6",
-        "set-immediate-shim": "~1.0.1"
+        "setimmediate": "^1.0.5"
       }
     },
     "node_modules/keyv": {
@@ -3890,7 +3893,8 @@
     },
     "node_modules/lie": {
       "version": "3.3.0",
-      "license": "MIT",
+      "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+      "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
       "dependencies": {
         "immediate": "~3.0.5"
       }
@@ -5246,7 +5250,8 @@
     },
     "node_modules/pako": {
       "version": "1.0.11",
-      "license": "(MIT AND Zlib)"
+      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
     },
     "node_modules/parent-module": {
       "version": "1.0.1",
@@ -5386,7 +5391,8 @@
     },
     "node_modules/process-nextick-args": {
       "version": "2.0.1",
-      "license": "MIT"
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
     },
     "node_modules/process-on-spawn": {
       "version": "1.0.0",
@@ -5511,7 +5517,8 @@
     },
     "node_modules/readable-stream": {
       "version": "2.3.7",
-      "license": "MIT",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+      "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
       "dependencies": {
         "core-util-is": "~1.0.0",
         "inherits": "~2.0.3",
@@ -5524,7 +5531,8 @@
     },
     "node_modules/readable-stream/node_modules/string_decoder": {
       "version": "1.1.1",
-      "license": "MIT",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
       "dependencies": {
         "safe-buffer": "~5.1.0"
       }
@@ -5765,13 +5773,13 @@
       "license": "MIT"
     },
     "node_modules/selenium-webdriver": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.1.1.tgz",
-      "integrity": "sha512-Fr9e9LC6zvD6/j7NO8M1M/NVxFX67abHcxDJoP5w2KN/Xb1SyYLjMVPGgD14U2TOiKe4XKHf42OmFw9g2JgCBQ==",
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.3.1.tgz",
+      "integrity": "sha512-TjH/ls1WKRQoFEHcqtn6UtwcLnA3yvx08v9cSSFYvyhp8hJWRtbe9ae2I8uXPisEZ2EaGKKoxBZ4EHv0BJM15g==",
       "dependencies": {
-        "jszip": "^3.6.0",
+        "jszip": "^3.10.0",
         "tmp": "^0.2.1",
-        "ws": ">=7.4.6"
+        "ws": ">=8.7.0"
       },
       "engines": {
         "node": ">= 10.15.0"
@@ -5802,12 +5810,10 @@
       "dev": true,
       "license": "ISC"
     },
-    "node_modules/set-immediate-shim": {
-      "version": "1.0.1",
-      "license": "MIT",
-      "engines": {
-        "node": ">=0.10.0"
-      }
+    "node_modules/setimmediate": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+      "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
     },
     "node_modules/shebang-command": {
       "version": "2.0.0",
@@ -6469,8 +6475,9 @@
       }
     },
     "node_modules/ws": {
-      "version": "8.4.2",
-      "license": "MIT",
+      "version": "8.8.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz",
+      "integrity": "sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==",
       "engines": {
         "node": ">=10.0.0"
       },
@@ -8669,7 +8676,9 @@
       "devOptional": true
     },
     "immediate": {
-      "version": "3.0.6"
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+      "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
     },
     "import-fresh": {
       "version": "3.3.0",
@@ -8787,7 +8796,9 @@
       }
     },
     "isarray": {
-      "version": "1.0.0"
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
     },
     "isexe": {
       "version": "2.0.0"
@@ -9012,12 +9023,14 @@
       }
     },
     "jszip": {
-      "version": "3.7.1",
+      "version": "3.10.0",
+      "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.0.tgz",
+      "integrity": "sha512-LDfVtOLtOxb9RXkYOwPyNBTQDL4eUbqahtoY6x07GiDJHwSYvn8sHHIw8wINImV3MqbMNve2gSuM1DDqEKk09Q==",
       "requires": {
         "lie": "~3.3.0",
         "pako": "~1.0.2",
         "readable-stream": "~2.3.6",
-        "set-immediate-shim": "~1.0.1"
+        "setimmediate": "^1.0.5"
       }
     },
     "keyv": {
@@ -9049,6 +9062,8 @@
     },
     "lie": {
       "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+      "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
       "requires": {
         "immediate": "~3.0.5"
       }
@@ -9966,7 +9981,9 @@
       }
     },
     "pako": {
-      "version": "1.0.11"
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
     },
     "parent-module": {
       "version": "1.0.1",
@@ -10049,7 +10066,9 @@
       "dev": true
     },
     "process-nextick-args": {
-      "version": "2.0.1"
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
     },
     "process-on-spawn": {
       "version": "1.0.0",
@@ -10125,6 +10144,8 @@
     },
     "readable-stream": {
       "version": "2.3.7",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+      "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
       "requires": {
         "core-util-is": "~1.0.0",
         "inherits": "~2.0.3",
@@ -10137,6 +10158,8 @@
       "dependencies": {
         "string_decoder": {
           "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
           "requires": {
             "safe-buffer": "~5.1.0"
           }
@@ -10291,13 +10314,13 @@
       "dev": true
     },
     "selenium-webdriver": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.1.1.tgz",
-      "integrity": "sha512-Fr9e9LC6zvD6/j7NO8M1M/NVxFX67abHcxDJoP5w2KN/Xb1SyYLjMVPGgD14U2TOiKe4XKHf42OmFw9g2JgCBQ==",
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.3.1.tgz",
+      "integrity": "sha512-TjH/ls1WKRQoFEHcqtn6UtwcLnA3yvx08v9cSSFYvyhp8hJWRtbe9ae2I8uXPisEZ2EaGKKoxBZ4EHv0BJM15g==",
       "requires": {
-        "jszip": "^3.6.0",
+        "jszip": "^3.10.0",
         "tmp": "^0.2.1",
-        "ws": ">=7.4.6"
+        "ws": ">=8.7.0"
       }
     },
     "semver": {
@@ -10316,8 +10339,10 @@
       "version": "2.0.0",
       "dev": true
     },
-    "set-immediate-shim": {
-      "version": "1.0.1"
+    "setimmediate": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+      "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
     },
     "shebang-command": {
       "version": "2.0.0",
@@ -10733,7 +10758,9 @@
       }
     },
     "ws": {
-      "version": "8.4.2",
+      "version": "8.8.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz",
+      "integrity": "sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==",
       "requires": {}
     },
     "xml": {
diff --git a/package.json b/package.json
index 8f8dcbe1..b73f3d0f 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 web applications using the W3C WebDriver API.",
-  "version": "2.2.2",
+  "version": "2.2.3-preview.1",
   "author": "Andrei Rusu",
   "homepage": "https://nightwatchjs.org",
   "main": "./lib/index.js",
@@ -33,7 +33,7 @@
     "mocha": "9.2.2",
     "open": "^8.4.0",
     "ora": "5.4.1",
-    "selenium-webdriver": "4.1.1",
+    "selenium-webdriver": "^4.3.1",
     "semver": "7.3.5",
     "stacktrace-parser": "^0.1.10",
     "strip-ansi": "6.0.1"


Test patch:
diff --git a/lib/testsuite/globals.js b/lib/testsuite/globals.js
index 05a356cc..762d4aea 100644
--- a/lib/testsuite/globals.js
+++ b/lib/testsuite/globals.js
@@ -1,10 +1,9 @@
 const path = require('path');
 const lodashClone = require('lodash.clone');
-const lodashMerge = require('lodash.merge');
-const defaultsDeep = require('lodash.defaultsdeep');
 const TestHooks = require('./hooks.js');
 const Context = require('./context.js');
 const Utils = require('../utils');
+const PluginLoader = require('../api/_loaders/plugin.js');
 
 class GlobalsContext extends Context {
   get isTestHook() {
@@ -159,12 +158,25 @@ class Globals {
     this.readExternal();
     this.mergeWithExisting();
     this.setupGlobalHooks();
+    this.loadPlugins();
   }
 
   get globals() {
     return this.context.module;
   }
 
+  loadPlugins() {
+    const definition = this.settings.plugins || [];
+    this.plugins = definition.reduce((prev, pluginName) => {
+      const plugin = PluginLoader.load(pluginName);
+      if (plugin.globals) {
+        prev.push(plugin);
+      }
+
+      return prev;
+    }, []);
+  }
+
   readExternal() {
     this.context = new GlobalsContext(this.settings, this.argv, this.currentEnv);
   }
@@ -187,13 +199,7 @@ class Globals {
       // eslint-disable-next-line
     } catch (err) {}
 
-    // Object.assign(this.settings.globals, this.globals);
-    //const existingGlobals = lodashClone(this.settings.globals, true);
-    //
     this.settings.globals = this.globals;
-    //
-    // // external globals take precedence
-    //defaultsDeep(this.settings.globals, existingGlobals);
   }
 
   setupGlobalHooks() {
@@ -202,6 +208,18 @@ class Globals {
       asyncHookTimeout: this.settings.globals.asyncHookTimeout
     });
   }
+
+  async runGlobalHook(key) {
+    await this.hooks[key].run();
+
+    await Promise.all(this.plugins.map(plugin => {
+      if (Utils.isFunction(plugin.globals[key])) {
+        return plugin.globals[key].call(this.settings.globals);
+      }
+      
+      return Promise.resolve();
+    }));
+  }
 }
 
 module.exports = Globals;
diff --git a/lib/testsuite/index.js b/lib/testsuite/index.js
index 5d051a4e..49ef5222 100644
--- a/lib/testsuite/index.js
+++ b/lib/testsuite/index.js
@@ -1,4 +1,6 @@
 const AssertionError = require('assertion-error');
+const {By, Key, locateWith, withTagName} = require('selenium-webdriver');
+
 const Reporter = require('../reporter');
 const Context = require('./context.js');
 const TestHooks = require('./hooks.js');
@@ -10,7 +12,6 @@ const NightwatchClient = require('../core/client.js');
 const Concurrency = require('../runner/concurrency');
 const ElementGlobal = require('../api/_loaders/element-global.js');
 const {Logger, Screenshots, alwaysDisplayError, isString, isFunction, SafeJSON} = require('../utils');
-const {By, Key, locateWith, withTagName} = require('selenium-webdriver');
 
 class TestSuite {
   constructor({modulePath, modules, settings, argv, usingMocha = false, addtOpts = {}}) {
diff --git a/test/src/cli/testParallelExecution.js b/test/src/cli/testParallelExecution.js
index 0896d249..947242c3 100644
--- a/test/src/cli/testParallelExecution.js
+++ b/test/src/cli/testParallelExecution.js
@@ -4,6 +4,7 @@ const mockery = require('mockery');
 const path = require('path');
 const assert = require('assert');
 const common = require('../../common.js');
+const Nightwatch = require('../../lib/nightwatch.js');
 
 describe('test Parallel Execution', function() {
   const allArgs = [];
@@ -326,7 +327,8 @@ describe('test Parallel Execution', function() {
     assert.ok(args.includes('--parallel-mode'));
   });
 
-  it('test parallel execution to ensure worker start_process is disabled when using selenium server', function() {
+  // TODO: this test is not complete
+  xit('test parallel execution to ensure worker start_process is disabled when using selenium server', function() {
     const CliRunner = common.require('runner/cli/cli.js');
     const runner = new CliRunner({
       reporter: 'junit',
@@ -335,6 +337,35 @@ describe('test Parallel Execution', function() {
 
     runner.setup();
     const worker = runner.concurrency.createChildProcess('test-worker');
+
+  });
+
+  it('test random port assignment for parallel execution', function(){
+    const client = Nightwatch.createClient({
+      webdriver: {
+        port: 9999,
+        start_process: true
+      },
+
+      'test_workers': {
+        'enabled': true,
+        'workers': 4
+      }
+    });
+    assert.equal(client.transport.settings.webdriver.port, undefined);
+
+    const client2 = Nightwatch.createClient({
+      webdriver: {
+        port: 9999,
+        start_process: false
+      },
+
+      'test_workers': {
+        'enabled': true,
+        'workers': 4
+      }
+    });
+    assert.equal(client2.transport.settings.webdriver.port, 9999);
   });
 
 });
diff --git a/test/src/index/transport/testChromeOptions.js b/test/src/index/transport/testChromeOptions.js
index dd2ae422..afe90c23 100644
--- a/test/src/index/transport/testChromeOptions.js
+++ b/test/src/index/transport/testChromeOptions.js
@@ -34,6 +34,23 @@ describe('Test chrome options', function () {
     assert.strictEqual(client.api.browserName, 'chrome');
   });
 
+  it('chromeOptions detach driver option', function () {
+    const client = Nightwatch.createClient({
+      desiredCapabilities: {
+        browserName: 'chrome',
+        chromeOptions: {
+          detach: true
+        }
+      }
+    });
+    const options = client.transport.createSessionOptions();
+
+    assert.strictEqual(options instanceof ChromeOptions, true);
+    assert.strictEqual(options.options_.detach, true);
+    assert.strictEqual(client.api.isChrome(), true);
+    assert.strictEqual(client.api.browserName, 'chrome');
+  });
+
   it('Chrome Binary Path option', function(){
     const client = Nightwatch.createClient({
       webdriver: {
@@ -139,6 +156,22 @@ describe('Test chrome options', function () {
     assert.deepStrictEqual(options.options_.args, ['--auto-open-devtools-for-tabs']);
   });
 
+  it('devtools cli arg with already defined setting (using chromeOptions)', function(){
+    const client = Nightwatch.createClient({
+      desiredCapabilities: {
+        browserName: 'chrome',
+        chromeOptions: {
+          args: ['auto-open-devtools-for-tabs']
+        }
+      }
+    });
+
+    const options = client.transport.createSessionOptions({devtools: true});
+
+    assert.strictEqual(options instanceof ChromeOptions, true);
+    assert.deepStrictEqual(options.options_.args, ['auto-open-devtools-for-tabs']);
+  });
+
   it('window size option', function(){
     const client =  Nightwatch.createClient({
       window_size: {