You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by am...@apache.org on 2022/04/22 01:43:55 UTC

[couchdb-fauxton] branch main updated: Upgrade nightwatch and switch from Travis to GH Actions (#1349)

This is an automated email from the ASF dual-hosted git repository.

amaranhao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/couchdb-fauxton.git


The following commit(s) were added to refs/heads/main by this push:
     new eb906579 Upgrade nightwatch and switch from Travis to GH Actions (#1349)
eb906579 is described below

commit eb9065795ddf4073cebdefaeb92f2b75334e2aa1
Author: Jordan Fry <94...@users.noreply.github.com>
AuthorDate: Fri Apr 22 02:43:50 2022 +0100

    Upgrade nightwatch and switch from Travis to GH Actions (#1349)
---
 .env                                               |    1 -
 .github/workflows/main.yml                         |   72 +
 .gitignore                                         |    1 +
 .travis.yml                                        |   35 -
 .../tests/nightwatch/checkDatabaseTooltip.js       |    3 +-
 .../tests/nightwatch/createsDatabasePartitioned.js |    2 +-
 .../tests/nightwatch/permissionsDbTable.js         |    2 +-
 .../tests/nightwatch/specialCharListLinks.js       |    4 +-
 .../databases/tests/nightwatch/switchDatabase.js   |    8 +-
 .../doc-editor/components/DocEditorScreen.js       |    4 +-
 .../tests/nightwatch/checkSidebarBehavior.js       |    2 +-
 .../nightwatch/editDocumentWithStringEditor.js     |    2 +-
 app/addons/documents/tests/nightwatch/jsonView.js  |    2 +-
 .../documents/tests/nightwatch/mangoIndex.js       |    4 +-
 .../documents/tests/nightwatch/mangoQuery.js       |    4 +-
 .../tests/nightwatch/navigateNotFoundDB.js         |    4 +-
 .../documents/tests/nightwatch/paginateAllDocs.js  |   30 +-
 .../documents/tests/nightwatch/paginateView.js     |   27 +-
 .../documents/tests/nightwatch/resultsToolbar.js   |   10 +-
 .../documents/tests/nightwatch/revBrowser.js       |   16 +-
 .../tests/nightwatch/selectDocViaTypeahead.js      |   30 +-
 app/addons/documents/tests/nightwatch/tableView.js |    2 +-
 app/addons/documents/tests/nightwatch/viewClone.js |    2 +-
 .../documents/tests/nightwatch/viewCreate.js       |   10 +-
 .../tests/nightwatch/viewCreateBadView.js          |    5 +-
 .../documents/tests/nightwatch/viewDelete.js       |    2 +-
 app/addons/documents/tests/nightwatch/viewEdit.js  |   13 +-
 .../fauxton/tests/nightwatch/highlightsidebar.js   |    2 +-
 .../permissions/tests/nightwatch/permissions.js    |    4 +-
 .../replication/tests/nightwatch/replication.js    |   45 +-
 bin/docker-up-and-check.sh                         |    2 +-
 docker/{dc.selenium.yml => couchdb.yml}            |    5 -
 docker/dc.selenium-debug.yml                       |   15 -
 package-lock.json                                  | 1721 ++++++++++----------
 package.json                                       |   12 +-
 readme.md                                          |    2 +-
 settings.json.default.json                         |    4 +-
 tasks/fauxton.js                                   |   11 +-
 test/nightwatch_tests/nightwatch.json.underscore   |   65 +-
 tests.md                                           |   52 +-
 40 files changed, 1075 insertions(+), 1162 deletions(-)

diff --git a/.env b/.env
index cbced886..59337d51 100644
--- a/.env
+++ b/.env
@@ -1,5 +1,4 @@
 # Default environment variables for the Docker Compose files in /docker
 # This file needs to be placed where the docker-compose command is run from.
 
-# Used to provide a CouchDB 2 / 3 build matrix in .travis.yml
 COUCHDB_IMAGE=apache/couchdb3
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 00000000..89c63c82
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,72 @@
+name: CI
+on: [push]
+jobs:
+  run-unit-tests:
+    name: Run unit tests
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v2
+    - uses: actions/setup-node@v2
+      with:
+        node-version: '14'
+    - name: Install npm packages
+      run: |
+        npm install -g npm@latest
+        npm ci
+        npm ls --production --depth=0
+    - name: Run style check
+      run: npm run stylecheck
+    - name: Run unit tests
+      run: npm run test
+  run-e2e-tests:
+    name: Run e2e tests
+    runs-on: ubuntu-latest
+    needs: [run-unit-tests]
+    strategy:
+      matrix:
+        include:
+          - COUCHDB_IMAGE: apache/couchdb:3
+            NIGHTWATCH_SKIPTAGS: "search,nonpartitioned,couchdb-v2-only"
+          - COUCHDB_IMAGE: apache/couchdb:2.3.1
+            NIGHTWATCH_SKIPTAGS: "search,partitioned"
+    steps:
+    - uses: actions/checkout@v2
+    - uses: actions/setup-node@v2
+      with:
+        node-version: '14'
+        cache: 'npm'
+    - run: ./bin/build-couchdb-dev.sh
+      env:
+        COUCHDB_IMAGE: ${{ matrix.COUCHDB_IMAGE }}
+        NIGHTWATCH_SKIPTAGS: ${{ matrix.NIGHTWATCH_SKIPTAGS }}
+    - name: Install npm packages
+      run: |
+        npm install -g npm@latest
+        npm ci
+        npm ls --production --depth=0
+    - name: Start CouchDB
+      env:
+        COUCHDB_IMAGE: ${{ matrix.COUCHDB_IMAGE }}
+        NIGHTWATCH_SKIPTAGS: ${{ matrix.NIGHTWATCH_SKIPTAGS }}
+      run: |
+        ./bin/docker-up-and-check.sh
+        curl http://127.0.0.1:5984
+    - name: Configure display
+      run: |
+        export DISPLAY=:99
+        sudo apt-get install xvfb
+    - name: Start Fauxton
+      env:
+        COUCHDB_IMAGE: ${{ matrix.COUCHDB_IMAGE }}
+        NIGHTWATCH_SKIPTAGS: ${{ matrix.NIGHTWATCH_SKIPTAGS }}
+      run: |
+        grunt debugDev && DIST=./dist/debug ./bin/fauxton &
+        sleep 60
+        curl http://localhost:8000
+    - name: Run e2e tests
+      env:
+        COUCHDB_IMAGE: ${{ matrix.COUCHDB_IMAGE }}
+        NIGHTWATCH_SKIPTAGS: ${{ matrix.NIGHTWATCH_SKIPTAGS }}
+      run: xvfb-run --auto-servernum ./node_modules/.bin/grunt nightwatch_retries
+    - name: Shutdown CouchDB
+      run: npm run docker:down
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 2d7315c2..8928229e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+*.log
 node_modules
 dist
 build
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 4deb9508..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,35 +0,0 @@
-language: node_js
-node_js:
-   - "14"
-sudo: false
-services:
-  - docker
-git:
-  depth: 1
-env:
-  - COUCHDB_IMAGE=apache/couchdb:2.3.1 NIGHTWATCH_SKIPTAGS="search,partitioned"
-  - COUCHDB_IMAGE=apache/couchdb:3 NIGHTWATCH_SKIPTAGS="search,nonpartitioned,couchdb-v2-only"
-  # - COUCHDB_IMAGE=couchdb:dev NIGHTWATCH_SKIPTAGS="search,nonpartitioned"
-
-before_install:
-  - npm install -g npm@latest
-  - ./bin/build-couchdb-dev.sh
-install:
-  - npm ci
-before_script:
-  - travis_retry ./bin/docker-up-and-check.sh
-  - curl http://127.0.0.1:5984
-  - npm run stylecheck
-  - npm ls --production --depth=0
-  - npm test
-  - grunt debugDev
-  - DIST=./dist/debug ./bin/fauxton &
-  - sleep 30
-script:
-  - ./node_modules/.bin/grunt nightwatch_retries
-after_script:
-  - npm run docker:down
-cache:
-  - apt
-  - directories:
-    - "$HOME/.npm"
diff --git a/app/addons/databases/tests/nightwatch/checkDatabaseTooltip.js b/app/addons/databases/tests/nightwatch/checkDatabaseTooltip.js
index 5da4cb29..b3af0ee5 100644
--- a/app/addons/databases/tests/nightwatch/checkDatabaseTooltip.js
+++ b/app/addons/databases/tests/nightwatch/checkDatabaseTooltip.js
@@ -27,8 +27,7 @@ module.exports = {
       .loginToGUI()
 
       // delete the document manually. This'll ensure the database page has at least one "!" icon
-      .waitForElementPresent('#dashboard-content a[href="database/' + newDatabaseName + '/_all_docs"]', waitTime, false)
-      .click('#dashboard-content a[href="database/' + newDatabaseName + '/_all_docs"]')
+      .clickWhenVisible('#dashboard-content a[href="database/' + newDatabaseName + '/_all_docs"]', waitTime, false)
 
       //this opens the alternative header
       .clickWhenVisible('.tableview-checkbox-cell input[type="checkbox"]')
diff --git a/app/addons/databases/tests/nightwatch/createsDatabasePartitioned.js b/app/addons/databases/tests/nightwatch/createsDatabasePartitioned.js
index 9174e113..2b6f6845 100644
--- a/app/addons/databases/tests/nightwatch/createsDatabasePartitioned.js
+++ b/app/addons/databases/tests/nightwatch/createsDatabasePartitioned.js
@@ -54,7 +54,7 @@ module.exports = {
       .clickWhenVisible('#js-create-database', waitTime, false)
       .waitForElementNotPresent('.new-database-tray', waitTime, false)
       .checkForDatabaseCreated(newDatabaseName, waitTime)
-      .url(baseUrl + '/_all_dbs')
+      .url(baseUrl + '/#/_all_dbs')
       .waitForElementVisible('html', waitTime, false)
       .getText('html', function (result) {
         var data = result.value,
diff --git a/app/addons/databases/tests/nightwatch/permissionsDbTable.js b/app/addons/databases/tests/nightwatch/permissionsDbTable.js
index 1c3b8d78..2a3b179d 100644
--- a/app/addons/databases/tests/nightwatch/permissionsDbTable.js
+++ b/app/addons/databases/tests/nightwatch/permissionsDbTable.js
@@ -31,7 +31,7 @@ module.exports = {
 
       .waitForElementVisible('.database-load-fail', waitTime, false)
       .waitForElementVisible('[data-name="database-load-fail-name"]', waitTime, false)
-      .assert.containsText('[data-name="database-load-fail-name"]', '_global_changes')
+      .assert.textContains('[data-name="database-load-fail-name"]', '_global_changes')
 
       .end();
   }
diff --git a/app/addons/databases/tests/nightwatch/specialCharListLinks.js b/app/addons/databases/tests/nightwatch/specialCharListLinks.js
index 2cb3c57b..3b2a4e9f 100644
--- a/app/addons/databases/tests/nightwatch/specialCharListLinks.js
+++ b/app/addons/databases/tests/nightwatch/specialCharListLinks.js
@@ -41,8 +41,8 @@ function createTest (db) {
       .waitForElementVisible('.faux-header__doc-header-title', waitTime, false)
       .waitForElementVisible('.no-results-screen', waitTime, false)
 
-      .assert.containsText('.no-results-screen', 'No Documents Found')
-      .assert.containsText('.faux-header__doc-header-title', db)
+      .assert.textContains('.no-results-screen', 'No Documents Found')
+      .assert.textContains('.faux-header__doc-header-title', db)
       .end();
   };
 }
diff --git a/app/addons/databases/tests/nightwatch/switchDatabase.js b/app/addons/databases/tests/nightwatch/switchDatabase.js
index 488d84ce..8973cb24 100644
--- a/app/addons/databases/tests/nightwatch/switchDatabase.js
+++ b/app/addons/databases/tests/nightwatch/switchDatabase.js
@@ -10,7 +10,7 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-
+const {Key} = require('selenium-webdriver');
 
 module.exports = {
   'Confirm selecting database via typeahead redirects properly': function (client) {
@@ -32,7 +32,11 @@ module.exports = {
       .clickWhenVisible('[data-name="jump-to-db"] .Select-placeholder')
       .setValue('[data-name="jump-to-db"] input', [newDatabaseName])
       .waitForElementPresent('.Select-option', waitTime, false)
-      .keys([client.Keys.ENTER])
+      .perform(function() {
+        const actions = this.actions({async: true});
+        return actions
+          .sendKeys(Key.ENTER);
+      })
       .waitForElementPresent('.index-pagination', waitTime, false)
       // now check we've redirected and the URL ends with /_all_docs
       .url((result) => {
diff --git a/app/addons/documents/doc-editor/components/DocEditorScreen.js b/app/addons/documents/doc-editor/components/DocEditorScreen.js
index 4c840f05..f14c0191 100644
--- a/app/addons/documents/doc-editor/components/DocEditorScreen.js
+++ b/app/addons/documents/doc-editor/components/DocEditorScreen.js
@@ -111,7 +111,9 @@ export default class DocEditorScreen extends React.Component {
   };
 
   onSaveComplete = () => {
-    this.getEditor().clearChanges();
+    if (this.getEditor()) {
+      this.getEditor().clearChanges();
+    }
   };
 
   hideDeleteDocModal = () => {
diff --git a/app/addons/documents/tests/nightwatch/checkSidebarBehavior.js b/app/addons/documents/tests/nightwatch/checkSidebarBehavior.js
index d485581a..5ed28f80 100644
--- a/app/addons/documents/tests/nightwatch/checkSidebarBehavior.js
+++ b/app/addons/documents/tests/nightwatch/checkSidebarBehavior.js
@@ -36,7 +36,7 @@ module.exports = {
       .clickWhenVisible('span[title="_design/' + docSpecialChars + '"]')
       .assert.visible('a[href="#/database/' + newDatabaseName + '/_design/' + docSpecialCharsEncoded + '/_info"]')
       // Verify display name is not encoded
-      .assert.containsText('span[title="_design/' + docSpecialChars + '"]', docSpecialChars)
+      .assert.textContains('span[title="_design/' + docSpecialChars + '"]', docSpecialChars)
       .end();
   }
 };
diff --git a/app/addons/documents/tests/nightwatch/editDocumentWithStringEditor.js b/app/addons/documents/tests/nightwatch/editDocumentWithStringEditor.js
index 7b8c507c..848e53f6 100644
--- a/app/addons/documents/tests/nightwatch/editDocumentWithStringEditor.js
+++ b/app/addons/documents/tests/nightwatch/editDocumentWithStringEditor.js
@@ -44,7 +44,7 @@ module.exports = {
       .waitForElementNotPresent('#string-editor-container', waitTime, false)
       //Check value has changed in the maind editor
       .waitForElementPresent('#editor-container', waitTime, false)
-      .assert.containsText('span.ace_string', '"' + newDocumentName + '"')
+      .assert.textContains('span.ace_string', '"' + newDocumentName + '"')
       .end();
   }
 };
diff --git a/app/addons/documents/tests/nightwatch/jsonView.js b/app/addons/documents/tests/nightwatch/jsonView.js
index 7fdb28ce..9c36b2a5 100644
--- a/app/addons/documents/tests/nightwatch/jsonView.js
+++ b/app/addons/documents/tests/nightwatch/jsonView.js
@@ -23,7 +23,7 @@ module.exports = {
       .waitForElementPresent('.doc-item', client.globals.maxWaitTime, false)
       // by default include_docs is on, so check "American Bittern" does exist in the DOM
       .waitForElementPresent('.prettyprint', client.globals.maxWaitTime, false)
-      .assert.containsText('.prettyprint', 'American Bittern')
+      .assert.textContains('.prettyprint', 'American Bittern')
       .end();
   }
 };
diff --git a/app/addons/documents/tests/nightwatch/mangoIndex.js b/app/addons/documents/tests/nightwatch/mangoIndex.js
index 7d9b791c..8593c67c 100644
--- a/app/addons/documents/tests/nightwatch/mangoIndex.js
+++ b/app/addons/documents/tests/nightwatch/mangoIndex.js
@@ -42,7 +42,7 @@ module.exports = {
       .checkForStringPresent(newDatabaseName + '/_index', 'rocko-artischocko')
       .checkForStringPresent(newDatabaseName + '/_index', 'gans_gans_mango')
       .waitForElementPresent('.prettyprint', waitTime, false)
-      .assert.containsText('#dashboard-lower-content', 'gans_gans_mango')
+      .assert.textContains('#dashboard-lower-content', 'gans_gans_mango')
       .end();
   },
 
@@ -56,7 +56,7 @@ module.exports = {
       .loginToGUI()
       .url(baseUrl + '/#/database/' + newDatabaseName + '/_index')
       .waitForElementPresent('#doc-list', waitTime, false)
-      .assert.containsText('#dashboard-lower-content', 'ente_ente_mango_ananas')
+      .assert.textContains('#dashboard-lower-content', 'ente_ente_mango_ananas')
       .clickWhenVisible('.bulk-action-component-panel input[type="checkbox"]')
       .clickWhenVisible('.bulk-action-component-selector-group button.fonticon-trash', waitTime, false)
       .acceptAlert()
diff --git a/app/addons/documents/tests/nightwatch/mangoQuery.js b/app/addons/documents/tests/nightwatch/mangoQuery.js
index dc9054bb..cf4b5098 100644
--- a/app/addons/documents/tests/nightwatch/mangoQuery.js
+++ b/app/addons/documents/tests/nightwatch/mangoQuery.js
@@ -38,8 +38,8 @@ module.exports = {
       .clickWhenVisible('.fonticon-json')
 
       .waitForElementPresent('.prettyprint', waitTime, false)
-      .assert.containsText('#dashboard-lower-content', 'number')
-      .assert.containsText('#dashboard-lower-content', 'ente_ente_mango_ananas_res')
+      .assert.textContains('#dashboard-lower-content', 'number')
+      .assert.textContains('#dashboard-lower-content', 'ente_ente_mango_ananas_res')
       .end();
   }
 };
diff --git a/app/addons/documents/tests/nightwatch/navigateNotFoundDB.js b/app/addons/documents/tests/nightwatch/navigateNotFoundDB.js
index 802ef3bf..ee2b46a3 100644
--- a/app/addons/documents/tests/nightwatch/navigateNotFoundDB.js
+++ b/app/addons/documents/tests/nightwatch/navigateNotFoundDB.js
@@ -25,9 +25,9 @@ module.exports = {
       .url(baseUrl + '/#/database/does-not-exist/_all_docs')
       .waitForElementVisible('.Toastify__toast-container .Toastify__toast--error', waitTime, false)
       // We wait for the first toasts to be cleared
-      .pause(1000)
+      .pause(3000)
       .waitForElementVisible('.Toastify__toast-container .Toastify__toast--error', waitTime, false)
-      .assert.containsText('.Toastify__toast-container .Toastify__toast--error .Toastify__toast-body', 'does not exist')
+      .assert.textContains('.Toastify__toast-container .Toastify__toast--error .Toastify__toast-body', 'does not exist')
       .verify.urlEquals(baseUrl + '/#');
   }
 };
diff --git a/app/addons/documents/tests/nightwatch/paginateAllDocs.js b/app/addons/documents/tests/nightwatch/paginateAllDocs.js
index 9455e1f4..a121ddc9 100644
--- a/app/addons/documents/tests/nightwatch/paginateAllDocs.js
+++ b/app/addons/documents/tests/nightwatch/paginateAllDocs.js
@@ -10,10 +10,7 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-
-
 module.exports = {
-
   'change number of items per page': function (client) {
     /*jshint multistr: true */
     var waitTime = client.globals.maxWaitTime,
@@ -25,16 +22,9 @@ module.exports = {
       .loginToGUI()
       .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
       .clickWhenVisible('.fonticon-json')
-
       // ensures the main body (results list) has been rendered
       .waitForElementPresent('.prettyprint', waitTime, false)
-
-      // ensures the select dropdown is rendered
-      .clickWhenVisible('#select-per-page', waitTime, false)
-
-      // hack to get select working by clicking on it and using keyboard to select
-      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
-      .keys(['\uE013', '\uE006'])
+      .clickWhenVisible('select[id="select-per-page"] option[value="10"]')
       .waitForElementPresent('.prettyprint', waitTime, false)
       .waitForElementNotPresent('div[data-id="document_16"]', waitTime)
       .waitForElementPresent('.doc-row', waitTime, false)
@@ -63,9 +53,8 @@ module.exports = {
       // ensures the main body (results list) has been rendered
       .waitForElementPresent('.prettyprint', waitTime, false)
 
-      .clickWhenVisible('#select-per-page', waitTime, false)
-      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
-      .keys(['\uE013', '\uE006'])
+      .clickWhenVisible('select[id="select-per-page"] option[value="10"]')
+
       .waitForElementNotPresent('.loading-lines', waitTime, false)
       .waitForElementNotPresent('div[data-id="document_16"]', waitTime)
       .clickWhenVisible('#next', waitTime, false)
@@ -91,17 +80,17 @@ module.exports = {
 
       // ensures the main body (results list) has been rendered
       .waitForElementPresent('.prettyprint', waitTime, false)
+      // moving from '20'
+      .clickWhenVisible('select[id="select-per-page"] option[value="10"]')
 
-      .clickWhenVisible('#select-per-page', waitTime, false)
-      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
-      .keys(['\uE013', '\uE006'])
       .waitForElementNotPresent('.loading-lines', waitTime, false)
       .waitForElementNotPresent('div[data-id="document_16"]', waitTime)
       .clickWhenVisible('#next', waitTime, false)
       .waitForElementPresent('div[data-id="document_17"]', waitTime)
       .clickWhenVisible('#select-per-page', waitTime, false)
-      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
-      .keys(['\uE013', '\uE006'])
+      // moving from '10'
+      .clickWhenVisible('select[id="select-per-page"] option[value="5"]')
+
       .waitForElementPresent('div[data-id="document_1"]', waitTime)
       .end();
   },
@@ -123,7 +112,8 @@ module.exports = {
 
       .clickWhenVisible('#select-per-page', waitTime, false)
       // http://www.w3.org/TR/2012/WD-webdriver-20120710/
-      .keys(['\uE013', '\uE006'])
+      // moving from '20'
+      .clickWhenVisible('select[id="select-per-page"] option[value="10"]')
       .waitForElementNotPresent('.loading-lines', waitTime, false)
       .waitForElementNotPresent('td[title="document_16"]', waitTime)
       .clickWhenVisible('#next', waitTime, false)
diff --git a/app/addons/documents/tests/nightwatch/paginateView.js b/app/addons/documents/tests/nightwatch/paginateView.js
index 7fe52506..e92b6663 100644
--- a/app/addons/documents/tests/nightwatch/paginateView.js
+++ b/app/addons/documents/tests/nightwatch/paginateView.js
@@ -35,11 +35,9 @@ module.exports = {
       .waitForElementPresent('.prettyprint', waitTime, false)
 
       .waitForElementPresent('#select-per-page', waitTime, false)
-      .clickWhenVisible('#select-per-page', waitTime, false)
 
-      // hack to get select working by clicking on it and using keyboard to select
-      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
-      .keys(['\uE013', '\uE006'])
+      // from '20'
+      .clickWhenVisible('select[id="select-per-page"] option[value="10"]')
       .waitForElementPresent('.prettyprint', waitTime, false)
       .waitForElementNotPresent('div[data-id="document_9"]', waitTime)
       .execute(function () {
@@ -69,10 +67,9 @@ module.exports = {
       // ensure the page content has loaded
       .waitForElementPresent('.prettyprint', waitTime, false)
 
-      .clickWhenVisible('#select-per-page', waitTime, false)
+      // from '20'
+      .clickWhenVisible('select[id="select-per-page"] option[value="10"]')
 
-      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
-      .keys(['\uE013', '\uE006'])
       .waitForElementNotPresent('.loading-lines', waitTime, false)
       .waitForElementPresent('#next', waitTime, false)
       .clickWhenVisible('#next', waitTime, false)
@@ -104,19 +101,16 @@ module.exports = {
 
       // ensure the page content has loaded
       .waitForElementPresent('.prettyprint', waitTime, false)
-      .clickWhenVisible('#select-per-page', waitTime, false)
-
-      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
-      .keys(['\uE013', '\uE006'])
+      // from '20'
+      .clickWhenVisible('select[id="select-per-page"] option[value="10"]')
       .waitForElementNotPresent('.loading-lines', waitTime, false)
 
       .clickWhenVisible('#next', waitTime, false)
       .waitForElementNotPresent('div[data-id="document_1"]', waitTime)
       .waitForElementNotPresent('.loading-lines', waitTime, false)
 
-      .clickWhenVisible('#select-per-page', waitTime, false)
-      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
-      .keys(['\uE013', '\uE006'])
+      // from '10'
+      .clickWhenVisible('select[id="select-per-page"] option[value="5"]')
 
       .waitForElementPresent('div[data-id="document_1"]', waitTime)
       .end();
@@ -140,10 +134,9 @@ module.exports = {
       // ensure the page content has loaded
       .waitForElementPresent('.table-view-docs', waitTime)
 
-      .clickWhenVisible('#select-per-page', waitTime, false)
+      // from '20'
+      .clickWhenVisible('select[id="select-per-page"] option[value="10"]')
 
-      // http://www.w3.org/TR/2012/WD-webdriver-20120710/
-      .keys(['\uE013', '\uE006'])
       .waitForElementNotPresent('.loading-lines', waitTime, false)
       .waitForElementPresent('#next', waitTime, false)
       .clickWhenVisible('#next', waitTime, false)
diff --git a/app/addons/documents/tests/nightwatch/resultsToolbar.js b/app/addons/documents/tests/nightwatch/resultsToolbar.js
index 74c2e0fb..09ffd9d8 100644
--- a/app/addons/documents/tests/nightwatch/resultsToolbar.js
+++ b/app/addons/documents/tests/nightwatch/resultsToolbar.js
@@ -27,7 +27,7 @@ module.exports = {
 
       .url(`${baseUrl}#/database/${newDatabaseName}/_all_docs`)
       .waitForElementPresent('.two-sides-toggle-button', waitTime, false)
-      .assert.containsText('.two-sides-toggle-button button.active', 'Metadata')
+      .assert.textContains('.two-sides-toggle-button button.active', 'Metadata')
       .assert.not.elementPresent('.table-container-autocomplete')
       .end();
   },
@@ -47,7 +47,7 @@ module.exports = {
       .checkForDocumentCreated(newDocumentName)
       .url(`${baseUrl}#/database/${newDatabaseName}/_all_docs`)
       .waitForElementPresent('.two-sides-toggle-button', waitTime, false)
-      .assert.containsText('.two-sides-toggle-button button.active', 'Metadata')
+      .assert.textContains('.two-sides-toggle-button button.active', 'Metadata')
 
       // turn include_docs on through query options
       .clickWhenVisible('.control-toggle-queryoptions')
@@ -55,18 +55,18 @@ module.exports = {
       .clickWhenVisible('#qoIncludeDocsLabel')
       .clickWhenVisible('.query-options .btn-secondary')
       .waitForElementPresent('.two-sides-toggle-button', waitTime, false)
-      .assert.containsText('.two-sides-toggle-button button.active', 'Table')
+      .assert.textContains('.two-sides-toggle-button button.active', 'Table')
 
       // switch to json view and then turn off include_docs
       .clickWhenVisible('.fonticon-json')
-      .assert.containsText('.two-sides-toggle-button button.active', 'JSON')
+      .assert.textContains('.two-sides-toggle-button button.active', 'JSON')
       .clickWhenVisible('.control-toggle-queryoptions')
       .waitForElementPresent('#qoIncludeDocsLabel', waitTime, false)
       .assert.attributeEquals('#qoIncludeDocs', 'checked', 'true')
       .clickWhenVisible('#qoIncludeDocsLabel')
       .clickWhenVisible('.query-options .btn-secondary')
       .waitForElementPresent('.two-sides-toggle-button', waitTime, false)
-      .assert.containsText('.two-sides-toggle-button button.active', 'Metadata')
+      .assert.textContains('.two-sides-toggle-button button.active', 'Metadata')
       .end();
   },
 };
diff --git a/app/addons/documents/tests/nightwatch/revBrowser.js b/app/addons/documents/tests/nightwatch/revBrowser.js
index bc0f3634..3256cd5a 100644
--- a/app/addons/documents/tests/nightwatch/revBrowser.js
+++ b/app/addons/documents/tests/nightwatch/revBrowser.js
@@ -30,15 +30,15 @@ module.exports = {
 
       .waitForElementVisible('.revision-diff-area', waitTime, false)
 
-      .assert.containsText('.revision-diff-area', '"black & white"')
-      .assert.containsText('.revision-diff-area', '"white"')
+      .assert.textContains('.revision-diff-area', '"black & white"')
+      .assert.textContains('.revision-diff-area', '"white"')
 
       .clickWhenVisible('.two-sides-toggle-button button:last-child')
 
       .waitForElementVisible('.revision-split-area', waitTime, false)
 
-      .assert.containsText('.revision-split-area [data-id="ours"]', '"black & white"')
-      .assert.containsText('.revision-split-area [data-id="theirs"]', '"white"')
+      .assert.textContains('.revision-split-area [data-id="ours"]', '"black & white"')
+      .assert.textContains('.revision-split-area [data-id="theirs"]', '"white"')
 
 
       .clickWhenVisible('[data-id="button-select-theirs"]')
@@ -76,15 +76,15 @@ module.exports = {
 
       .waitForElementVisible('.revision-diff-area', waitTime, false)
 
-      .assert.containsText('.revision-diff-area', '"black & white"')
-      .assert.containsText('.revision-diff-area', '"white"')
+      .assert.textContains('.revision-diff-area', '"black & white"')
+      .assert.textContains('.revision-diff-area', '"white"')
 
       .clickWhenVisible('.two-sides-toggle-button button:last-child')
 
       .waitForElementVisible('.revision-split-area', waitTime, false)
 
-      .assert.containsText('.revision-split-area [data-id="ours"]', '"black & white"')
-      .assert.containsText('.revision-split-area [data-id="theirs"]', '"white"')
+      .assert.textContains('.revision-split-area [data-id="ours"]', '"black & white"')
+      .assert.textContains('.revision-split-area [data-id="theirs"]', '"white"')
 
 
       .clickWhenVisible('[data-id="button-select-theirs"]')
diff --git a/app/addons/documents/tests/nightwatch/selectDocViaTypeahead.js b/app/addons/documents/tests/nightwatch/selectDocViaTypeahead.js
index b96340dc..7480860d 100644
--- a/app/addons/documents/tests/nightwatch/selectDocViaTypeahead.js
+++ b/app/addons/documents/tests/nightwatch/selectDocViaTypeahead.js
@@ -9,11 +9,11 @@
 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 // License for the specific language governing permissions and limitations under
 // the License.
+const {Key} = require('selenium-webdriver');
 
 
 
 module.exports = {
-
   'Select doc via typeahead field redirects user': function (client) {
     var waitTime = client.globals.maxWaitTime,
         newDatabaseName = client.globals.testDatabaseName,
@@ -25,12 +25,22 @@ module.exports = {
       .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
       .clickWhenVisible('.fonticon-json')
       .waitForElementPresent('.jump-to-doc', waitTime, false)
-      .keys(['\uE00C'])
+      .perform(function() {
+        const actions = this.actions({async: true});
+        return actions
+          .sendKeys(Key.ESCAPE);
+      })
       .waitForElementPresent('.prettyprint', waitTime, false)
       .waitForElementPresent('.documents-pagination', waitTime, false)
       .setValue('.jump-to-doc .Select-input input', ['_des'])
       .waitForElementPresent('.Select-option', waitTime, false)
-      .keys(['\uE015', '\uE015', '\uE006'])
+      .perform(function() {
+        const actions = this.actions({async: true});
+        return actions
+          .sendKeys(Key.DOWN)
+          .sendKeys(Key.DOWN)
+          .sendKeys(Key.ENTER);
+      })
       .waitForElementPresent('.panel-button.upload', waitTime, false)
       .end();
   },
@@ -46,12 +56,22 @@ module.exports = {
       .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
       .clickWhenVisible('.fonticon-json')
       .waitForElementPresent('.jump-to-doc', waitTime, false)
-      .keys(['\uE00C'])
+      .perform(function() {
+        const actions = this.actions({async: true});
+        return actions
+          .sendKeys(Key.ESCAPE);
+      })
       .waitForElementPresent('.prettyprint', waitTime, false)
       .waitForElementPresent('.documents-pagination', waitTime, false)
       .setValue('.jump-to-doc .Select-input input', ['MY_CAP'])
       .waitForElementPresent('.Select-option', waitTime, false)
-      .keys(['\uE015', '\uE015', '\uE006'])
+      .perform(function() {
+        const actions = this.actions({async: true});
+        return actions
+          .sendKeys(Key.DOWN)
+          .sendKeys(Key.DOWN)
+          .sendKeys(Key.ENTER);
+      })
       .waitForElementPresent('.panel-button.upload', waitTime, false)
       .end();
   }
diff --git a/app/addons/documents/tests/nightwatch/tableView.js b/app/addons/documents/tests/nightwatch/tableView.js
index a5d32017..d7d28072 100644
--- a/app/addons/documents/tests/nightwatch/tableView.js
+++ b/app/addons/documents/tests/nightwatch/tableView.js
@@ -60,7 +60,7 @@ module.exports = {
       .checkForDocumentCreated(newDocumentName1)
       .checkForDocumentCreated(newDocumentName2)
       .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
-      .assert.containsText('button.active', 'Metadata')
+      .assert.textContains('button.active', 'Metadata')
       .waitForElementVisible('.tableview-checkbox-cell', waitTime, false)
       .waitForElementVisible('.table', waitTime, false)
       .getText('.table', function (result) {
diff --git a/app/addons/documents/tests/nightwatch/viewClone.js b/app/addons/documents/tests/nightwatch/viewClone.js
index 1d6bbff4..518f8555 100644
--- a/app/addons/documents/tests/nightwatch/viewClone.js
+++ b/app/addons/documents/tests/nightwatch/viewClone.js
@@ -24,7 +24,7 @@ module.exports = {
       .url(baseUrl + '/#/database/' + newDatabaseName + '/_design/testdesigndoc/_view/stubview')
       .clickWhenVisible('.fonticon-json')
       .waitForElementPresent('.prettyprint', waitTime, false)
-      .assert.containsText('.prettyprint', 'stub')
+      .assert.textContains('.prettyprint', 'stub')
       .clickWhenVisible('.index-list .active span', waitTime, true)
       .clickWhenVisible('.popover-content .fonticon-files-o', waitTime, true)
       .waitForElementVisible('#new-index-name', waitTime, true)
diff --git a/app/addons/documents/tests/nightwatch/viewCreate.js b/app/addons/documents/tests/nightwatch/viewCreate.js
index aa83f64c..5b76ec1d 100644
--- a/app/addons/documents/tests/nightwatch/viewCreate.js
+++ b/app/addons/documents/tests/nightwatch/viewCreate.js
@@ -29,7 +29,7 @@ module.exports = {
       .checkForDocumentCreated('_design/test_design_doc-selenium-0')
       .waitForElementNotPresent('.loading-lines', waitTime, false)
       .waitForElementPresent('.table-view-docs', waitTime, false)
-      .assert.containsText('td[title="blerg"]', 'blerg')
+      .assert.textContains('td[title="blerg"]', 'blerg')
       .end();
   },
 
@@ -50,7 +50,7 @@ module.exports = {
       .checkForDocumentCreated('_design/test_design_doc-selenium-1')
       .waitForElementNotPresent('.loading-lines', waitTime, false)
       .waitForElementPresent('.table-view-docs', waitTime, false)
-      .assert.containsText('td[title="hasehase"]', 'hasehase')
+      .assert.textContains('td[title="hasehase"]', 'hasehase')
       .end();
   },
 
@@ -73,7 +73,7 @@ module.exports = {
 
       // page now automatically redirects user to results of View. Confirm the new doc is present.
       .waitForElementPresent('.table-view-docs', waitTime, false)
-      .assert.containsText('td[title="hasehase"]', 'hasehase')
+      .assert.textContains('td[title="hasehase"]', 'hasehase')
       .end();
   },
 
@@ -94,7 +94,7 @@ module.exports = {
       .checkForDocumentCreated('_design/test_design_doc-selenium-2')
       .waitForElementNotPresent('.loading-lines', waitTime, false)
       .waitForElementPresent('.table-view-docs', waitTime, false)
-      .assert.containsText('td[title="gansgans"]', 'gansgans')
+      .assert.textContains('td[title="gansgans"]', 'gansgans')
       .end();
   },
 
@@ -121,7 +121,7 @@ module.exports = {
       .checkForDocumentCreated('_design/testdesigndoc/_view/test-new-view')
       .waitForElementNotPresent('.loading-lines', waitTime, false)
       .waitForElementPresent('.table-view-docs', waitTime, false)
-      .assert.containsText('td[title="enteente"]', 'enteente')
+      .assert.textContains('td[title="enteente"]', 'enteente')
       .end();
   }
 };
diff --git a/app/addons/documents/tests/nightwatch/viewCreateBadView.js b/app/addons/documents/tests/nightwatch/viewCreateBadView.js
index ddac11c6..39c6414e 100644
--- a/app/addons/documents/tests/nightwatch/viewCreateBadView.js
+++ b/app/addons/documents/tests/nightwatch/viewCreateBadView.js
@@ -10,8 +10,6 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-
-
 module.exports = {
 
   'Displays an error if reduce is not possible': function (client) {
@@ -30,8 +28,7 @@ module.exports = {
       .setValue('#new-ddoc', 'test_design_doc-selenium-bad-reduce')
       .clearValue('#index-name')
       .setValue('#index-name', 'hasenindex')
-      .clickWhenVisible('#reduce-function-selector')
-      .keys(['\uE013', '\uE013', '\uE013', '\uE013', '\uE013', '\uE006'])
+      .clickWhenVisible('select[id="reduce-function-selector"] option[value="_sum"]')
       .execute('\
         var editor = ace.edit("map-function");\
         editor.getSession().setValue("function (doc) { emit(\'boom\', doc._id); }");\
diff --git a/app/addons/documents/tests/nightwatch/viewDelete.js b/app/addons/documents/tests/nightwatch/viewDelete.js
index 4959db4c..44d60b0c 100644
--- a/app/addons/documents/tests/nightwatch/viewDelete.js
+++ b/app/addons/documents/tests/nightwatch/viewDelete.js
@@ -26,7 +26,7 @@ module.exports = {
       .url(baseUrl + '/#/database/' + newDatabaseName + '/_design/testdesigndoc/_view/stubview')
       .clickWhenVisible('.fonticon-json')
       .waitForElementPresent('.prettyprint', waitTime, false)
-      .assert.containsText('.prettyprint', 'stub')
+      .assert.textContains('.prettyprint', 'stub')
 
       // confirm the sidebar shows the testdesigndoc design doc
       .waitForElementVisible('#design-doc-menu-testdesigndoc', waitTime, true)
diff --git a/app/addons/documents/tests/nightwatch/viewEdit.js b/app/addons/documents/tests/nightwatch/viewEdit.js
index 8fde21e6..f9de8098 100644
--- a/app/addons/documents/tests/nightwatch/viewEdit.js
+++ b/app/addons/documents/tests/nightwatch/viewEdit.js
@@ -13,7 +13,6 @@
 
 
 module.exports = {
-
   'Edits a design doc - renames index': function (client) {
     var waitTime = client.globals.maxWaitTime,
         newDatabaseName = client.globals.testDatabaseName,
@@ -139,23 +138,19 @@ module.exports = {
           `expected header text to contain '${newDatabaseName}' and found '${headerContent}'`
         );
       })
-
       .waitForElementVisible('#new-ddoc', waitTime, false)
       .setValue('#new-ddoc', 'view1-name')
       .clearValue('#index-name')
       .setValue('#index-name', 'view1')
-      .clickWhenVisible('#reduce-function-selector')
-      .keys(['\uE013', '\uE013', '\uE013', '\uE013', '\uE013', '\uE006'])
+      .clickWhenVisible('select[id="reduce-function-selector"] option[value="_sum"]')
       .execute('\
         var editor = ace.edit("map-function");\
         editor.getSession().setValue("function (doc) { emit(doc._id, 100); }");\
       ')
       .clickWhenVisible('#save-view')
       .checkForDocumentCreated('_design/view1-name')
-
       // create the second view
       .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
-      .closeNotifications()
 
       .clickWhenVisible('.faux-header__doc-header-dropdown-toggle')
       .clickWhenVisible('.faux-header__doc-header-dropdown-itemwrapper a[href*="new_view"]')
@@ -176,8 +171,7 @@ module.exports = {
       .setValue('#new-ddoc', 'view2-name')
       .clearValue('#index-name')
       .setValue('#index-name', 'view2')
-      .clickWhenVisible('#reduce-function-selector')
-      .keys(['\uE013', '\uE013', '\uE013', '\uE013', '\uE006'])
+      .clickWhenVisible('select[id="reduce-function-selector"] option[value="_count"]')
       .execute('\
         var editor = ace.edit("map-function");\
         editor.getSession().setValue("function (doc) { emit(doc._id, 200); }");\
@@ -251,8 +245,7 @@ module.exports = {
       .waitForElementPresent('.index-cancel-link', waitTime, true)
       .waitForElementVisible('.styled-select select', waitTime, true)
       .waitForElementNotPresent('.loading-lines', waitTime, true)
-
-      .setValue('.styled-select select', 'new-doc')
+      .clickWhenVisible('select[id="faux__edit-view__design-doc"] option[value="new-doc"]')
 
       // needed to get React to update + show the new design doc field
       .click('body')
diff --git a/app/addons/fauxton/tests/nightwatch/highlightsidebar.js b/app/addons/fauxton/tests/nightwatch/highlightsidebar.js
index 8dd1588b..871666db 100644
--- a/app/addons/fauxton/tests/nightwatch/highlightsidebar.js
+++ b/app/addons/fauxton/tests/nightwatch/highlightsidebar.js
@@ -24,7 +24,7 @@ module.exports = {
       .click('a[href="#/replication"]')
       .pause(1000)
       .waitForElementVisible('.replication__activity_header-btn', waitTime, false)
-      .assert.cssClassPresent('a[href="#/replication"]', 'faux-navbar__link--active')
+      .assert.hasClass('a[href="#/replication"]', 'faux-navbar__link--active')
       .end();
   }
 };
diff --git a/app/addons/permissions/tests/nightwatch/permissions.js b/app/addons/permissions/tests/nightwatch/permissions.js
index a51db00c..518822de 100644
--- a/app/addons/permissions/tests/nightwatch/permissions.js
+++ b/app/addons/permissions/tests/nightwatch/permissions.js
@@ -29,11 +29,11 @@ module.exports = {
       .clickWhenVisible('.permissions__admins .permissions-add-user button')
 
       .waitForElementVisible('.permissions__admins .permissions__entry', waitTime, false)
-      .assert.containsText('.permissions__entry span', 'blergie')
+      .assert.textContains('.permissions__entry span', 'blergie')
 
       .url(baseUrl + '/#/database/' + newDatabaseName + '/permissions')
       .waitForElementVisible('.permissions__admins .permissions__entry', waitTime, false)
-      .assert.containsText('.permissions__entry span', 'blergie')
+      .assert.textContains('.permissions__entry span', 'blergie')
 
       .end();
   }
diff --git a/app/addons/replication/tests/nightwatch/replication.js b/app/addons/replication/tests/nightwatch/replication.js
index d05673eb..4b0e4454 100644
--- a/app/addons/replication/tests/nightwatch/replication.js
+++ b/app/addons/replication/tests/nightwatch/replication.js
@@ -50,16 +50,13 @@ module.exports = {
       .waitForElementVisible('#replication-source', waitTime, true)
 
       // select LOCAL as the source
-      .clickWhenVisible('#replication-source')
-      .keys(['\uE015', '\uE006'])
+      .clickWhenVisible('select[id="replication-source"] option[value="REPLICATION_SOURCE_LOCAL"]')
       .waitForElementVisible('.replication__input-react-select', waitTime, true)
-
       // enter our source DB
       .setValue('.replication__input-react-select .Select-input input', [newDatabaseName1, client.Keys.ENTER])
 
       // select source USER/PASSWORD authentication
-      .clickWhenVisible('#select-replication-source-auth')
-      .keys(['\uE015', '\uE006'])
+      .clickWhenVisible('select[id="select-replication-source-auth"] option[value="BASIC_AUTH"]')
       .waitForElementVisible('#replication-source-auth-username', waitTime, true)
 
       // enter source username/password
@@ -71,8 +68,7 @@ module.exports = {
       .setValue('.replication__new-input', replicatedDBName)
 
       // select target USER/PASSWORD authentication
-      .clickWhenVisible('#select-replication-target-auth')
-      .keys(['\uE015', '\uE006'])
+      .clickWhenVisible('select[id="select-replication-target-auth"] option[value="BASIC_AUTH"]')
       .waitForElementVisible('#replication-target-auth-username', waitTime, true)
 
       // enter target username/password
@@ -106,14 +102,13 @@ module.exports = {
       .waitForElementVisible('#replication-source', waitTime, true)
 
       // select the LOCAL db as the source
-      .clickWhenVisible('#replication-source')
-      .keys(['\uE015', '\uE006'])
+      .clickWhenVisible('select[id="replication-source"] option[value="REPLICATION_SOURCE_LOCAL"]')
       .waitForElementVisible('.replication__input-react-select', waitTime, true)
       .setValue('.replication__input-react-select .Select-input input', [newDatabaseName1, client.Keys.ENTER])
 
+
       // select source USER/PASSWORD authentication
-      .clickWhenVisible('#select-replication-source-auth')
-      .keys(['\uE015', '\uE006'])
+      .clickWhenVisible('select[id="select-replication-source-auth"] option[value="BASIC_AUTH"]')
       .waitForElementVisible('#replication-source-auth-username', waitTime, true)
 
       // enter source username/password
@@ -125,8 +120,7 @@ module.exports = {
       .setValue('#replication-target-local .Select-input input', [newDatabaseName2, client.Keys.ENTER])
 
       // select target USER/PASSWORD authentication
-      .clickWhenVisible('#select-replication-target-auth')
-      .keys(['\uE015', '\uE006'])
+      .clickWhenVisible('select[id="select-replication-target-auth"] option[value="BASIC_AUTH"]')
       .waitForElementVisible('#replication-target-auth-username', waitTime, true)
 
       // enter target username/password
@@ -171,14 +165,13 @@ module.exports = {
       .waitForElementVisible('#replication-source', waitTime, true)
 
       // select the LOCAL db as the source
-      .clickWhenVisible('#replication-source')
-      .keys(['\uE015', '\uE006'])
+      .clickWhenVisible('select[id="replication-source"] option[value="REPLICATION_SOURCE_LOCAL"]')
       .waitForElementVisible('.replication__input-react-select', waitTime, true)
       .setValue('.replication__input-react-select .Select-input input', [newDatabaseName1, client.Keys.ENTER])
 
+
       // select source USER/PASSWORD authentication
-      .clickWhenVisible('#select-replication-source-auth')
-      .keys(['\uE015', '\uE006'])
+      .clickWhenVisible('select[id="select-replication-source-auth"] option[value="BASIC_AUTH"]')
       .waitForElementVisible('#replication-source-auth-username', waitTime, true)
 
       // enter source username/password
@@ -191,8 +184,7 @@ module.exports = {
       .setValue('.replication__doc-name-input', [replicatorDoc._id, client.Keys.ENTER])
 
       // select target USER/PASSWORD authentication
-      .clickWhenVisible('#select-replication-target-auth')
-      .keys(['\uE015', '\uE006'])
+      .clickWhenVisible('select[id="select-replication-target-auth"] option[value="BASIC_AUTH"]')
       .waitForElementVisible('#replication-target-auth-username', waitTime, true)
 
       // enter target username/password
@@ -225,10 +217,10 @@ module.exports = {
       .waitForElementVisible('button#replicate', waitTime, true)
       .waitForElementVisible('#replication-source', waitTime, true)
 
-      // select LOCAL as the source
-      .clickWhenVisible('#replication-source')
-      .keys(['\uE015', '\uE006'])
+      // select local db as the source
+      .clickWhenVisible('select[id="replication-source"] option[value="REPLICATION_SOURCE_LOCAL"]')
       .waitForElementVisible('.replication__input-react-select', waitTime, true)
+      .setValue('.replication__input-react-select .Select-input input', [newDatabaseName1, client.Keys.ENTER])
 
       // enter our source DB
       .setValue('.replication__input-react-select .Select-input input', [newDatabaseName1, client.Keys.ENTER])
@@ -257,17 +249,16 @@ module.exports = {
       .waitForElementVisible('button#replicate', waitTime, true)
       .waitForElementVisible('#replication-source', waitTime, true)
 
-      // select LOCAL as the source
-      .clickWhenVisible('#replication-source')
-      .keys(['\uE015', '\uE006'])
+      // select local db as the source
+      .clickWhenVisible('select[id="replication-source"] option[value="REPLICATION_SOURCE_LOCAL"]')
       .waitForElementVisible('.replication__input-react-select', waitTime, true)
+      .setValue('.replication__input-react-select .Select-input input', [newDatabaseName1, client.Keys.ENTER])
 
       // enter our source DB
       .setValue('.replication__input-react-select .Select-input input', [newDatabaseName1, client.Keys.ENTER])
 
       // select source USER/PASSWORD authentication
-      .clickWhenVisible('#select-replication-source-auth')
-      .keys(['\uE015', '\uE006'])
+      .clickWhenVisible('select[id="select-replication-source-auth"] option[value="BASIC_AUTH"]')
       .waitForElementVisible('#replication-source-auth-username', waitTime, true)
 
       // enter source username/password
diff --git a/bin/docker-up-and-check.sh b/bin/docker-up-and-check.sh
index 27f99c78..1a228c4d 100755
--- a/bin/docker-up-and-check.sh
+++ b/bin/docker-up-and-check.sh
@@ -14,7 +14,7 @@
 
 
 ## Sometimes the couchdb docker container won't start correctly, which causes
-## the Travis build to fail and forces users to resubmit their PRs.
+## the GitHub Actions build to fail and forces users to resubmit their PRs.
 ## This script tries to minimize the issue by retrying to start the containers
 ## in case of failure.
 
diff --git a/docker/dc.selenium.yml b/docker/couchdb.yml
similarity index 62%
rename from docker/dc.selenium.yml
rename to docker/couchdb.yml
index 0061bed2..bf87d035 100644
--- a/docker/dc.selenium.yml
+++ b/docker/couchdb.yml
@@ -1,10 +1,5 @@
 version: '2'
 services:
-  selenium:
-    container_name: selenium
-    image: selenium/standalone-chrome:3.141.59
-    ports:
-      - "4444:4444"
   couchdb:
     container_name: couchdb
     image: ${COUCHDB_IMAGE}
diff --git a/docker/dc.selenium-debug.yml b/docker/dc.selenium-debug.yml
deleted file mode 100644
index cba3c54c..00000000
--- a/docker/dc.selenium-debug.yml
+++ /dev/null
@@ -1,15 +0,0 @@
-version: '2'
-services:
-  selenium:
-    extends:
-      file: './dc.selenium.yml'
-      service: selenium
-    container_name: selenium
-    image: selenium/standalone-chrome-debug:3.141.59
-    ports:
-      - "4444:4444"
-      - "5900:5900"
-  couchdb:
-    extends:
-      file: './dc.selenium.yml'
-      service: couchdb
diff --git a/package-lock.json b/package-lock.json
index fb1ad69f..dfb2f733 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4919,6 +4919,26 @@
       "dev": true,
       "optional": true
     },
+    "@nightwatch/chai": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/@nightwatch/chai/-/chai-5.0.2.tgz",
+      "integrity": "sha512-yzILJFCcE75OPoRfBlJ80Y3Ky06ljsdrK4Ld92yhmM477vxO2GEguwnd+ldl7pdSYTcg1gSJ1bPPQrA+/Hrn+A==",
+      "dev": true,
+      "requires": {
+        "assertion-error": "1.1.0",
+        "check-error": "1.0.2",
+        "deep-eql": "4.0.1",
+        "loupe": "2.3.4",
+        "pathval": "1.1.1",
+        "type-detect": "4.0.8"
+      }
+    },
+    "@nightwatch/ejs": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/@nightwatch/ejs/-/ejs-3.2.0.tgz",
+      "integrity": "sha512-NbJzBXGjh7gzG9nCYtbpdHrqQ3CnMt1FUBj8PomVyc1q5+qBFS8z3aLvBGWPt1leHmRK6d4TZn/jsS0XKmVGQQ==",
+      "dev": true
+    },
     "@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -4998,6 +5018,12 @@
       "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
       "dev": true
     },
+    "@testim/chrome-version": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.2.tgz",
+      "integrity": "sha512-1c4ZOETSRpI0iBfIFUqU4KqwBAB2lHUAlBjZz/YqOHqwM9dTTzjV6Km0ZkiEiSCx/tLr1BtESIKyWWMww+RUqw==",
+      "dev": true
+    },
     "@tootallnate/once": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -5319,6 +5345,22 @@
       "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==",
       "dev": true
     },
+    "@types/yauzl": {
+      "version": "2.10.0",
+      "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz",
+      "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "@ungap/promise-all-settled": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
+      "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==",
+      "dev": true
+    },
     "@webassemblyjs/ast": {
       "version": "1.11.1",
       "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
@@ -5664,10 +5706,19 @@
       "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
       "dev": true
     },
+    "ansi-align": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
+      "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==",
+      "dev": true,
+      "requires": {
+        "string-width": "^4.1.0"
+      }
+    },
     "ansi-colors": {
-      "version": "3.2.3",
-      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
-      "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==",
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
       "dev": true
     },
     "ansi-escapes": {
@@ -5953,23 +6004,6 @@
       "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
       "dev": true
     },
-    "ast-types": {
-      "version": "0.13.4",
-      "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
-      "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
-      "dev": true,
-      "requires": {
-        "tslib": "^2.0.1"
-      },
-      "dependencies": {
-        "tslib": {
-          "version": "2.3.1",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
-          "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
-          "dev": true
-        }
-      }
-    },
     "async": {
       "version": "0.2.10",
       "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
@@ -6312,6 +6346,12 @@
       "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz",
       "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="
     },
+    "base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "dev": true
+    },
     "batch": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
@@ -6394,6 +6434,79 @@
       "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==",
       "dev": true
     },
+    "boxen": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz",
+      "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==",
+      "dev": true,
+      "requires": {
+        "ansi-align": "^3.0.0",
+        "camelcase": "^6.2.0",
+        "chalk": "^4.1.0",
+        "cli-boxes": "^2.2.1",
+        "string-width": "^4.2.2",
+        "type-fest": "^0.20.2",
+        "widest-line": "^3.1.0",
+        "wrap-ansi": "^7.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "camelcase": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+          "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+          "dev": true
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
     "brace": {
       "version": "0.11.1",
       "resolved": "https://registry.npmjs.org/brace/-/brace-0.11.1.tgz",
@@ -6452,6 +6565,22 @@
         "node-int64": "^0.4.0"
       }
     },
+    "buffer": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+      "dev": true,
+      "requires": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.1.13"
+      }
+    },
+    "buffer-crc32": {
+      "version": "0.2.13",
+      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+      "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+      "dev": true
+    },
     "buffer-from": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
@@ -6521,21 +6650,12 @@
       "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
     },
     "chai-nightwatch": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/chai-nightwatch/-/chai-nightwatch-0.4.1.tgz",
-      "integrity": "sha512-s2put5cFhG8Hw+6Po3R8QZ0ctsDmcaIh7+l9Fu3RcLCfosfQffT3mcFSq2jmXEQk0pmwo/PuXvYMO87MRlyqxg==",
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/chai-nightwatch/-/chai-nightwatch-0.5.3.tgz",
+      "integrity": "sha512-38ixH/mqpY6IwnZkz6xPqx8aB5/KVR+j6VPugcir3EGOsphnWXrPH/mUt8Jp+ninL6ghY0AaJDQ10hSfCPGy/g==",
       "dev": true,
       "requires": {
-        "assertion-error": "1.0.0",
-        "deep-eql": "0.1.3"
-      },
-      "dependencies": {
-        "assertion-error": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.0.tgz",
-          "integrity": "sha1-x/hUOP3UZrx8oWq5DIFRN5el0js=",
-          "dev": true
-        }
+        "assertion-error": "1.1.0"
       }
     },
     "chalk": {
@@ -6554,6 +6674,12 @@
       "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
       "dev": true
     },
+    "check-error": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+      "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
+      "dev": true
+    },
     "cheerio": {
       "version": "1.0.0-rc.10",
       "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz",
@@ -6700,10 +6826,36 @@
       "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
       "dev": true
     },
+    "chromedriver": {
+      "version": "100.0.0",
+      "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-100.0.0.tgz",
+      "integrity": "sha512-oLfB0IgFEGY9qYpFQO/BNSXbPw7bgfJUN5VX8Okps9W2qNT4IqKh5hDwKWtpUIQNI6K3ToWe2/J5NdpurTY02g==",
+      "dev": true,
+      "requires": {
+        "@testim/chrome-version": "^1.1.2",
+        "axios": "^0.24.0",
+        "del": "^6.0.0",
+        "extract-zip": "^2.0.1",
+        "https-proxy-agent": "^5.0.0",
+        "proxy-from-env": "^1.1.0",
+        "tcp-port-used": "^1.0.1"
+      },
+      "dependencies": {
+        "axios": {
+          "version": "0.24.0",
+          "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
+          "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
+          "dev": true,
+          "requires": {
+            "follow-redirects": "^1.14.4"
+          }
+        }
+      }
+    },
     "ci-info": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
-      "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz",
+      "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==",
       "dev": true
     },
     "cjs-module-lexer": {
@@ -6723,6 +6875,12 @@
       "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
       "dev": true
     },
+    "cli-boxes": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz",
+      "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==",
+      "dev": true
+    },
     "cli-cursor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -6749,56 +6907,22 @@
       }
     },
     "cliui": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
-      "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
       "dev": true,
       "requires": {
-        "string-width": "^3.1.0",
-        "strip-ansi": "^5.2.0",
-        "wrap-ansi": "^5.1.0"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
-          "dev": true
-        },
-        "emoji-regex": {
-          "version": "7.0.3",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-          "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-          "dev": true
-        },
-        "string-width": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^7.0.1",
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^5.1.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^4.1.0"
-          }
-        }
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^7.0.0"
       }
     },
+    "clone": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+      "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
+      "dev": true
+    },
     "clone-deep": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
@@ -7097,12 +7221,6 @@
         "assert-plus": "^1.0.0"
       }
     },
-    "data-uri-to-buffer": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
-      "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==",
-      "dev": true
-    },
     "data-urls": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
@@ -7157,9 +7275,9 @@
       }
     },
     "decamelize": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+      "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
       "dev": true
     },
     "decimal.js": {
@@ -7175,12 +7293,12 @@
       "dev": true
     },
     "deep-eql": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz",
-      "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.0.1.tgz",
+      "integrity": "sha512-D/Oxqobjr+kxaHsgiQBZq9b6iAWdEj5W/JdJm8deNduAPc9CwXQ3BJJCuEqlrPXcy45iOMkGPZ0T81Dnz7UDCA==",
       "dev": true,
       "requires": {
-        "type-detect": "0.1.1"
+        "type-detect": "^4.0.0"
       }
     },
     "deep-equal": {
@@ -7225,14 +7343,6 @@
       "dev": true,
       "requires": {
         "clone": "^1.0.2"
-      },
-      "dependencies": {
-        "clone": {
-          "version": "1.0.4",
-          "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
-          "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
-          "dev": true
-        }
       }
     },
     "define-lazy-prop": {
@@ -7250,18 +7360,6 @@
         "object-keys": "^1.0.12"
       }
     },
-    "degenerator": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-3.0.1.tgz",
-      "integrity": "sha512-LFsIFEeLPlKvAKXu7j3ssIG6RT0TbI7/GhsqrI0DnHASEQjXQ0LUSYcjJteGgRGmZbl1TnMSxpNQIAiJ7Du5TQ==",
-      "dev": true,
-      "requires": {
-        "ast-types": "^0.13.2",
-        "escodegen": "^1.8.1",
-        "esprima": "^4.0.0",
-        "vm2": "^3.9.3"
-      }
-    },
     "del": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz",
@@ -7339,6 +7437,12 @@
       "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
       "dev": true
     },
+    "diff": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
+      "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==",
+      "dev": true
+    },
     "diff-match-patch": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
@@ -7500,9 +7604,9 @@
       }
     },
     "dotenv": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz",
-      "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==",
+      "version": "10.0.0",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
+      "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
       "dev": true
     },
     "ecc-jsbn": {
@@ -7519,15 +7623,6 @@
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
       "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
     },
-    "ejs": {
-      "version": "3.1.6",
-      "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz",
-      "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==",
-      "dev": true,
-      "requires": {
-        "jake": "^10.6.1"
-      }
-    },
     "electron-to-chromium": {
       "version": "1.4.46",
       "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.46.tgz",
@@ -7556,6 +7651,15 @@
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
       "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
     },
+    "end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "dev": true,
+      "requires": {
+        "once": "^1.4.0"
+      }
+    },
     "entities": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
@@ -7727,19 +7831,6 @@
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
       "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
     },
-    "escodegen": {
-      "version": "1.14.3",
-      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
-      "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
-      "dev": true,
-      "requires": {
-        "esprima": "^4.0.1",
-        "estraverse": "^4.2.0",
-        "esutils": "^2.0.2",
-        "optionator": "^0.8.1",
-        "source-map": "~0.6.1"
-      }
-    },
     "eslint": {
       "version": "8.9.0",
       "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.9.0.tgz",
@@ -8630,6 +8721,44 @@
       "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
       "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
     },
+    "extract-zip": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+      "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+      "dev": true,
+      "requires": {
+        "@types/yauzl": "^2.9.1",
+        "debug": "^4.1.1",
+        "get-stream": "^5.1.0",
+        "yauzl": "^2.10.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.4",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+          "dev": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        },
+        "get-stream": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+          "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+          "dev": true,
+          "requires": {
+            "pump": "^3.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+          "dev": true
+        }
+      }
+    },
     "extsprintf": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
@@ -8697,6 +8826,15 @@
         "bser": "2.1.1"
       }
     },
+    "fd-slicer": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+      "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+      "dev": true,
+      "requires": {
+        "pend": "~1.2.0"
+      }
+    },
     "fetch-mock": {
       "version": "9.11.0",
       "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-9.11.0.tgz",
@@ -8765,15 +8903,6 @@
       "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=",
       "dev": true
     },
-    "filelist": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz",
-      "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==",
-      "dev": true,
-      "requires": {
-        "minimatch": "^3.0.4"
-      }
-    },
     "fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -8861,21 +8990,10 @@
       "dev": true
     },
     "flat": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz",
-      "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==",
-      "dev": true,
-      "requires": {
-        "is-buffer": "~2.0.3"
-      },
-      "dependencies": {
-        "is-buffer": {
-          "version": "2.0.5",
-          "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
-          "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
-          "dev": true
-        }
-      }
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+      "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+      "dev": true
     },
     "flat-cache": {
       "version": "3.0.4",
@@ -8993,42 +9111,6 @@
       "dev": true,
       "optional": true
     },
-    "ftp": {
-      "version": "0.3.10",
-      "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz",
-      "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=",
-      "dev": true,
-      "requires": {
-        "readable-stream": "1.1.x",
-        "xregexp": "2.0.0"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "0.0.1",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
-          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "1.1.14",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
-          "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.1",
-            "isarray": "0.0.1",
-            "string_decoder": "~0.10.x"
-          }
-        },
-        "string_decoder": {
-          "version": "0.10.31",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
-          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
-          "dev": true
-        }
-      }
-    },
     "function-bind": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -9070,6 +9152,12 @@
       "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
       "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
     },
+    "get-func-name": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+      "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
+      "dev": true
+    },
     "get-intrinsic": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
@@ -9103,63 +9191,6 @@
         "get-intrinsic": "^1.1.1"
       }
     },
-    "get-uri": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz",
-      "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==",
-      "dev": true,
-      "requires": {
-        "@tootallnate/once": "1",
-        "data-uri-to-buffer": "3",
-        "debug": "4",
-        "file-uri-to-path": "2",
-        "fs-extra": "^8.1.0",
-        "ftp": "^0.3.10"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.3",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
-          "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "file-uri-to-path": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz",
-          "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==",
-          "dev": true
-        },
-        "fs-extra": {
-          "version": "8.1.0",
-          "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
-          "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.2.0",
-            "jsonfile": "^4.0.0",
-            "universalify": "^0.1.0"
-          }
-        },
-        "jsonfile": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
-          "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.6"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
-      }
-    },
     "getobject": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.1.tgz",
@@ -9962,6 +9993,12 @@
       "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
       "dev": true
     },
+    "ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "dev": true
+    },
     "ignore": {
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
@@ -9975,6 +10012,12 @@
       "dev": true,
       "optional": true
     },
+    "immediate": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+      "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=",
+      "dev": true
+    },
     "import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -10049,6 +10092,12 @@
       "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",
       "dev": true
     },
+    "ip-regex": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz",
+      "integrity": "sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==",
+      "dev": true
+    },
     "ipaddr.js": {
       "version": "1.9.1",
       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@@ -10193,6 +10242,12 @@
       "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
       "dev": true
     },
+    "is-plain-obj": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+      "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+      "dev": true
+    },
     "is-plain-object": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@@ -10279,6 +10334,18 @@
         "unc-path-regex": "^0.1.2"
       }
     },
+    "is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true
+    },
+    "is-url": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
+      "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==",
+      "dev": true
+    },
     "is-weakref": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
@@ -10309,6 +10376,17 @@
         "is-docker": "^2.0.0"
       }
     },
+    "is2": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/is2/-/is2-2.0.7.tgz",
+      "integrity": "sha512-4vBQoURAXC6hnLFxD4VW7uc04XiwTTl/8ydYJxKvPwkWQrSjInkuM5VZVg6BGr1/natq69zDuvO9lGpLClJqvA==",
+      "dev": true,
+      "requires": {
+        "deep-is": "^0.1.3",
+        "ip-regex": "^4.1.0",
+        "is-url": "^1.2.4"
+      }
+    },
     "isarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@@ -10458,26 +10536,6 @@
         "istanbul-lib-report": "^3.0.0"
       }
     },
-    "jake": {
-      "version": "10.8.2",
-      "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz",
-      "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==",
-      "dev": true,
-      "requires": {
-        "async": "0.9.x",
-        "chalk": "^2.4.2",
-        "filelist": "^1.0.1",
-        "minimatch": "^3.0.4"
-      },
-      "dependencies": {
-        "async": {
-          "version": "0.9.2",
-          "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
-          "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=",
-          "dev": true
-        }
-      }
-    },
     "jest": {
       "version": "27.5.1",
       "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
@@ -15153,6 +15211,35 @@
         "object.assign": "^4.1.2"
       }
     },
+    "jszip": {
+      "version": "3.9.1",
+      "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.9.1.tgz",
+      "integrity": "sha512-H9A60xPqJ1CuC4Ka6qxzXZeU8aNmgOeP5IFqwJbQQwtu2EUYxota3LdsiZWplF7Wgd9tkAd0mdu36nceSaPuYw==",
+      "dev": true,
+      "requires": {
+        "lie": "~3.3.0",
+        "pako": "~1.0.2",
+        "readable-stream": "~2.3.6",
+        "set-immediate-shim": "~1.0.1"
+      },
+      "dependencies": {
+        "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==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        }
+      }
+    },
     "just-extend": {
       "version": "4.2.1",
       "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz",
@@ -15224,6 +15311,15 @@
         "type-check": "~0.3.2"
       }
     },
+    "lie": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+      "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+      "dev": true,
+      "requires": {
+        "immediate": "~3.0.5"
+      }
+    },
     "liftup": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz",
@@ -15495,12 +15591,64 @@
       "dev": true
     },
     "log-symbols": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
-      "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
       "dev": true,
       "requires": {
-        "chalk": "^2.0.1"
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
       }
     },
     "lolex": {
@@ -15517,6 +15665,15 @@
         "js-tokens": "^3.0.0 || ^4.0.0"
       }
     },
+    "loupe": {
+      "version": "2.3.4",
+      "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz",
+      "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==",
+      "dev": true,
+      "requires": {
+        "get-func-name": "^2.0.0"
+      }
+    },
     "lower-case": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
@@ -15755,67 +15912,96 @@
       "dev": true
     },
     "mocha": {
-      "version": "6.2.3",
-      "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz",
-      "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==",
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz",
+      "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==",
       "dev": true,
       "requires": {
-        "ansi-colors": "3.2.3",
+        "@ungap/promise-all-settled": "1.1.2",
+        "ansi-colors": "4.1.1",
         "browser-stdout": "1.3.1",
-        "debug": "3.2.6",
-        "diff": "3.5.0",
-        "escape-string-regexp": "1.0.5",
-        "find-up": "3.0.0",
-        "glob": "7.1.3",
+        "chokidar": "3.5.3",
+        "debug": "4.3.3",
+        "diff": "5.0.0",
+        "escape-string-regexp": "4.0.0",
+        "find-up": "5.0.0",
+        "glob": "7.2.0",
         "growl": "1.10.5",
         "he": "1.2.0",
-        "js-yaml": "3.13.1",
-        "log-symbols": "2.2.0",
-        "minimatch": "3.0.4",
-        "mkdirp": "0.5.4",
-        "ms": "2.1.1",
-        "node-environment-flags": "1.0.5",
-        "object.assign": "4.1.0",
-        "strip-json-comments": "2.0.1",
-        "supports-color": "6.0.0",
-        "which": "1.3.1",
-        "wide-align": "1.1.3",
-        "yargs": "13.3.2",
-        "yargs-parser": "13.1.2",
-        "yargs-unparser": "1.6.0"
+        "js-yaml": "4.1.0",
+        "log-symbols": "4.1.0",
+        "minimatch": "4.2.1",
+        "ms": "2.1.3",
+        "nanoid": "3.3.1",
+        "serialize-javascript": "6.0.0",
+        "strip-json-comments": "3.1.1",
+        "supports-color": "8.1.1",
+        "which": "2.0.2",
+        "workerpool": "6.2.0",
+        "yargs": "16.2.0",
+        "yargs-parser": "20.2.4",
+        "yargs-unparser": "2.0.0"
       },
       "dependencies": {
-        "ansi-regex": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+        "argparse": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+          "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
           "dev": true
         },
+        "chokidar": {
+          "version": "3.5.3",
+          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+          "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+          "dev": true,
+          "requires": {
+            "anymatch": "~3.1.2",
+            "braces": "~3.0.2",
+            "fsevents": "~2.3.2",
+            "glob-parent": "~5.1.2",
+            "is-binary-path": "~2.1.0",
+            "is-glob": "~4.0.1",
+            "normalize-path": "~3.0.0",
+            "readdirp": "~3.6.0"
+          }
+        },
         "debug": {
-          "version": "3.2.6",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
-          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+          "version": "4.3.3",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
+          "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
           "dev": true,
           "requires": {
-            "ms": "^2.1.1"
+            "ms": "2.1.2"
+          },
+          "dependencies": {
+            "ms": {
+              "version": "2.1.2",
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+              "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+              "dev": true
+            }
           }
         },
-        "diff": {
-          "version": "3.5.0",
-          "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
-          "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+        "escape-string-regexp": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+          "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
           "dev": true
         },
-        "emoji-regex": {
-          "version": "7.0.3",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-          "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
-          "dev": true
+        "find-up": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+          "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^6.0.0",
+            "path-exists": "^4.0.0"
+          }
         },
         "glob": {
-          "version": "7.1.3",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
-          "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+          "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
           "dev": true,
           "requires": {
             "fs.realpath": "^1.0.0",
@@ -15824,102 +16010,113 @@
             "minimatch": "^3.0.4",
             "once": "^1.3.0",
             "path-is-absolute": "^1.0.0"
+          },
+          "dependencies": {
+            "minimatch": {
+              "version": "3.1.2",
+              "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+              "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+              "dev": true,
+              "requires": {
+                "brace-expansion": "^1.1.7"
+              }
+            }
           }
         },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
           "dev": true
         },
         "js-yaml": {
-          "version": "3.13.1",
-          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
-          "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+          "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
           "dev": true,
           "requires": {
-            "argparse": "^1.0.7",
-            "esprima": "^4.0.0"
+            "argparse": "^2.0.1"
           }
         },
-        "mkdirp": {
-          "version": "0.5.4",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz",
-          "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==",
+        "locate-path": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+          "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
           "dev": true,
           "requires": {
-            "minimist": "^1.2.5"
+            "p-locate": "^5.0.0"
           }
         },
-        "ms": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
-          "dev": true
-        },
-        "object.assign": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
-          "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
+        "minimatch": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz",
+          "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==",
           "dev": true,
           "requires": {
-            "define-properties": "^1.1.2",
-            "function-bind": "^1.1.1",
-            "has-symbols": "^1.0.0",
-            "object-keys": "^1.0.11"
+            "brace-expansion": "^1.1.7"
           }
         },
-        "string-width": {
+        "ms": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+          "dev": true
+        },
+        "p-limit": {
           "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+          "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
           "dev": true,
           "requires": {
-            "emoji-regex": "^7.0.1",
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^5.1.0"
+            "yocto-queue": "^0.1.0"
           }
         },
-        "strip-ansi": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+        "p-locate": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+          "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
           "dev": true,
           "requires": {
-            "ansi-regex": "^4.1.0"
+            "p-limit": "^3.0.2"
           }
         },
-        "strip-json-comments": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
-          "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
-          "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==",
+        "path-exists": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "8.1.1",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+          "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
           "dev": true,
           "requires": {
-            "has-flag": "^3.0.0"
+            "has-flag": "^4.0.0"
+          }
+        },
+        "which": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+          "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+          "dev": true,
+          "requires": {
+            "isexe": "^2.0.0"
           }
         },
         "yargs": {
-          "version": "13.3.2",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
-          "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
+          "version": "16.2.0",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+          "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
           "dev": true,
           "requires": {
-            "cliui": "^5.0.0",
-            "find-up": "^3.0.0",
-            "get-caller-file": "^2.0.1",
+            "cliui": "^7.0.2",
+            "escalade": "^3.1.1",
+            "get-caller-file": "^2.0.5",
             "require-directory": "^2.1.1",
-            "require-main-filename": "^2.0.0",
-            "set-blocking": "^2.0.0",
-            "string-width": "^3.0.0",
-            "which-module": "^2.0.0",
-            "y18n": "^4.0.0",
-            "yargs-parser": "^13.1.2"
+            "string-width": "^4.2.0",
+            "y18n": "^5.0.5",
+            "yargs-parser": "^20.2.2"
           }
         }
       }
@@ -15974,12 +16171,6 @@
       "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
       "dev": true
     },
-    "mute-stream": {
-      "version": "0.0.8",
-      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
-      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
-      "dev": true
-    },
     "nano": {
       "version": "9.0.5",
       "resolved": "https://registry.npmjs.org/nano/-/nano-9.0.5.tgz",
@@ -16054,52 +16245,73 @@
       "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
       "dev": true
     },
-    "netmask": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
-      "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
-      "dev": true
-    },
     "nightwatch": {
-      "version": "1.7.13",
-      "resolved": "https://registry.npmjs.org/nightwatch/-/nightwatch-1.7.13.tgz",
-      "integrity": "sha512-bX7mI5JmRdGvVxWYIyUgpF1vuBc/Tlx3nFQc511CW90gbyvQ3PY18wqT5wul45mR2BjDCnCYkxHJcXRKnxC91A==",
-      "dev": true,
-      "requires": {
-        "ansi-regex": "^6.0.1",
-        "assertion-error": "^1.1.0",
-        "chai-nightwatch": "^0.4.0",
-        "ci-info": "^2.0.0",
-        "didyoumean": "^1.2.1",
-        "dotenv": "7.0.0",
-        "ejs": "^3.1.6",
-        "envinfo": "^7.5.1",
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/nightwatch/-/nightwatch-2.1.3.tgz",
+      "integrity": "sha512-NMNr4/jPsAtfd/u+RgKTzYyhS9TUuEmP6LMxLcH/KdQlkQmPIixVStRijv0bpvK4zASsqrO2+/em2LNRNMT6sw==",
+      "dev": true,
+      "requires": {
+        "@nightwatch/chai": "5.0.2",
+        "@nightwatch/ejs": "3.2.0",
+        "assertion-error": "1.1.0",
+        "boxen": "5.1.2",
+        "chai-nightwatch": "0.5.3",
+        "ci-info": "3.3.0",
+        "didyoumean": "1.2.2",
+        "dotenv": "10.0.0",
+        "envinfo": "7.8.1",
+        "glob": "7.2.0",
         "lodash.clone": "3.0.3",
-        "lodash.defaultsdeep": "^4.6.1",
-        "lodash.merge": "^4.6.2",
+        "lodash.defaultsdeep": "4.6.1",
+        "lodash.merge": "4.6.2",
         "minimatch": "3.0.4",
-        "minimist": "^1.2.5",
+        "minimist": "1.2.6",
         "mkpath": "1.0.0",
-        "mocha": "6.2.3",
-        "ora": "^4.0.3",
-        "proxy-agent": "^5.0.0",
-        "request": "^2.88.2",
-        "request-promise": "^4.2.5",
-        "semver": "^6.3.0",
-        "strip-ansi": "^6.0.0"
+        "mocha": "9.2.2",
+        "ora": "5.4.1",
+        "selenium-webdriver": "4.1.1",
+        "semver": "7.3.5",
+        "stacktrace-parser": "0.1.10",
+        "strip-ansi": "6.0.1"
       },
       "dependencies": {
-        "ansi-regex": {
-          "version": "6.0.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
-          "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+        "glob": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+          "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "minimist": {
+          "version": "1.2.6",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+          "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
           "dev": true
         },
         "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
+          "version": "7.3.5",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+          "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+          "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^5.0.1"
+          }
         }
       }
     },
@@ -16160,16 +16372,6 @@
         }
       }
     },
-    "node-environment-flags": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz",
-      "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==",
-      "dev": true,
-      "requires": {
-        "object.getownpropertydescriptors": "^2.0.3",
-        "semver": "^5.7.0"
-      }
-    },
     "node-fetch": {
       "version": "2.6.7",
       "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
@@ -16339,17 +16541,6 @@
         "has": "^1.0.3"
       }
     },
-    "object.getownpropertydescriptors": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz",
-      "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.2",
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.18.0-next.2"
-      }
-    },
     "object.hasown": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz",
@@ -16515,17 +16706,18 @@
       }
     },
     "ora": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/ora/-/ora-4.1.1.tgz",
-      "integrity": "sha512-sjYP8QyVWBpBZWD6Vr1M/KwknSw6kJOz41tvGMlwWeClHBtYKTbHMki1PsLZnxKpXMPbTKv9b3pjQu3REib96A==",
+      "version": "5.4.1",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
+      "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
       "dev": true,
       "requires": {
-        "chalk": "^3.0.0",
+        "bl": "^4.1.0",
+        "chalk": "^4.1.0",
         "cli-cursor": "^3.1.0",
-        "cli-spinners": "^2.2.0",
+        "cli-spinners": "^2.5.0",
         "is-interactive": "^1.0.0",
-        "log-symbols": "^3.0.0",
-        "mute-stream": "0.0.8",
+        "is-unicode-supported": "^0.1.0",
+        "log-symbols": "^4.1.0",
         "strip-ansi": "^6.0.0",
         "wcwidth": "^1.0.1"
       },
@@ -16539,10 +16731,21 @@
             "color-convert": "^2.0.1"
           }
         },
+        "bl": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+          "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+          "dev": true,
+          "requires": {
+            "buffer": "^5.5.0",
+            "inherits": "^2.0.4",
+            "readable-stream": "^3.4.0"
+          }
+        },
         "chalk": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
@@ -16570,66 +16773,11 @@
           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
           "dev": true
         },
-        "log-symbols": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
-          "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
-          "dev": true,
-          "requires": {
-            "chalk": "^2.4.2"
-          },
-          "dependencies": {
-            "ansi-styles": {
-              "version": "3.2.1",
-              "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-              "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-              "dev": true,
-              "requires": {
-                "color-convert": "^1.9.0"
-              }
-            },
-            "chalk": {
-              "version": "2.4.2",
-              "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-              "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-              "dev": true,
-              "requires": {
-                "ansi-styles": "^3.2.1",
-                "escape-string-regexp": "^1.0.5",
-                "supports-color": "^5.3.0"
-              }
-            },
-            "color-convert": {
-              "version": "1.9.3",
-              "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-              "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-              "dev": true,
-              "requires": {
-                "color-name": "1.1.3"
-              }
-            },
-            "color-name": {
-              "version": "1.1.3",
-              "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-              "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-              "dev": true
-            },
-            "has-flag": {
-              "version": "3.0.0",
-              "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-              "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-              "dev": true
-            },
-            "supports-color": {
-              "version": "5.5.0",
-              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-              "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-              "dev": true,
-              "requires": {
-                "has-flag": "^3.0.0"
-              }
-            }
-          }
+        "inherits": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+          "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+          "dev": true
         },
         "supports-color": {
           "version": "7.2.0",
@@ -16707,50 +16855,11 @@
       "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
       "dev": true
     },
-    "pac-proxy-agent": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz",
-      "integrity": "sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ==",
-      "dev": true,
-      "requires": {
-        "@tootallnate/once": "1",
-        "agent-base": "6",
-        "debug": "4",
-        "get-uri": "3",
-        "http-proxy-agent": "^4.0.1",
-        "https-proxy-agent": "5",
-        "pac-resolver": "^5.0.0",
-        "raw-body": "^2.2.0",
-        "socks-proxy-agent": "5"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.3",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
-          "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
-      }
-    },
-    "pac-resolver": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-5.0.0.tgz",
-      "integrity": "sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA==",
-      "dev": true,
-      "requires": {
-        "degenerator": "^3.0.1",
-        "ip": "^1.1.5",
-        "netmask": "^2.0.1"
-      }
+    "pako": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+      "dev": true
     },
     "param-case": {
       "version": "3.0.4",
@@ -16884,6 +16993,18 @@
       "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
       "dev": true
     },
+    "pathval": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
+      "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
+      "dev": true
+    },
+    "pend": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+      "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+      "dev": true
+    },
     "performance-now": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@@ -17133,54 +17254,6 @@
         "ipaddr.js": "1.9.1"
       }
     },
-    "proxy-agent": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-5.0.0.tgz",
-      "integrity": "sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g==",
-      "dev": true,
-      "requires": {
-        "agent-base": "^6.0.0",
-        "debug": "4",
-        "http-proxy-agent": "^4.0.0",
-        "https-proxy-agent": "^5.0.0",
-        "lru-cache": "^5.1.1",
-        "pac-proxy-agent": "^5.0.0",
-        "proxy-from-env": "^1.0.0",
-        "socks-proxy-agent": "^5.0.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.3",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
-          "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "lru-cache": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-          "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
-          "dev": true,
-          "requires": {
-            "yallist": "^3.0.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
-        "yallist": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
-          "dev": true
-        }
-      }
-    },
     "proxy-from-env": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -17199,6 +17272,16 @@
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
       "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
     },
+    "pump": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+      "dev": true,
+      "requires": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
     "punycode": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
@@ -17711,27 +17794,6 @@
         }
       }
     },
-    "request-promise": {
-      "version": "4.2.6",
-      "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz",
-      "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==",
-      "dev": true,
-      "requires": {
-        "bluebird": "^3.5.0",
-        "request-promise-core": "1.1.4",
-        "stealthy-require": "^1.1.1",
-        "tough-cookie": "^2.3.3"
-      }
-    },
-    "request-promise-core": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz",
-      "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==",
-      "dev": true,
-      "requires": {
-        "lodash": "^4.17.19"
-      }
-    },
     "require-directory": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -17743,12 +17805,6 @@
       "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
       "dev": true
     },
-    "require-main-filename": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
-      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
-      "dev": true
-    },
     "requires-port": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -17905,6 +17961,17 @@
       "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=",
       "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==",
+      "dev": true,
+      "requires": {
+        "jszip": "^3.6.0",
+        "tmp": "^0.2.1",
+        "ws": ">=7.4.6"
+      }
+    },
     "selfsigned": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.0.tgz",
@@ -18049,10 +18116,10 @@
         }
       }
     },
-    "set-blocking": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+    "set-immediate-shim": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
+      "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
       "dev": true
     },
     "setprototypeof": {
@@ -18141,12 +18208,6 @@
       "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
       "dev": true
     },
-    "smart-buffer": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
-      "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
-      "dev": true
-    },
     "sockjs": {
       "version": "0.3.24",
       "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
@@ -18158,44 +18219,6 @@
         "websocket-driver": "^0.7.4"
       }
     },
-    "socks": {
-      "version": "2.6.1",
-      "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz",
-      "integrity": "sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA==",
-      "dev": true,
-      "requires": {
-        "ip": "^1.1.5",
-        "smart-buffer": "^4.1.0"
-      }
-    },
-    "socks-proxy-agent": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz",
-      "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==",
-      "dev": true,
-      "requires": {
-        "agent-base": "^6.0.2",
-        "debug": "4",
-        "socks": "^2.3.3"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.3.3",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
-          "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
-          "dev": true,
-          "requires": {
-            "ms": "2.1.2"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
-      }
-    },
     "source-map": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -18301,17 +18324,28 @@
         "tweetnacl": "~0.14.0"
       }
     },
+    "stacktrace-parser": {
+      "version": "0.1.10",
+      "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz",
+      "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==",
+      "dev": true,
+      "requires": {
+        "type-fest": "^0.7.1"
+      },
+      "dependencies": {
+        "type-fest": {
+          "version": "0.7.1",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz",
+          "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==",
+          "dev": true
+        }
+      }
+    },
     "statuses": {
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
       "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
     },
-    "stealthy-require": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
-      "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
-      "dev": true
-    },
     "string-length": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
@@ -18539,6 +18573,33 @@
       "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
       "dev": true
     },
+    "tcp-port-used": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.2.tgz",
+      "integrity": "sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA==",
+      "dev": true,
+      "requires": {
+        "debug": "4.3.1",
+        "is2": "^2.0.6"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.1",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+          "dev": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        },
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+          "dev": true
+        }
+      }
+    },
     "terminal-link": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz",
@@ -18665,6 +18726,26 @@
       "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
       "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
     },
+    "tmp": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+      "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+      "dev": true,
+      "requires": {
+        "rimraf": "^3.0.0"
+      },
+      "dependencies": {
+        "rimraf": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+          "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+          "dev": true,
+          "requires": {
+            "glob": "^7.1.3"
+          }
+        }
+      }
+    },
     "tmpl": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
@@ -18738,9 +18819,9 @@
       }
     },
     "type-detect": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz",
-      "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=",
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+      "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
       "dev": true
     },
     "type-fest": {
@@ -18946,30 +19027,6 @@
         "extsprintf": "^1.2.0"
       }
     },
-    "vm2": {
-      "version": "3.9.8",
-      "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.8.tgz",
-      "integrity": "sha512-/1PYg/BwdKzMPo8maOZ0heT7DLI0DAFTm7YQaz/Lim9oIaFZsJs3EdtalvXuBfZwczNwsYhju75NW4d6E+4q+w==",
-      "dev": true,
-      "requires": {
-        "acorn": "^8.7.0",
-        "acorn-walk": "^8.2.0"
-      },
-      "dependencies": {
-        "acorn": {
-          "version": "8.7.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz",
-          "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==",
-          "dev": true
-        },
-        "acorn-walk": {
-          "version": "8.2.0",
-          "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
-          "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
-          "dev": true
-        }
-      }
-    },
     "w3c-hr-time": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
@@ -19573,52 +19630,13 @@
         "is-symbol": "^1.0.3"
       }
     },
-    "which-module": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
-      "dev": true
-    },
-    "wide-align": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
-      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
+    "widest-line": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
+      "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==",
       "dev": true,
       "requires": {
-        "string-width": "^1.0.2 || 2"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-          "dev": true
-        },
-        "string-width": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
-          "dev": true,
-          "requires": {
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^4.0.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^3.0.0"
-          }
-        }
+        "string-width": "^4.0.0"
       }
     },
     "wildcard": {
@@ -19633,54 +19651,46 @@
       "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
       "dev": true
     },
+    "workerpool": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz",
+      "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==",
+      "dev": true
+    },
     "wrap-ansi": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
-      "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
       "dev": true,
       "requires": {
-        "ansi-styles": "^3.2.0",
-        "string-width": "^3.0.0",
-        "strip-ansi": "^5.0.0"
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
       },
       "dependencies": {
-        "ansi-regex": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
-          "dev": true
-        },
-        "emoji-regex": {
-          "version": "7.0.3",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-          "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-          "dev": true
-        },
-        "string-width": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
           "dev": true,
           "requires": {
-            "emoji-regex": "^7.0.1",
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^5.1.0"
+            "color-convert": "^2.0.1"
           }
         },
-        "strip-ansi": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
           "dev": true,
           "requires": {
-            "ansi-regex": "^4.1.0"
+            "color-name": "~1.1.4"
           }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
         }
       }
     },
@@ -19720,16 +19730,10 @@
       "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
       "dev": true
     },
-    "xregexp": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz",
-      "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=",
-      "dev": true
-    },
     "y18n": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
-      "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
       "dev": true
     },
     "yallist": {
@@ -19826,83 +19830,46 @@
       }
     },
     "yargs-parser": {
-      "version": "13.1.2",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
-      "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
-      "dev": true,
-      "requires": {
-        "camelcase": "^5.0.0",
-        "decamelize": "^1.2.0"
-      }
+      "version": "20.2.4",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz",
+      "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==",
+      "dev": true
     },
     "yargs-unparser": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz",
-      "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz",
+      "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==",
       "dev": true,
       "requires": {
-        "flat": "^4.1.0",
-        "lodash": "^4.17.15",
-        "yargs": "^13.3.0"
+        "camelcase": "^6.0.0",
+        "decamelize": "^4.0.0",
+        "flat": "^5.0.2",
+        "is-plain-obj": "^2.1.0"
       },
       "dependencies": {
-        "ansi-regex": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
-          "dev": true
-        },
-        "emoji-regex": {
-          "version": "7.0.3",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-          "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+        "camelcase": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+          "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
           "dev": true
-        },
-        "string-width": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^7.0.1",
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^5.1.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^4.1.0"
-          }
-        },
-        "yargs": {
-          "version": "13.3.2",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
-          "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
-          "dev": true,
-          "requires": {
-            "cliui": "^5.0.0",
-            "find-up": "^3.0.0",
-            "get-caller-file": "^2.0.1",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^2.0.0",
-            "set-blocking": "^2.0.0",
-            "string-width": "^3.0.0",
-            "which-module": "^2.0.0",
-            "y18n": "^4.0.0",
-            "yargs-parser": "^13.1.2"
-          }
         }
       }
+    },
+    "yauzl": {
+      "version": "2.10.0",
+      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+      "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+      "dev": true,
+      "requires": {
+        "buffer-crc32": "~0.2.3",
+        "fd-slicer": "~1.1.0"
+      }
+    },
+    "yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true
     }
   }
 }
diff --git a/package.json b/package.json
index 98d094e1..ee658c84 100644
--- a/package.json
+++ b/package.json
@@ -24,6 +24,7 @@
     "babel-loader": "^8.2.3",
     "babel-plugin-array-includes": "^2.0.3",
     "bootstrap": "^3.4.1",
+    "chromedriver": "^100.0.0",
     "css-loader": "^6.7.1",
     "enzyme": "^3.11.0",
     "enzyme-adapter-react-16": "^1.15.6",
@@ -46,7 +47,7 @@
     "less-loader": "^10.2.0",
     "mini-css-extract-plugin": "^2.6.0",
     "mock-local-storage": "^1.1.20",
-    "nightwatch": "^1.7.13",
+    "nightwatch": "^2.1.3",
     "node-fetch": "^2.6.7",
     "redux-mock-store": "^1.5.4",
     "sinon": "^7.5.0",
@@ -119,14 +120,11 @@
     "preversion": "node version-check.js && grunt release",
     "test-before-publish": "npm run preversion && npm install . -g",
     "create:animaldb": "node ./bin/create-animal-db",
-    "docker:couchdb-up": "docker-compose -f ./docker/dc.selenium.yml up -d couchdb",
-    "docker:selenium-up": "docker-compose -f ./docker/dc.selenium.yml up -d selenium",
-    "docker:selenium-debug-up": "docker-compose -f ./docker/dc.selenium-debug.yml up -d selenium",
+    "docker:couchdb-up": "docker-compose -f ./docker/couchdb.yml up -d couchdb",
     "docker:reset": "npm run docker:down && npm run docker:up",
     "docker:logs": "docker logs couchdb",
-    "docker:up": "docker-compose -f ./docker/dc.selenium.yml up -d",
-    "docker:debug-up": "docker-compose -f ./docker/dc.selenium-debug.yml up -d",
-    "docker:down": "docker-compose -f ./docker/dc.selenium.yml down",
+    "docker:up": "docker-compose -f ./docker/couchdb.yml up -d",
+    "docker:down": "docker-compose -f ./docker/couchdb.yml down",
     "remove-test-dbs": "node ./bin/remove-test-dbs.js"
   },
   "repository": {
diff --git a/readme.md b/readme.md
index 32688d10..b7b13c46 100644
--- a/readme.md
+++ b/readme.md
@@ -1,4 +1,4 @@
-[![Build Status](https://travis-ci.org/apache/couchdb-fauxton.svg?branch=main)](https://travis-ci.org/apache/couchdb-fauxton)
+![Build Status](https://github.com/github/docs/actions/workflows/main.yml/badge.svg?branch=main)
 
 # Fauxton
 
diff --git a/settings.json.default.json b/settings.json.default.json
index 02979f9d..28ee2406 100644
--- a/settings.json.default.json
+++ b/settings.json.default.json
@@ -67,7 +67,7 @@
 
     "couch_config": {
       "fauxton": {
-        "db": "http://localhost:5984/fauxton",
+        "db": "http://127.0.0.1:5984/fauxton",
         "app": "./couchapp.js",
         "options": {
           "okay_if_missing": true
@@ -80,7 +80,7 @@
       "password": "testerpass",
       "fauxton_port": "8000",
       "db_protocol": "http",
-      "db_host": "localhost",
+      "db_host": "127.0.0.1",
       "db_port": "5984",
       "custom_commands_path": ["test/nightwatch_tests/custom-commands", "test/nightwatch_tests/custom-commands/auth"],
       "globals_path": "./helpers/helpers.js",
diff --git a/tasks/fauxton.js b/tasks/fauxton.js
index 897f3388..1a6cd0be 100644
--- a/tasks/fauxton.js
+++ b/tasks/fauxton.js
@@ -12,8 +12,7 @@
 
 module.exports = function (grunt) {
   var _ = grunt.util._,
-      fs = require('fs'),
-      os = require('os');
+      fs = require('fs');
 
   grunt.registerMultiTask('get_deps', 'Fetch external dependencies', function () {
 
@@ -121,12 +120,8 @@ module.exports = function (grunt) {
     if (fauxton_ip) {
       return fauxton_ip;
     }
-    //making some assumptions here
-    const interfaces = os.networkInterfaces();
-    const eth0 = interfaces[Object.keys(interfaces)[2]];
-    return eth0.find(function (item) {
-      return item.family === 'IPv4';
-    }).address;
+
+    return "127.0.0.1";
   }
 
   function _validateNightwatchSettings (data) {
diff --git a/test/nightwatch_tests/nightwatch.json.underscore b/test/nightwatch_tests/nightwatch.json.underscore
index 8a9bb305..5dae8d51 100644
--- a/test/nightwatch_tests/nightwatch.json.underscore
+++ b/test/nightwatch_tests/nightwatch.json.underscore
@@ -8,20 +8,11 @@
   "live_output" : false,
 
   "webdriver": {
+    "start_process": true,
     "ssl": false,
-    "password": "<%- password %>"
-  },
-  "selenium" : {
-    "start_process" : false,
-    "server_path" : "",
-    "log_path" : "",
+    "password": "<%- password %>",
     "host" : "127.0.0.1",
-    "port" : "<%- selenium_port %>",
-    "cli_args" : {
-      "webdriver.chrome.driver" : "",
-      "webdriver.ie.driver" : "",
-      "webdriver.firefox.profile" : ""
-    }
+    "port" : "<%- selenium_port %>"
   },
 
   "test_settings" : {
@@ -58,57 +49,9 @@
         "javascriptEnabled" : true,
         "acceptSslCerts" : true,
         "chromeOptions" : {
-          "args" : ["window-size=1400,900", "--no-sandbox"]
+          "args" : ["window-size=1400,900", "--no-sandbox", "--headless", "--disable-gpu", "--disable-dev-shm-usage", "--remote-debugging-port=9222"]
         }
       }
-    },
-
-    "saucelabs" : {
-      "selenium_host" : "ondemand.saucelabs.com",
-      "selenium_port" : 80,
-      "username" : "${SAUCE_USERNAME}",
-      "access_key" : "${SAUCE_ACCESS_KEY}",
-      "silent" : true,
-      "output" : true,
-      "screenshots" : {
-        "enabled" : false,
-        "path" : ""
-      },
-      "desiredCapabilities": {
-        "name" : "test-example",
-        "browserName": "chrome",
-        "tunnel-identifier":"${TRAVIS_JOB_NUMBER}"
-      },
-      "globals" : {
-        "myGlobal" : "some_sauce_global"
-      },
-      "selenium" : {
-        "start_process" : false
-      }
-    },
-
-    "phantomjs" : {
-      "desiredCapabilities" : {
-        "browserName" : "phantomjs",
-        "javascriptEnabled" : true,
-        "acceptSslCerts" : true,
-        "phantomjs.binary.path" : "/path/to/phantomjs"
-      }
-    },
-
-    "browserstack" : {
-      "selenium" : {
-        "start_process" : false
-      },
-      "selenium_host" : "hub.browserstack.com",
-      "selenium_port" : 80,
-      "silent" : true,
-      "desiredCapabilities": {
-        "name" : "test-example",
-        "browserName": "firefox",
-        "browserstack.user" : "...",
-        "browserstack.key" : "..."
-      }
     }
   }
 }
diff --git a/tests.md b/tests.md
index e9033f06..4aea862d 100644
--- a/tests.md
+++ b/tests.md
@@ -20,40 +20,44 @@ E.g.: to run tests under the `addons/cors` path:
 
 ## End-to-end tests
 
-To run selenium locally you need Docker installed. Selenium runs in a Docker container and connects to a CouchDB instance in another container. To start them run the command:
+Nightwatch tests require that you have Chrome installed. If you prefer to use another browser, update `test/nightwatch_tests/nightwatch.json.underscore` and install the appropriate driver - see Nightwatch documentation for more details.
 
-    npm run docker:up
+The tests also require a CouchDB server (see step 2).
 
-You can run `npm run docker:logs` to see when the CouchDB instance is ready to go. You also need a Fauxton server instance runnning:
-
-    grunt debugDev && DIST=./dist/debug ./bin/fauxton
-
-Finally to run the tests:
-
-    grunt nightwatch
+1. Define the version of CouchDB to test against
+```bash
+COUCHDB_IMAGE=couchdb:3
+NIGHTWATCH_SKIPTAGS="search,nonpartitioned,couchdb-v2-only"
+-- OR --
+COUCHDB_IMAGE=couchdb:2.3.1
+NIGHTWATCH_SKIPTAGS="search,partitioned"
+```
+2. Start a CouchDB instance
+```bash
+npm run docker:up
+```
+(run `npm run docker:logs` to see when the CouchDB instance is ready to go)
+3. Start Fauxton
+```bash
+grunt debugDev && DIST=./dist/debug ./bin/fauxton
+```
+4. Run the tests
+```bash
+grunt nightwatch
+```
 
 Or to run only one file:
+```bash
+grunt nightwatch --file=filename
+```
 
-    grunt nightwatch --file=viewEdit
-
-View the package.json `scripts` section for some other useful docker commands.
-
-### Debugging Selenium tests
-
-To debug and view a failing selenium test, you need to run the selenium container with vnc built into it:
-
-    npm run docker:debug-up
-
-Once it is up and running you can connect to it with any VNC client on `127.0.0.1:5900`. On MacOSX open safari
-and type `vnc://127.0.0.1:5900`. That will open screen sharing. It will then prompt for the password which is `secret`.
-
-After that run a Fauxton server instance and the nightwatch tests you want to debug.
+View the package.json `scripts` section for other useful Docker commands.
 
 
 ### Omitting Nightwatch tests
 
 If you need to omit particular tests from running you can add a `testBlacklist` option to the nightwatch section of
-your settings.json file. That defines an object of the following form:
+your settings.json file. It should define an object of the following form:
 
 ```javascript
 // ...