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

voidmatcha pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new 9245bbb6bf [ZEPPELIN-6527] Fix flaky run-e2e-tests-in-zeppelin-web CI 
job (searchBlock Protractor timing)
9245bbb6bf is described below

commit 9245bbb6bf4b74d36959b0335ee2958b0542b984
Author: Minho Jang <[email protected]>
AuthorDate: Sat Jul 18 01:26:12 2026 +0900

    [ZEPPELIN-6527] Fix flaky run-e2e-tests-in-zeppelin-web CI job (searchBlock 
Protractor timing)
    
    ### What is this PR for?
    This PR removes the flaky classic `zeppelin-web` Protractor e2e job by 
moving its remaining active coverage to the existing Playwright e2e workflow.
    
    The old `run-e2e-tests-in-zeppelin-web` job depended on Protractor, 
webdriver-manager, and a pinned ChromeDriver 2.35, and had been failing 
intermittently in the classic search/replace tests due to AngularJS/Ace 
synchronization timing.
    
    Since that stack is end-of-life and cannot be reasonably modernized in 
place, this PR ports the 10 active checks from `home.spec.js` and 
`searchBlock.spec.js` to Playwright, pointed at the classic `/classic` UI.
    
    The migrated tests keep the existing classic UI coverage for the home page, 
interpreter permission save flow, search shortcut, match counters, replace, and 
replace-all behavior. After that coverage is available in Playwright, the 
obsolete Protractor config, scripts, dependencies, and CI job are removed.
    
    ### What type of PR is it?
    Improvement
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/browse/ZEPPELIN-6527
    
    ### How should this be tested?
    
    ```bash
    cd zeppelin-web-angular
    npx playwright test e2e/tests/classic --project=classic --reporter=line
    ```
    
    For the Maven/CI path:
    ```bash
    ./mvnw clean install -DskipTests -am -pl 
python,zeppelin-jupyter-interpreter,zeppelin-web,zeppelin-web-angular 
-Pweb-classic
    xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" ./mvnw 
verify -pl zeppelin-web-angular -Pweb-e2e
    ```
    
    ### Questions:
    * Does the license files need to update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? Edit `zeppelin-web/README.md` to reflect 
migrated classic web e2e test
    
    
    Closes #5295 from miinhho/fix/flaky-e2e-in-zeppelin-web.
    
    Signed-off-by: YONGJAE LEE <[email protected]>
---
 .github/workflows/frontend.yml                     |   39 +-
 pom.xml                                            |    1 -
 zeppelin-web-angular/e2e/AGENTS.md                 |   30 +
 zeppelin-web-angular/e2e/cleanup-util.ts           |    8 +-
 .../classic/classic-collaborative-mode.spec.ts     |   20 +
 .../e2e/tests/classic/classic-home.spec.ts         |   40 +
 .../e2e/tests/classic/classic-interpreter.spec.ts  |   72 ++
 .../e2e/tests/classic/classic-search-block.spec.ts |  164 +++
 zeppelin-web-angular/package.json                  |    1 +
 zeppelin-web-angular/playwright.config.js          |   44 +-
 zeppelin-web/README.md                             |    9 +-
 zeppelin-web/e2e/collaborativeMode.spec.js         |   72 --
 zeppelin-web/e2e/home.spec.js                      |   66 --
 zeppelin-web/e2e/searchBlock.spec.js               |  207 ----
 zeppelin-web/package-lock.json                     | 1229 +-------------------
 zeppelin-web/package.json                          |    3 -
 zeppelin-web/pom.xml                               |   70 +-
 zeppelin-web/protractor.conf.js                    |   44 -
 18 files changed, 403 insertions(+), 1716 deletions(-)

diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml
index efdda51a3d..872bfe6133 100644
--- a/.github/workflows/frontend.yml
+++ b/.github/workflows/frontend.yml
@@ -44,37 +44,6 @@ jobs:
         working-directory: zeppelin-web-angular/projects/zeppelin-react
         run: npm ci --ignore-scripts && npm audit --audit-level=high
 
-  run-e2e-tests-in-zeppelin-web:
-    runs-on: ubuntu-24.04
-    steps:
-      - name: Checkout
-        uses: actions/checkout@v5
-      - name: Tune Runner VM
-        uses: ./.github/actions/tune-runner-vm
-      - name: Set up JDK 11
-        uses: actions/setup-java@v5
-        with:
-          distribution: 'temurin'
-          java-version: 11
-      - name: Cache local Maven repository
-        uses: actions/cache@v5
-        with:
-          path: |
-            ~/.m2/repository
-            !~/.m2/repository/org/apache/zeppelin/
-            ~/.spark-dist
-            ~/.cache
-          key: ${{ runner.os }}-zeppelin-${{ hashFiles('**/pom.xml') }}
-          restore-keys: |
-            ${{ runner.os }}-zeppelin-
-      - name: Install application
-        run: ./mvnw clean install -DskipTests -am -pl 
zeppelin-web,zeppelin-web-angular -Pweb-classic -Pspark-scala-2.12 -Pspark-3.4 
-Pweb-dist ${MAVEN_ARGS}
-      - name: Run headless test
-        run: xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" 
./mvnw verify -pl zeppelin-web -Pweb-classic -Pspark-scala-2.12 -Pspark-3.4 
-Pweb-dist -Pweb-e2e ${MAVEN_ARGS}
-      - name: Print zeppelin logs
-        if: always()
-        run: if [ -d "logs" ]; then cat logs/*; fi
-
   run-playwright-e2e-tests:
     runs-on: ubuntu-24.04
     env:
@@ -122,7 +91,11 @@ jobs:
           channels: conda-forge,defaults
           channel-priority: strict
       - name: Install application
-        run: ./mvnw clean install -DskipTests -am -pl 
python,zeppelin-jupyter-interpreter,zeppelin-web-angular ${MAVEN_ARGS}
+        run: ./mvnw clean install -DskipTests -am -pl 
python,zeppelin-jupyter-interpreter,zeppelin-web,zeppelin-web-angular 
-Pweb-classic ${MAVEN_ARGS}
+      # Keeps the Karma coverage previously run by the removed zeppelin-web 
e2e job
+      - name: Run zeppelin-web unit tests
+        if: matrix.mode == 'anonymous'
+        run: ./mvnw test -pl zeppelin-web -Pweb-classic,web-unit-test 
${MAVEN_ARGS}
       - name: Setup Zeppelin Server (Shiro.ini)
         run: |
           export ZEPPELIN_CONF_DIR=./conf
@@ -136,6 +109,8 @@ jobs:
           mkdir -p $ZEPPELIN_E2E_TEST_NOTEBOOK_DIR
           echo "Created test notebook directory: 
$ZEPPELIN_E2E_TEST_NOTEBOOK_DIR"
       - name: Run headless E2E test with Maven
+        env:
+          E2E_MODE: ${{ matrix.mode }}
         run: xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" 
./mvnw verify -pl zeppelin-web-angular -Pweb-e2e ${MAVEN_ARGS}
       - name: Upload Playwright Report
         uses: actions/upload-artifact@v6
diff --git a/pom.xml b/pom.xml
index 0b3a180301..62fe3a5b2d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -998,7 +998,6 @@
               <exclude>**/.bowerrc</exclude>
               <exclude>.editorconfig</exclude>
               <exclude>**/.eslintrc</exclude>
-              <exclude>**/protractor.conf.js</exclude>
               <exclude>**/.tmp/**</exclude>
               <exclude>**/target/**</exclude>
               <exclude>**/node/**</exclude>
diff --git a/zeppelin-web-angular/e2e/AGENTS.md 
b/zeppelin-web-angular/e2e/AGENTS.md
index 3a65bff2a3..1fe1c62acf 100644
--- a/zeppelin-web-angular/e2e/AGENTS.md
+++ b/zeppelin-web-angular/e2e/AGENTS.md
@@ -117,6 +117,7 @@ exercised transitively and are not counted.
 | --- | --- |
 | `npm run e2e` | Full suite |
 | `npm run e2e:fast` | Chromium only (fast) |
+| `npm run e2e:classic` | Classic `/classic` UI suite against `:8080` (needs 
`-Pweb-classic`) |
 | `npm run e2e:ui` | Playwright Test UI |
 | `npm run e2e:headed` | Headed run |
 | `npm run e2e:debug` | Step-by-step debugger |
@@ -184,3 +185,32 @@ route being reimplemented, but do not build parity 
infrastructure ahead of need.
 - Keep the composed suite focused on real cross-seam user flows. Behavior that
   lives entirely inside one fragment belongs in that fragment's own tests; do 
not
   grow the composed suite into a per-fragment unit suite.
+
+## Classic UI Tests (`e2e/tests/classic/`)
+
+`e2e/tests/classic/` runs Playwright against the legacy AngularJS app served at
+`/classic`, ported from the retired `zeppelin-web` Protractor suite. Treat it 
as
+a frozen legacy surface: keep it at parity coverage and test new features only 
in
+the Angular/React suites.
+
+- **Locators (classic exception):** the classic templates predate roles and
+  `data-testid`, so the role/label/text-first rule cannot apply. Sanctioned 
here:
+  element ids (`#findInput`), `ng-click="..."` / `ng-controller="..."` 
attribute
+  selectors, class selectors the legacy templates already expose (`.username`,
+  `.interpreterHead`), and Ace/Select2 internals. Do not add `data-testid` to 
the
+  frozen `zeppelin-web` sources.
+- **Readiness:** `waitForZeppelinReady` is Angular-specific (`[ng-version]`) 
and
+  does not resolve on `/classic`; gate on a classic-visible signal instead 
(e.g.
+  the first `ParagraphCtrl` paragraph, or `.ace_text-input` attached).
+- **Coverage:** `PAGES` is the Angular coverage denominator; classic pages are
+  intentionally outside it, so `addPageAnnotationBeforeEach` is not used here.
+- **Running:** the `classic` project targets `http://localhost:8080` (Desktop
+  Chrome only) and needs a Zeppelin server built with `-Pweb-classic` — the
+  `:4200` dev server does not serve `/classic`. Run it with `npm run 
e2e:classic`
+  (sets `E2E_CLASSIC=1`); running a `tests/classic/*` file path directly is 
also
+  detected. In CI the classic project runs only in the anonymous matrix leg
+  (`E2E_MODE`), matching the anonymous-only legacy Protractor suite.
+- **POM:** inlining locators/helpers is acceptable while the suite is this 
small;
+  if it grows, move them behind `models/classic-*.ts` / `*.util.ts`.
+- The React-migration / framework-neutral-spec guidance does not apply to
+  `tests/classic/`.
diff --git a/zeppelin-web-angular/e2e/cleanup-util.ts 
b/zeppelin-web-angular/e2e/cleanup-util.ts
index a00678dedd..48a0deefd5 100644
--- a/zeppelin-web-angular/e2e/cleanup-util.ts
+++ b/zeppelin-web-angular/e2e/cleanup-util.ts
@@ -12,12 +12,14 @@
 
 import { BASE_URL, E2E_TEST_FOLDER } from './models/base-page';
 
+const cleanupBaseUrl = process.env.PLAYWRIGHT_BASE_URL || BASE_URL;
+
 export const cleanupTestNotebooks = async () => {
   try {
     console.log('Cleaning up test folder via API...');
 
     // Get all notebooks and folders
-    const response = await fetch(`${BASE_URL}/api/notebook`);
+    const response = await fetch(`${cleanupBaseUrl}/api/notebook`);
     const data = await response.json();
     if (!data.body || !Array.isArray(data.body)) {
       console.log('No notebooks found or invalid response format');
@@ -47,7 +49,7 @@ export const cleanupTestNotebooks = async () => {
         try {
           console.log(`Deleting test folder: ${testFolder.id} 
(${testFolder.path})`);
 
-          const deleteResponse = await 
fetch(`${BASE_URL}/api/notebook/${testFolder.id}`, {
+          const deleteResponse = await 
fetch(`${cleanupBaseUrl}/api/notebook/${testFolder.id}`, {
             method: 'DELETE'
           });
 
@@ -70,7 +72,7 @@ export const cleanupTestNotebooks = async () => {
     if (error instanceof Error && error.message.includes('ECONNREFUSED')) {
       console.error('Failed to connect to local server. Please start the 
frontend server first:');
       console.error('  npm start');
-      console.error(`  or make sure ${BASE_URL} is running`);
+      console.error(`  or make sure ${cleanupBaseUrl} is running`);
     } else {
       console.warn('Failed to cleanup test folder:', error);
     }
diff --git 
a/zeppelin-web-angular/e2e/tests/classic/classic-collaborative-mode.spec.ts 
b/zeppelin-web-angular/e2e/tests/classic/classic-collaborative-mode.spec.ts
new file mode 100644
index 0000000000..afc9935d0f
--- /dev/null
+++ b/zeppelin-web-angular/e2e/tests/classic/classic-collaborative-mode.spec.ts
@@ -0,0 +1,20 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { test } from '@playwright/test';
+
+test.describe('Classic collaborative mode', () => {
+  // TODO: Port the disabled Protractor collaborative editing scenario from
+  // zeppelin-web/e2e/collaborativeMode.spec.js when collaborative mode 
coverage is restored.
+  // See https://issues.apache.org/jira/browse/ZEPPELIN-5674.
+  test.fixme('propagates edits across browser sessions', async () => {});
+});
diff --git a/zeppelin-web-angular/e2e/tests/classic/classic-home.spec.ts 
b/zeppelin-web-angular/e2e/tests/classic/classic-home.spec.ts
new file mode 100644
index 0000000000..c20d5ebfe1
--- /dev/null
+++ b/zeppelin-web-angular/e2e/tests/classic/classic-home.spec.ts
@@ -0,0 +1,40 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { expect, Page, test } from '@playwright/test';
+
+const CLASSIC_HOME = '/classic';
+
+const waitForClassicHomeReady = async (page: Page) => {
+  await page.goto(CLASSIC_HOME, { waitUntil: 'domcontentloaded' });
+  await expect(page.locator('#welcome')).toHaveText('Welcome to Zeppelin!', { 
timeout: 30000 });
+  await expect(page.getByRole('link', { name: /Import note/ })).toBeVisible();
+  await expect(page.getByRole('link', { name: /Create new note/ 
})).toBeVisible();
+};
+
+test.describe('Classic home', () => {
+  test.beforeEach(async ({ page }) => {
+    await waitForClassicHomeReady(page);
+  });
+
+  test('should have a welcome message', async ({ page }) => {
+    await expect(page.locator('#welcome')).toHaveText('Welcome to Zeppelin!');
+  });
+
+  test('should have the button for importing notebook', async ({ page }) => {
+    await expect(page.getByRole('link', { name: /Import note/ 
})).toBeVisible();
+  });
+
+  test('should have the button for creating notebook', async ({ page }) => {
+    await expect(page.getByRole('link', { name: /Create new note/ 
})).toBeVisible();
+  });
+});
diff --git a/zeppelin-web-angular/e2e/tests/classic/classic-interpreter.spec.ts 
b/zeppelin-web-angular/e2e/tests/classic/classic-interpreter.spec.ts
new file mode 100644
index 0000000000..f0453a8fcd
--- /dev/null
+++ b/zeppelin-web-angular/e2e/tests/classic/classic-interpreter.spec.ts
@@ -0,0 +1,72 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { expect, Page, test } from '@playwright/test';
+
+const CLASSIC_HOME = '/classic';
+
+const waitForClassicHomeReady = async (page: Page) => {
+  await page.goto(CLASSIC_HOME, { waitUntil: 'domcontentloaded' });
+  await expect(page.locator('#welcome')).toHaveText('Welcome to Zeppelin!', { 
timeout: 30000 });
+  await expect(page.getByRole('link', { name: /Import note/ })).toBeVisible();
+  await expect(page.getByRole('link', { name: /Create new note/ 
})).toBeVisible();
+};
+
+test.describe('Classic interpreter', () => {
+  test.beforeEach(async ({ page }) => {
+    await waitForClassicHomeReady(page);
+  });
+
+  test('correct save permission in interpreter', async ({ page }) => {
+    const ownerName = 'admin';
+    const interpreterName = `interpreter_e2e_test_${Date.now()}`;
+
+    await page.locator('.username').click();
+    await page.locator('a[href="#/interpreter"]').click();
+    await expect(page.locator('.interpreterHead')).toBeVisible({ timeout: 
30000 });
+
+    await page.locator('button[ng-click="showAddNewSetting = 
!showAddNewSetting"]').click();
+    const createForm = page.locator('.interpreterSettingAdd');
+    await expect(createForm).toBeVisible();
+    await 
createForm.locator('#newInterpreterSettingName').fill(interpreterName);
+    await 
createForm.locator('select[ng-model="newInterpreterSetting.group"]').selectOption({
 label: 'angular' });
+    await createForm.locator('#idShowPermission').check();
+
+    const ownerInput = createForm.locator('input.select2-search__field');
+    await ownerInput.fill(ownerName);
+    // JUSTIFIED: Select2 can render grouped AJAX/tag candidates; the final 
visible option is the concrete typed owner.
+    const ownerOption = page.locator('.select2-results__option').filter({ 
hasText: ownerName }).last();
+    await expect(ownerOption).toBeVisible({ timeout: 30000 });
+    await ownerInput.press('Enter');
+    await expect(createForm.locator('.select2-selection__choice', { hasText: 
ownerName })).toBeVisible();
+
+    await 
createForm.locator('span[ng-click="addNewInterpreterSetting()"]').click();
+
+    let setting = page.locator(`#${interpreterName}`);
+    await expect(setting).toBeVisible({ timeout: 30000 });
+
+    await setting.locator('span.fa-pencil').click();
+    await setting.locator('button[type="submit"]').click();
+    await page.locator('.bootstrap-dialog-footer-buttons button', { hasText: 
'OK' }).click();
+
+    await page.goto('/classic/#/interpreter', { waitUntil: 'domcontentloaded' 
});
+    await expect(page.locator('.interpreterHead')).toBeVisible({ timeout: 
30000 });
+    setting = page.locator(`#${interpreterName}`);
+    await expect(setting.locator(`select[id="${interpreterName}Owners"] 
option`)).toHaveText(ownerName, {
+      timeout: 30000
+    });
+
+    await setting.locator('span.fa-trash').click();
+    await page.locator('.bootstrap-dialog-footer-buttons button', { hasText: 
'OK' }).click();
+    await expect(setting).toBeHidden({ timeout: 30000 });
+  });
+});
diff --git 
a/zeppelin-web-angular/e2e/tests/classic/classic-search-block.spec.ts 
b/zeppelin-web-angular/e2e/tests/classic/classic-search-block.spec.ts
new file mode 100644
index 0000000000..72d36f09b6
--- /dev/null
+++ b/zeppelin-web-angular/e2e/tests/classic/classic-search-block.spec.ts
@@ -0,0 +1,164 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { expect, Page, test } from '@playwright/test';
+import { createTestNotebookWithName } from '../../utils';
+
+const testData = {
+  textInFirstP: 'text word text',
+  textInSecondP: 'text tete tt'
+};
+
+const countSubstringOccurrence = (text: string, substring: string): number =>
+  substring ? text.split(substring).length - 1 : 0;
+
+const expectedMatchCount = (substring: string): number =>
+  countSubstringOccurrence(testData.textInFirstP, substring) +
+  countSubstringOccurrence(testData.textInSecondP, substring);
+
+const waitForClassicNotebookReady = async (page: Page, noteId: string) => {
+  await page.goto(`/classic/#/notebook/${noteId}`, { waitUntil: 
'domcontentloaded' });
+  // JUSTIFIED: Classic note setup creates a single first paragraph; this is 
the render gate for that paragraph.
+  await 
expect(page.locator('div[ng-controller="ParagraphCtrl"]').first()).toBeVisible({
 timeout: 30000 });
+  // JUSTIFIED: The first Ace textarea belongs to the first paragraph created 
with the note.
+  await expect(page.locator('.ace_text-input').first()).toBeAttached({ 
timeout: 30000 });
+};
+
+const fillAceEditor = async (page: Page, index: number, text: string) => {
+  // JUSTIFIED: The tests intentionally fill paragraph editors by creation 
order: first paragraph, then inserted second paragraph.
+  const editor = page.locator('.ace_editor').nth(index);
+  await editor.click();
+  await page.keyboard.type(text);
+  await expect(editor.locator('.ace_line', { hasText: text })).toBeVisible({ 
timeout: 15000 });
+};
+
+const makeTestParagraphs = async (page: Page) => {
+  await fillAceEditor(page, 0, testData.textInFirstP);
+
+  await page.locator('.new-paragraph.last-paragraph').click();
+  await expect(page.locator('.ace_editor')).toHaveCount(2, { timeout: 15000 });
+  await fillAceEditor(page, 1, testData.textInSecondP);
+};
+
+const openSearchBoxByShortcut = async (page: Page) => {
+  await page.keyboard.press('Control+Alt+F');
+  await expect(page.locator('.search-dropdown')).toBeVisible({ timeout: 10000 
});
+};
+
+const findInput = (page: Page) => page.locator('#findInput');
+const replaceInput = (page: Page) => page.locator('.search-group', { hasText: 
'Replace' }).locator('input');
+const matchesElement = (page: Page) => page.locator('.search-group 
.after-input');
+const nextOccurrenceButton = (page: Page) => page.locator('.search-group 
button[ng-click="nextOccurrence()"]');
+const prevOccurrenceButton = (page: Page) => page.locator('.search-group 
button[ng-click="prevOccurrence()"]');
+const replaceButton = (page: Page) => page.locator('.search-group 
button[ng-click="replace()"]');
+const replaceAllButton = (page: Page) => page.locator('.search-group 
button[ng-click="replaceAll()"]');
+
+const setFindText = async (page: Page, text: string) => {
+  await findInput(page).fill(text);
+};
+
+const waitForMatches = async (page: Page, current: number, amount: number) => {
+  await expect(matchesElement(page)).toHaveText(`${current} of ${amount}`, { 
timeout: 15000 });
+};
+
+const markerCount = async (page: Page): Promise<number> =>
+  page.locator('.ace_marker-layer div.ace_selected-word, .ace_marker-layer 
div.ace_selection').count();
+
+test.describe('Classic search block', () => {
+  test.beforeEach(async ({ page }) => {
+    const { noteId } = await createTestNotebookWithName(page, {
+      namePrefix: 'ClassicSearchBlock'
+    });
+    await waitForClassicNotebookReady(page, noteId);
+  });
+
+  test('shortcut works', async ({ page }) => {
+    // JUSTIFIED: The keyboard shortcut is scoped to the currently focused 
first paragraph editor.
+    await page.locator('.ace_editor').first().click();
+    await openSearchBoxByShortcut(page);
+  });
+
+  test('correct count of selections', async ({ page }) => {
+    await makeTestParagraphs(page);
+    await openSearchBoxByShortcut(page);
+
+    const textToFind = 'te';
+    const matchesCount = expectedMatchCount(textToFind);
+    await setFindText(page, textToFind);
+
+    await waitForMatches(page, 1, matchesCount);
+    await expect.poll(() => markerCount(page), { timeout: 15000 
}).toBe(matchesCount + 1);
+  });
+
+  test('correct matches count number', async ({ page }) => {
+    await makeTestParagraphs(page);
+    await openSearchBoxByShortcut(page);
+
+    let textToFind = 't';
+    await setFindText(page, textToFind);
+    await waitForMatches(page, 1, expectedMatchCount(textToFind));
+
+    textToFind = 'te';
+    await setFindText(page, textToFind);
+    await waitForMatches(page, 1, expectedMatchCount(textToFind));
+  });
+
+  test('counter increase and decrease correctly', async ({ page }) => {
+    await makeTestParagraphs(page);
+    await openSearchBoxByShortcut(page);
+
+    const textToFind = 'te';
+    const matchesCount = expectedMatchCount(textToFind);
+    await setFindText(page, textToFind);
+    await waitForMatches(page, 1, matchesCount);
+
+    await nextOccurrenceButton(page).click();
+    await waitForMatches(page, matchesCount > 1 ? 2 : 1, matchesCount);
+
+    await prevOccurrenceButton(page).click();
+    await waitForMatches(page, 1, matchesCount);
+
+    await prevOccurrenceButton(page).click();
+    await waitForMatches(page, matchesCount, matchesCount);
+  });
+
+  test('matches count changes correctly after replace', async ({ page }) => {
+    await makeTestParagraphs(page);
+    await openSearchBoxByShortcut(page);
+
+    const textToFind = 'te';
+    const matchesCount = expectedMatchCount(textToFind);
+    await setFindText(page, textToFind);
+    await waitForMatches(page, 1, matchesCount);
+    await replaceInput(page).fill('ABC');
+
+    await replaceButton(page).click();
+    await waitForMatches(page, 1, matchesCount - 1);
+
+    await prevOccurrenceButton(page).click();
+    await replaceButton(page).click();
+    await waitForMatches(page, 1, matchesCount - 2);
+  });
+
+  test('replace all works correctly', async ({ page }) => {
+    await makeTestParagraphs(page);
+    await openSearchBoxByShortcut(page);
+
+    const textToFind = 'te';
+    await setFindText(page, textToFind);
+    await waitForMatches(page, 1, expectedMatchCount(textToFind));
+    await replaceInput(page).fill('ABC');
+
+    await replaceAllButton(page).click();
+    await waitForMatches(page, 0, 0);
+  });
+});
diff --git a/zeppelin-web-angular/package.json 
b/zeppelin-web-angular/package.json
index 5e84360608..441c4cb5ea 100644
--- a/zeppelin-web-angular/package.json
+++ b/zeppelin-web-angular/package.json
@@ -21,6 +21,7 @@
     "test:eslint-rules": "node --test eslint-rules/",
     "e2e": "playwright test",
     "e2e:fast": "playwright test --project=chromium",
+    "e2e:classic": "cross-env E2E_CLASSIC=1 playwright test --project=classic",
     "e2e:ui": "playwright test --ui",
     "e2e:headed": "playwright test --headed",
     "e2e:debug": "playwright test --debug",
diff --git a/zeppelin-web-angular/playwright.config.js 
b/zeppelin-web-angular/playwright.config.js
index bc1bd46ebd..4e019e8fd5 100644
--- a/zeppelin-web-angular/playwright.config.js
+++ b/zeppelin-web-angular/playwright.config.js
@@ -12,6 +12,11 @@
 
 const { defineConfig, devices } = require('@playwright/test');
 
+const classicTests = /tests\/classic\/.*\.spec\.ts/;
+const isClassicOnlyRun = process.env.E2E_CLASSIC === '1' || 
process.argv.some(arg => arg.includes('tests/classic'));
+const defaultBaseURL = process.env.CI || isClassicOnlyRun ? 
'http://localhost:8080' : 'http://localhost:4200';
+process.env.PLAYWRIGHT_BASE_URL = process.env.PLAYWRIGHT_BASE_URL || 
defaultBaseURL;
+
 // https://playwright.dev/docs/test-configuration
 module.exports = defineConfig({
   testDir: './e2e',
@@ -31,7 +36,7 @@ module.exports = defineConfig({
     ['./e2e/reporter.coverage.ts']
   ],
   use: {
-    baseURL: process.env.CI ? 'http://localhost:8080' : 
'http://localhost:4200',
+    baseURL: process.env.PLAYWRIGHT_BASE_URL,
     trace: 'on-first-retry', // https://playwright.dev/docs/trace-viewer
     screenshot: process.env.CI ? 'off' : 'only-on-failure',
     video: process.env.CI ? 'off' : 'retain-on-failure',
@@ -50,8 +55,24 @@ module.exports = defineConfig({
       name: 'setup',
       testMatch: /global\.setup\.ts/
     },
+    // skip classic in the auth CI leg (its Protractor predecessor was 
anonymous-only)
+    ...(process.env.E2E_MODE === 'auth'
+      ? []
+      : [
+          {
+            name: 'classic',
+            testMatch: classicTests,
+            use: {
+              ...devices['Desktop Chrome'],
+              baseURL: 'http://localhost:8080',
+              storageState: 'playwright/.auth/user.json'
+            },
+            dependencies: ['setup']
+          }
+        ]),
     {
       name: 'chromium',
+      testIgnore: classicTests,
       use: {
         ...devices['Desktop Chrome'],
         permissions: ['clipboard-read', 'clipboard-write'],
@@ -61,6 +82,7 @@ module.exports = defineConfig({
     },
     {
       name: 'Google Chrome',
+      testIgnore: classicTests,
       use: {
         ...devices['Desktop Chrome'],
         channel: 'chrome',
@@ -71,6 +93,7 @@ module.exports = defineConfig({
     },
     {
       name: 'firefox',
+      testIgnore: classicTests,
       use: {
         ...devices['Desktop Firefox'],
         storageState: 'playwright/.auth/user.json'
@@ -79,6 +102,7 @@ module.exports = defineConfig({
     },
     {
       name: 'webkit',
+      testIgnore: classicTests,
       use: {
         ...devices['Desktop Safari'],
         launchOptions: {
@@ -90,6 +114,7 @@ module.exports = defineConfig({
     },
     {
       name: 'Microsoft Edge',
+      testIgnore: classicTests,
       use: {
         ...devices['Desktop Edge'],
         channel: 'msedge',
@@ -99,12 +124,13 @@ module.exports = defineConfig({
       dependencies: ['setup']
     }
   ],
-  webServer: process.env.CI
-    ? undefined
-    : {
-        command: 'npm run start',
-        url: 'http://localhost:4200',
-        reuseExistingServer: true,
-        timeout: 2 * 60 * 1000
-      }
+  webServer:
+    process.env.CI || isClassicOnlyRun
+      ? undefined
+      : {
+          command: 'npm run start',
+          url: 'http://localhost:4200',
+          reuseExistingServer: true,
+          timeout: 2 * 60 * 1000
+        }
 });
diff --git a/zeppelin-web/README.md b/zeppelin-web/README.md
index a7ab711700..4023f14d87 100644
--- a/zeppelin-web/README.md
+++ b/zeppelin-web/README.md
@@ -40,12 +40,15 @@ $ WEB_PORT=YOUR_WEB_DEV_PORT npm run dev
 # running unit tests
 $ npm run karma-test
 
-# running e2e tests: make sure that zeppelin instance started (localhost:8080)
-$ npm run e2e
+# running unit tests through Maven (requires node_modules from a prior build)
+$ (cd .. && ./mvnw test -pl zeppelin-web -Pweb-classic,web-unit-test)
+
+# running classic UI e2e tests: make sure that a Zeppelin instance started 
(localhost:8080)
+$ cd ../zeppelin-web-angular && npm run e2e:classic
 ```
 
 - to write unit tests, please refer [Angular Test 
Patterns](https://github.com/daniellmb/angular-test-patterns)
-- to write e2e tests, please refer [Protractor 
Tutorial](http://www.protractortest.org/#/tutorial#step-1-interacting-with-elements)
+- to write e2e tests, please refer to the Playwright tests under 
`zeppelin-web-angular/e2e`
 
 ### Packaging
 
diff --git a/zeppelin-web/e2e/collaborativeMode.spec.js 
b/zeppelin-web/e2e/collaborativeMode.spec.js
deleted file mode 100644
index 2c3dc1196e..0000000000
--- a/zeppelin-web/e2e/collaborativeMode.spec.js
+++ /dev/null
@@ -1,72 +0,0 @@
-// Disable this test temporarily, See 
https://issues.apache.org/jira/browse/ZEPPELIN-5674
-// describe('Collaborative mode tests', function () {
-//
-//   let clickOn = function(elem) {
-//     browser.actions().mouseMove(elem).click().perform()
-//   };
-//
-//   let waitVisibility = function(elem) {
-//     browser.wait(protractor.ExpectedConditions.visibilityOf(elem))
-//   };
-//
-//   let test_text_1 = "_one_more_text_for_tests";      // without space!!!
-//   let test_text_2 = "Collaborative_mode_test_text";  // without space!!!
-//
-//   browser.get('http://localhost:8080/classic');
-//   clickOn(element(by.linkText('Create new note')));
-//   waitVisibility(element(by.id('noteCreateModal')));
-//   clickOn(element(by.id('createNoteButton')));
-//   let user1Browser = browser.forkNewDriverInstance();
-//   let user2Browser = browser.forkNewDriverInstance();
-//   browser.getCurrentUrl().then(function (url) {
-//     user1Browser.get(url);
-//     user2Browser.get(url);
-//   });
-//   waitVisibility(element(by.xpath('//*[@uib-tooltip="Users who watch this 
note: anonymous"]')));
-//   browser.sleep(500);
-//
-//   it('user 1 received the first patch', function () {
-//     browser.switchTo().activeElement().sendKeys(test_text_1);
-//     browser.sleep(500);
-//     user1Browser.isElementPresent(by.xpath('//span[contains(text(), \'' + 
test_text_1 + '\')]'))
-//       .then(function (isPresent) {
-//       expect(isPresent).toBe(true);
-//     });
-//   });
-//
-//   it('user 2 received the first patch', function () {
-//     user2Browser.isElementPresent(by.xpath('//span[contains(text(), \'' + 
test_text_1 + '\')]'))
-//       .then(function (isPresent) {
-//       expect(isPresent).toBe(true);
-//     });
-//   });
-//
-//   it('user root received a first patch', function () {
-//     user1Browser.switchTo().activeElement().sendKeys(test_text_2);
-//     user1Browser.sleep(500);
-//     browser.isElementPresent(by.xpath('//span[contains(text(), \'' + 
test_text_2 +
-//       test_text_1 + '\')]')).then(function (isPresent) {
-//       expect(isPresent).toBe(true);
-//     });
-//   });
-//
-//   it('user 2 received the second patch', function () {
-//     user2Browser.isElementPresent(by.xpath('//span[contains(text(), \'' + 
test_text_2 +
-//       test_text_1 + '\')]')).then(function (isPresent) {
-//       expect(isPresent).toBe(true);
-//     });
-//   });
-//
-//   it('finish', function () {
-//     user1Browser.close();
-//     user2Browser.close();
-//     
clickOn(element(by.xpath('//*[@id="main"]//button[@ng-click="moveNoteToTrash(note.id)"]')));
-//     let moveToTrashDialogPath =
-//       '//div[@class="modal-dialog"][contains(.,"This note will be moved to 
trash")]';
-//     waitVisibility(element(by.xpath(moveToTrashDialogPath)));
-//     let okButton = element(
-//       by.xpath(moveToTrashDialogPath + 
'//div[@class="modal-footer"]//button[contains(.,"OK")]'));
-//     clickOn(okButton);
-//   });
-//
-// });
diff --git a/zeppelin-web/e2e/home.spec.js b/zeppelin-web/e2e/home.spec.js
deleted file mode 100644
index 7a9dde0759..0000000000
--- a/zeppelin-web/e2e/home.spec.js
+++ /dev/null
@@ -1,66 +0,0 @@
-describe('Home e2e Test', function() {
-  /*Common methods for interact with elements*/
-  let clickOn = function(elem) {
-    browser.actions().mouseMove(elem).click().perform()
-  }
-
-  let sendKeysToInput = function(input, keys) {
-    cleanInput(input)
-    input.sendKeys(keys)
-  }
-
-  let cleanInput = function(inputElem) {
-    inputElem.sendKeys(protractor.Key.chord(protractor.Key.CONTROL, "a"))
-    inputElem.sendKeys(protractor.Key.BACK_SPACE)
-  }
-
-  let scrollToElementAndClick = function(elem) {
-    browser.executeScript("arguments[0].scrollIntoView(false);", 
elem.getWebElement())
-    browser.sleep(300)
-    clickOn(elem)
-  }
-
-  //tests
-  it('should have a welcome message', function() {
-    browser.get('http://localhost:8080/classic');
-    browser.sleep(500);
-    var welcomeElem = element(by.id('welcome'))
-
-    expect(welcomeElem.getText()).toEqual('Welcome to Zeppelin!')
-  })
-
-  it('should have the button for importing notebook', function() {
-    var btn = element(by.cssContainingText('a', 'Import note'))
-    expect(btn.isPresent()).toBe(true)
-  })
-
-  it('should have the button for creating notebook', function() {
-    var btn = element(by.cssContainingText('a', 'Create new note'))
-    expect(btn.isPresent()).toBe(true)
-  })
-
-  it('correct save permission in interpreter', function() {
-    var ownerName = 'admin'
-    var interpreterName = 'interpreter_e2e_test'
-    clickOn(element(by.xpath('//span[@class="username ng-binding"]')))
-    clickOn(element(by.xpath('//a[@href="#/interpreter"]')))
-    clickOn(element(by.xpath('//button[@ng-click="showAddNewSetting = 
!showAddNewSetting"]')))
-    
sendKeysToInput(element(by.xpath('//input[@id="newInterpreterSettingName"]')), 
interpreterName)
-    
clickOn(element(by.xpath('//select[@ng-model="newInterpreterSetting.group"]')))
-    browser.sleep(500)
-    browser.actions().sendKeys('angular').perform()
-    
clickOn(element(by.xpath('//div[@ng-show="showAddNewSetting"]//input[@id="idShowPermission"]')))
-    
sendKeysToInput(element(by.xpath('//div[@ng-show="showAddNewSetting"]//input[@class="select2-search__field"]')),
 ownerName)
-    browser.sleep(500)
-    browser.actions().sendKeys(protractor.Key.ENTER).perform()
-    
scrollToElementAndClick(element(by.xpath('//span[@ng-click="addNewInterpreterSetting()"]')))
-    scrollToElementAndClick(element(by.xpath('//*[@id="' + interpreterName + 
'"]//span[@class="fa fa-pencil"]')))
-    scrollToElementAndClick(element(by.xpath('//*[@id="' + interpreterName + 
'"]//button[@type="submit"]')))
-    
clickOn(element(by.xpath('//div[@class="bootstrap-dialog-footer-buttons"]//button[contains(text(),
 \'OK\')]')))
-    browser.get('http://localhost:8080/classic/#/interpreter');
-    var text = element(by.xpath('//*[@id="' + interpreterName + 
'"]//li[contains(text(), \'admin\')]')).getText()
-    scrollToElementAndClick(element(by.xpath('//*[@id="' + interpreterName + 
'"]//span//span[@class="fa fa-trash"]')))
-    
clickOn(element(by.xpath('//div[@class="bootstrap-dialog-footer-buttons"]//button[contains(text(),
 \'OK\')]')))
-    expect(text).toEqual(ownerName);
-  })
-})
diff --git a/zeppelin-web/e2e/searchBlock.spec.js 
b/zeppelin-web/e2e/searchBlock.spec.js
deleted file mode 100644
index af59f42c0d..0000000000
--- a/zeppelin-web/e2e/searchBlock.spec.js
+++ /dev/null
@@ -1,207 +0,0 @@
-describe('Search block e2e Test', function() {
-  let testData = {
-    textInFirstP: 'text word text',
-    textInSecondP: 'text tete tt'
-  }
-
-  /*Common methods for interact with elements*/
-  let clickOn = function(elem) {
-    browser.actions().mouseMove(elem).click().perform()
-  }
-
-  let clickAndWait = function(elem){
-    clickOn(elem)
-    browser.sleep(60);
-  }
-
-  let waitVisibility = function(elem) {
-    browser.wait(protractor.ExpectedConditions.visibilityOf(elem))
-  }
-
-  beforeEach(function() {
-    browser.get('http://localhost:8080/classic')
-    browser.sleep(500);
-    waitVisibility(element(by.linkText('Create new note')))
-    clickOn(element(by.linkText('Create new note')))
-    waitVisibility(element(by.id('noteCreateModal')))
-    clickAndWait(element(by.id('createNoteButton')))
-  })
-
-  afterEach(function() {
-    
clickOn(element(by.xpath('//*[@id="main"]//button[@ng-click="moveNoteToTrash(note.id)"]')))
-    let moveToTrashDialogPath =
-      '//div[@class="modal-dialog"][contains(.,"This note will be moved to 
trash")]'
-    waitVisibility(element(by.xpath(moveToTrashDialogPath)))
-    let okButton = element(
-      by.xpath(moveToTrashDialogPath + 
'//div[@class="modal-footer"]//button[contains(.,"OK")]'))
-    clickOn(okButton)
-  })
-
-  /*Getting elements*/
-  let getFindInput = function() {
-    return element(by.id('findInput'))
-  }
-
-  let getReplaceInput = function() {
-    return element(
-      by.xpath('//div[contains(@class, 
"search-group")]//span[text()="Replace"]//..//input'))
-  }
-
-  let getNextOccurrenceButton = function() {
-    return element(by.xpath('//div[contains(@class, "search-group")]' +
-      '/div/button[@ng-click="nextOccurrence()"]'))
-  }
-
-  let getPrevOccurrenceButton = function() {
-    return element(by.xpath('//div[contains(@class, "search-group")]' +
-      '/div/button[@ng-click="prevOccurrence()"]'))
-  }
-
-  let getReplaceButton = function() {
-    return element(by.xpath('//div[contains(@class, 
"search-group")]//button[@ng-click="replace()"]'))
-  }
-
-  let getReplaceAllButton = function() {
-    return element(
-      by.xpath('//div[contains(@class, 
"search-group")]//button[@ng-click="replaceAll()"]'))
-  }
-
-  let getMatchesElement = function() {
-    return element(by.xpath('//div[contains(@class, "search-group")]' +
-      '//span[contains(@class, "after-input")]'))
-  }
-
-  /*Require: focus on any paragraph editor*/
-  let openSearchBoxByShortcut = function() {
-    
browser.switchTo().activeElement().sendKeys(protractor.Key.chord(protractor.Key.CONTROL,
-      protractor.Key.ALT, "f"))
-  }
-
-  let countSubstringOccurrence = function(s, subs) {
-    return (s.match(new RegExp(subs,"g")) || []).length
-  }
-
-  let cleanInput = function(inputElem) {
-    inputElem.sendKeys(protractor.Key.chord(protractor.Key.CONTROL, "a"))
-    inputElem.sendKeys(protractor.Key.BACK_SPACE)
-  }
-
-  let checkFind = function(findInput, text, expectedMatchesCount) {
-    cleanInput(findInput)
-    findInput.sendKeys(text)
-    let matchesCount = element(by.xpath('//div[contains(@class, 
"search-group")]' +
-      '//span[contains(@class, "after-input")]'))
-    matchesCount.getText().then(function(text) {
-    expect(text.indexOf((expectedMatchesCount === 0 ? 0 : 1) + ' of ' +
-      expectedMatchesCount) !== -1).toBe(true)
-    })
-  }
-
-  let makeTestParagraphs = function() {
-    waitVisibility(element(by.repeater('currentParagraph in note.paragraphs')))
-    browser.switchTo().activeElement().sendKeys(testData.textInFirstP)
-    let addBelow = element(
-      by.xpath('//div[@class="new-paragraph last-paragraph" and 
@ng-click="insertNew(\'below\');"]'))
-    clickAndWait(addBelow)
-    browser.switchTo().activeElement().sendKeys(testData.textInSecondP)
-  }
-
-  let checkMatchesElement = function(elem, current, amount) {
-    elem.getText().then(function(text) {
-      expect(text.indexOf(current + ' of ' + amount) !== -1).toBe(true)})
-  }
-
-  let sendKeysToInput = function(input, keys) {
-    cleanInput(input)
-    input.sendKeys(keys)
-  }
-
-  let sendKeysToFindInput = function(keys) {
-    sendKeysToInput(getFindInput(), keys)
-  }
-
-  let sendKeysToReplaceInput = function(keys) {
-    sendKeysToInput(getReplaceInput(), keys)
-  }
-
-  /*Tests*/
-  it('shortcut works', function() {
-    waitVisibility(element(by.repeater('currentParagraph in note.paragraphs')))
-    openSearchBoxByShortcut()
-    
expect(element(by.xpath('//ul[contains(@class,"search-dropdown")]')).isDisplayed()).toBeTruthy()
-  })
-
-  it('correct count of selections', function() {
-    makeTestParagraphs()
-    openSearchBoxByShortcut()
-    let subs = 'te'
-    sendKeysToFindInput(subs)
-    var markers = 
element.all(by.xpath('//code-editor/div/div[@class="ace_scroller"]' +
-      '/div[@class="ace_content"]/div[@class="ace_layer 
ace_marker-layer"]/div'))
-    
expect(markers.count()).toEqual(countSubstringOccurrence(testData.textInFirstP, 
subs) +
-      countSubstringOccurrence(testData.textInSecondP, subs) + 1)
-  })
-
-  it('correct matches count number', function() {
-    makeTestParagraphs()
-    openSearchBoxByShortcut()
-    let findInput = getFindInput()
-    clickAndWait(findInput)
-    let subs = 't';
-    checkFind(findInput, subs, countSubstringOccurrence(testData.textInFirstP, 
subs) +
-      countSubstringOccurrence(testData.textInSecondP, subs))
-    subs = 'te';
-    checkFind(findInput, subs, countSubstringOccurrence(testData.textInFirstP, 
subs) +
-      countSubstringOccurrence(testData.textInSecondP, subs))
-  })
-
-  it('counter increase and decrease correctly', function() {
-    makeTestParagraphs()
-    openSearchBoxByShortcut()
-    let subs = 'te'
-    sendKeysToFindInput(subs)
-    let matchesElement = getMatchesElement()
-    let matchesCount = countSubstringOccurrence(testData.textInFirstP, subs) +
-      countSubstringOccurrence(testData.textInSecondP, subs)
-    checkMatchesElement(matchesElement, matchesCount > 0 ? 1 : 0, matchesCount)
-    let nextOccurrenceButton = getNextOccurrenceButton()
-    let prevOccurrenceButton = getPrevOccurrenceButton()
-    clickOn(nextOccurrenceButton)
-    checkMatchesElement(matchesElement, matchesCount > 1 ? 2 : 1, matchesCount)
-    clickOn(prevOccurrenceButton)
-    checkMatchesElement(matchesElement, 1, matchesCount)
-    clickOn(prevOccurrenceButton)
-    checkMatchesElement(matchesElement, matchesCount, matchesCount)
-  })
-
-  it('matches count changes correctly after replace', function() {
-    makeTestParagraphs()
-    openSearchBoxByShortcut()
-    let textToFind = 'te'
-    sendKeysToFindInput(textToFind)
-    let matchesElement = getMatchesElement()
-    let matchesCount = countSubstringOccurrence(testData.textInFirstP, 
textToFind) +
-      countSubstringOccurrence(testData.textInSecondP, textToFind)
-    sendKeysToReplaceInput('ABC')
-    let replaceButton = getReplaceButton()
-    clickOn(replaceButton)
-    checkMatchesElement(matchesElement, 1, matchesCount - 1)
-    clickOn(getPrevOccurrenceButton())
-    clickOn(replaceButton)
-    checkMatchesElement(matchesElement, 1, matchesCount - 2)
-  })
-
-  it('replace all works correctly', function() {
-    makeTestParagraphs()
-    openSearchBoxByShortcut()
-    let textToFind = 'te'
-    sendKeysToFindInput(textToFind)
-    let matchesElement = getMatchesElement()
-    let matchesCount = countSubstringOccurrence(testData.textInFirstP, 
textToFind) +
-      countSubstringOccurrence(testData.textInSecondP, textToFind)
-    sendKeysToReplaceInput('ABC')
-    let replaceAllButton = getReplaceAllButton()
-    clickOn(replaceAllButton)
-    checkMatchesElement(matchesElement, 0, 0)
-  })
-})
diff --git a/zeppelin-web/package-lock.json b/zeppelin-web/package-lock.json
index 5c97c38309..19a8f4b58b 100644
--- a/zeppelin-web/package-lock.json
+++ b/zeppelin-web/package-lock.json
@@ -115,7 +115,6 @@
         "ng-annotate-loader": "^0.2.0",
         "npm-run-all": "^4.1.5",
         "postcss-loader": "^3.0.0",
-        "protractor": "^5.4.1",
         "raw-loader": "^0.5.1",
         "rimraf": "^3.0.2",
         "string-replace-webpack-plugin": "^0.1.3",
@@ -258,12 +257,6 @@
         "@types/node": "*"
       }
     },
-    "node_modules/@types/q": {
-      "version": "0.0.32",
-      "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz";,
-      "integrity": 
"sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==",
-      "dev": true
-    },
     "node_modules/@types/qs": {
       "version": "6.9.15",
       "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz";,
@@ -282,12 +275,6 @@
       "integrity": 
"sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
       "dev": true
     },
-    "node_modules/@types/selenium-webdriver": {
-      "version": "3.0.26",
-      "resolved": 
"https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz";,
-      "integrity": 
"sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==",
-      "dev": true
-    },
     "node_modules/@types/send": {
       "version": "0.17.4",
       "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz";,
@@ -615,33 +602,12 @@
         "node": ">=0.4.0"
       }
     },
-    "node_modules/adm-zip": {
-      "version": "0.5.15",
-      "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.15.tgz";,
-      "integrity": 
"sha512-jYPWSeOA8EFoZnucrKCNihqBjoEGQSU4HKgHYQgKNEQ0pQF9a/DYuo/+fAxY76k4qe75LUlLWpAM1QWcBMTOKw==",
-      "dev": true,
-      "engines": {
-        "node": ">=12.0"
-      }
-    },
     "node_modules/after": {
       "version": "0.8.2",
       "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz";,
       "integrity": 
"sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==",
       "dev": true
     },
-    "node_modules/agent-base": {
-      "version": "4.3.0",
-      "resolved": 
"https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz";,
-      "integrity": 
"sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
-      "dev": true,
-      "dependencies": {
-        "es6-promisify": "^5.0.0"
-      },
-      "engines": {
-        "node": ">= 4.0.0"
-      }
-    },
     "node_modules/ajv": {
       "version": "6.12.6",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz";,
@@ -1243,24 +1209,6 @@
       "integrity": 
"sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
       "dev": true
     },
-    "node_modules/arrify": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz";,
-      "integrity": 
"sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/asn1": {
-      "version": "0.2.6",
-      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz";,
-      "integrity": 
"sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
-      "dev": true,
-      "dependencies": {
-        "safer-buffer": "~2.1.0"
-      }
-    },
     "node_modules/asn1.js": {
       "version": "4.10.1",
       "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz";,
@@ -1288,15 +1236,6 @@
         "util": "^0.10.4"
       }
     },
-    "node_modules/assert-plus": {
-      "version": "1.0.0",
-      "resolved": 
"https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz";,
-      "integrity": 
"sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.8"
-      }
-    },
     "node_modules/assert/node_modules/inherits": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz";,
@@ -1347,12 +1286,6 @@
       "integrity": 
"sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
       "dev": true
     },
-    "node_modules/asynckit": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz";,
-      "integrity": 
"sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
-      "dev": true
-    },
     "node_modules/atob": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz";,
@@ -1394,21 +1327,6 @@
         "url": "https://github.com/sponsors/ljharb";
       }
     },
-    "node_modules/aws-sign2": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz";,
-      "integrity": 
"sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
-      "dev": true,
-      "engines": {
-        "node": "*"
-      }
-    },
-    "node_modules/aws4": {
-      "version": "1.13.1",
-      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz";,
-      "integrity": 
"sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==",
-      "dev": true
-    },
     "node_modules/babel-cli": {
       "version": "6.26.0",
       "resolved": 
"https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz";,
@@ -2263,15 +2181,6 @@
       "integrity": 
"sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==",
       "dev": true
     },
-    "node_modules/bcrypt-pbkdf": {
-      "version": "1.0.2",
-      "resolved": 
"https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz";,
-      "integrity": 
"sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
-      "dev": true,
-      "dependencies": {
-        "tweetnacl": "^0.14.3"
-      }
-    },
     "node_modules/better-assert": {
       "version": "1.0.2",
       "resolved": 
"https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz";,
@@ -2318,21 +2227,6 @@
       "integrity": 
"sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==",
       "dev": true
     },
-    "node_modules/blocking-proxy": {
-      "version": "1.0.1",
-      "resolved": 
"https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz";,
-      "integrity": 
"sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==",
-      "dev": true,
-      "dependencies": {
-        "minimist": "^1.2.0"
-      },
-      "bin": {
-        "blocking-proxy": "built/lib/bin.js"
-      },
-      "engines": {
-        "node": ">=6.9.x"
-      }
-    },
     "node_modules/bluebird": {
       "version": "3.7.2",
       "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz";,
@@ -2516,15 +2410,6 @@
         "browserslist": "cli.js"
       }
     },
-    "node_modules/browserstack": {
-      "version": "1.6.1",
-      "resolved": 
"https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz";,
-      "integrity": 
"sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==",
-      "dev": true,
-      "dependencies": {
-        "https-proxy-agent": "^2.2.1"
-      }
-    },
     "node_modules/buffer": {
       "version": "4.9.2",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz";,
@@ -2741,15 +2626,6 @@
         "upper-case": "^1.1.1"
       }
     },
-    "node_modules/camelcase": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz";,
-      "integrity": 
"sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-      "dev": true,
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/camelcase-keys": {
       "version": "2.1.0",
       "resolved": 
"https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz";,
@@ -2810,12 +2686,6 @@
         }
       ]
     },
-    "node_modules/caseless": {
-      "version": "0.12.0",
-      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz";,
-      "integrity": 
"sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==",
-      "dev": true
-    },
     "node_modules/center-align": {
       "version": "0.1.3",
       "resolved": 
"https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz";,
@@ -3072,60 +2942,6 @@
         "tiny-emitter": "^1.0.0"
       }
     },
-    "node_modules/cliui": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz";,
-      "integrity": 
"sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==",
-      "dev": true,
-      "dependencies": {
-        "string-width": "^2.1.1",
-        "strip-ansi": "^4.0.0",
-        "wrap-ansi": "^2.0.0"
-      }
-    },
-    "node_modules/cliui/node_modules/ansi-regex": {
-      "version": "3.0.1",
-      "resolved": 
"https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz";,
-      "integrity": 
"sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
-      "dev": true,
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/cliui/node_modules/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": 
"sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
-      "dev": true,
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/cliui/node_modules/string-width": {
-      "version": "2.1.1",
-      "resolved": 
"https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz";,
-      "integrity": 
"sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
-      "dev": true,
-      "dependencies": {
-        "is-fullwidth-code-point": "^2.0.0",
-        "strip-ansi": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/cliui/node_modules/strip-ansi": {
-      "version": "4.0.0",
-      "resolved": 
"https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz";,
-      "integrity": 
"sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==",
-      "dev": true,
-      "dependencies": {
-        "ansi-regex": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
     "node_modules/clone": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz";,
@@ -3292,18 +3108,6 @@
       "integrity": 
"sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
       "dev": true
     },
-    "node_modules/combined-stream": {
-      "version": "1.0.8",
-      "resolved": 
"https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz";,
-      "integrity": 
"sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
-      "dev": true,
-      "dependencies": {
-        "delayed-stream": "~1.0.0"
-      },
-      "engines": {
-        "node": ">= 0.8"
-      }
-    },
     "node_modules/commander": {
       "version": "2.20.3",
       "resolved": 
"https://registry.npmjs.org/commander/-/commander-2.20.3.tgz";,
@@ -3943,18 +3747,6 @@
       "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz";,
       "integrity": 
"sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg=="
     },
-    "node_modules/dashdash": {
-      "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz";,
-      "integrity": 
"sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
-      "dev": true,
-      "dependencies": {
-        "assert-plus": "^1.0.0"
-      },
-      "engines": {
-        "node": ">=0.10"
-      }
-    },
     "node_modules/data-view-buffer": {
       "version": "1.0.1",
       "resolved": 
"https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz";,
@@ -4280,72 +4072,6 @@
         "url": "https://github.com/sponsors/ljharb";
       }
     },
-    "node_modules/del": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz";,
-      "integrity": 
"sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==",
-      "dev": true,
-      "dependencies": {
-        "globby": "^5.0.0",
-        "is-path-cwd": "^1.0.0",
-        "is-path-in-cwd": "^1.0.0",
-        "object-assign": "^4.0.1",
-        "pify": "^2.0.0",
-        "pinkie-promise": "^2.0.0",
-        "rimraf": "^2.2.8"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/del/node_modules/globby": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz";,
-      "integrity": 
"sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==",
-      "dev": true,
-      "dependencies": {
-        "array-union": "^1.0.1",
-        "arrify": "^1.0.0",
-        "glob": "^7.0.3",
-        "object-assign": "^4.0.1",
-        "pify": "^2.0.0",
-        "pinkie-promise": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/del/node_modules/pify": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz";,
-      "integrity": 
"sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/del/node_modules/rimraf": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz";,
-      "integrity": 
"sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
-      "deprecated": "Rimraf versions prior to v4 are no longer supported",
-      "dev": true,
-      "dependencies": {
-        "glob": "^7.1.3"
-      },
-      "bin": {
-        "rimraf": "bin.js"
-      }
-    },
-    "node_modules/delayed-stream": {
-      "version": "1.0.0",
-      "resolved": 
"https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz";,
-      "integrity": 
"sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.4.0"
-      }
-    },
     "node_modules/delegate": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz";,
@@ -4592,16 +4318,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/ecc-jsbn": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz";,
-      "integrity": 
"sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
-      "dev": true,
-      "dependencies": {
-        "jsbn": "~0.1.0",
-        "safer-buffer": "^2.1.0"
-      }
-    },
     "node_modules/ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz";,
@@ -5047,21 +4763,6 @@
         "event-emitter": "~0.3.5"
       }
     },
-    "node_modules/es6-promisify": {
-      "version": "5.0.0",
-      "resolved": 
"https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz";,
-      "integrity": 
"sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==",
-      "dev": true,
-      "dependencies": {
-        "es6-promise": "^4.0.3"
-      }
-    },
-    "node_modules/es6-promisify/node_modules/es6-promise": {
-      "version": "4.2.8",
-      "resolved": 
"https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz";,
-      "integrity": 
"sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
-      "dev": true
-    },
     "node_modules/es6-set": {
       "version": "0.1.6",
       "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz";,
@@ -6037,24 +5738,6 @@
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz";,
       "integrity": 
"sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ=="
     },
-    "node_modules/execa": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz";,
-      "integrity": 
"sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
-      "dev": true,
-      "dependencies": {
-        "cross-spawn": "^6.0.0",
-        "get-stream": "^4.0.0",
-        "is-stream": "^1.1.0",
-        "npm-run-path": "^2.0.0",
-        "p-finally": "^1.0.0",
-        "signal-exit": "^3.0.0",
-        "strip-eof": "^1.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/exit": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz";,
@@ -6194,15 +5877,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/extsprintf": {
-      "version": "1.3.0",
-      "resolved": 
"https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz";,
-      "integrity": 
"sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==",
-      "dev": true,
-      "engines": [
-        "node >=0.6.0"
-      ]
-    },
     "node_modules/fast-deep-equal": {
       "version": "3.1.3",
       "resolved": 
"https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz";,
@@ -6577,29 +6251,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/forever-agent": {
-      "version": "0.6.1",
-      "resolved": 
"https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz";,
-      "integrity": 
"sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
-      "dev": true,
-      "engines": {
-        "node": "*"
-      }
-    },
-    "node_modules/form-data": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz";,
-      "integrity": 
"sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
-      "dev": true,
-      "dependencies": {
-        "asynckit": "^0.4.0",
-        "combined-stream": "^1.0.6",
-        "mime-types": "^2.1.12"
-      },
-      "engines": {
-        "node": ">= 0.12"
-      }
-    },
     "node_modules/forwarded": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz";,
@@ -6755,12 +6406,6 @@
         "is-property": "^1.0.0"
       }
     },
-    "node_modules/get-caller-file": {
-      "version": "1.0.3",
-      "resolved": 
"https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz";,
-      "integrity": 
"sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
-      "dev": true
-    },
     "node_modules/get-intrinsic": {
       "version": "1.2.4",
       "resolved": 
"https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz";,
@@ -6789,28 +6434,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/get-stream": {
-      "version": "4.1.0",
-      "resolved": 
"https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz";,
-      "integrity": 
"sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
-      "dev": true,
-      "dependencies": {
-        "pump": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/get-stream/node_modules/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,
-      "dependencies": {
-        "end-of-stream": "^1.1.0",
-        "once": "^1.3.1"
-      }
-    },
     "node_modules/get-symbol-description": {
       "version": "1.0.2",
       "resolved": 
"https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz";,
@@ -6845,15 +6468,6 @@
         "node": ">= 0.8.0"
       }
     },
-    "node_modules/getpass": {
-      "version": "0.1.7",
-      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz";,
-      "integrity": 
"sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
-      "dev": true,
-      "dependencies": {
-        "assert-plus": "^1.0.0"
-      }
-    },
     "node_modules/github-markdown-css": {
       "version": "2.6.0",
       "resolved": 
"https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-2.6.0.tgz";,
@@ -8062,36 +7676,13 @@
         "node": ">=0.8.0"
       }
     },
-    "node_modules/har-schema": {
-      "version": "2.0.0",
-      "resolved": 
"https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz";,
-      "integrity": 
"sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==",
+    "node_modules/has": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz";,
+      "integrity": 
"sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==",
       "dev": true,
       "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/har-validator": {
-      "version": "5.1.5",
-      "resolved": 
"https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz";,
-      "integrity": 
"sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
-      "deprecated": "this library is no longer supported",
-      "dev": true,
-      "dependencies": {
-        "ajv": "^6.12.3",
-        "har-schema": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/has": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz";,
-      "integrity": 
"sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==",
-      "dev": true,
-      "engines": {
-        "node": ">= 0.4.0"
+        "node": ">= 0.4.0"
       }
     },
     "node_modules/has-ansi": {
@@ -8928,55 +8519,12 @@
         "node": ">=8.0"
       }
     },
-    "node_modules/http-signature": {
-      "version": "1.2.0",
-      "resolved": 
"https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz";,
-      "integrity": 
"sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
-      "dev": true,
-      "dependencies": {
-        "assert-plus": "^1.0.0",
-        "jsprim": "^1.2.2",
-        "sshpk": "^1.7.0"
-      },
-      "engines": {
-        "node": ">=0.8",
-        "npm": ">=1.3.7"
-      }
-    },
     "node_modules/https-browserify": {
       "version": "1.0.0",
       "resolved": 
"https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz";,
       "integrity": 
"sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==",
       "dev": true
     },
-    "node_modules/https-proxy-agent": {
-      "version": "2.2.4",
-      "resolved": 
"https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz";,
-      "integrity": 
"sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
-      "dev": true,
-      "dependencies": {
-        "agent-base": "^4.3.0",
-        "debug": "^3.1.0"
-      },
-      "engines": {
-        "node": ">= 4.5.0"
-      }
-    },
-    "node_modules/https-proxy-agent/node_modules/debug": {
-      "version": "3.2.7",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz";,
-      "integrity": 
"sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-      "dev": true,
-      "dependencies": {
-        "ms": "^2.1.1"
-      }
-    },
-    "node_modules/https-proxy-agent/node_modules/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
-    },
     "node_modules/human-signals": {
       "version": "2.1.0",
       "resolved": 
"https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz";,
@@ -9036,12 +8584,6 @@
       "integrity": 
"sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
       "dev": true
     },
-    "node_modules/immediate": {
-      "version": "3.0.6",
-      "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz";,
-      "integrity": 
"sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
-      "dev": true
-    },
     "node_modules/import-cwd": {
       "version": "2.1.0",
       "resolved": 
"https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz";,
@@ -9257,12 +8799,6 @@
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz";,
       "integrity": 
"sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
     },
-    "node_modules/ini": {
-      "version": "1.3.8",
-      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz";,
-      "integrity": 
"sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
-      "dev": true
-    },
     "node_modules/inquirer": {
       "version": "0.12.0",
       "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz";,
@@ -9322,15 +8858,6 @@
         "loose-envify": "^1.0.0"
       }
     },
-    "node_modules/invert-kv": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz";,
-      "integrity": 
"sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
-      "dev": true,
-      "engines": {
-        "node": ">=4"
-      }
-    },
     "node_modules/ipaddr.js": {
       "version": "1.9.1",
       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz";,
@@ -9674,39 +9201,6 @@
         "url": "https://github.com/sponsors/ljharb";
       }
     },
-    "node_modules/is-path-cwd": {
-      "version": "1.0.0",
-      "resolved": 
"https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz";,
-      "integrity": 
"sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/is-path-in-cwd": {
-      "version": "1.0.1",
-      "resolved": 
"https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz";,
-      "integrity": 
"sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
-      "dev": true,
-      "dependencies": {
-        "is-path-inside": "^1.0.0"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/is-path-inside": {
-      "version": "1.0.1",
-      "resolved": 
"https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz";,
-      "integrity": 
"sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==",
-      "dev": true,
-      "dependencies": {
-        "path-is-inside": "^1.0.1"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/is-plain-obj": {
       "version": "1.1.0",
       "resolved": 
"https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz";,
@@ -9791,15 +9285,6 @@
         "url": "https://github.com/sponsors/ljharb";
       }
     },
-    "node_modules/is-stream": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz";,
-      "integrity": 
"sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/is-string": {
       "version": "1.0.7",
       "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz";,
@@ -9857,12 +9342,6 @@
         "url": "https://github.com/sponsors/ljharb";
       }
     },
-    "node_modules/is-typedarray": {
-      "version": "1.0.0",
-      "resolved": 
"https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz";,
-      "integrity": 
"sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==",
-      "dev": true
-    },
     "node_modules/is-upper-case": {
       "version": "1.1.2",
       "resolved": 
"https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz";,
@@ -9943,12 +9422,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/isstream": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz";,
-      "integrity": 
"sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
-      "dev": true
-    },
     "node_modules/istanbul": {
       "version": "0.4.5",
       "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz";,
@@ -10093,20 +9566,6 @@
         "which": "bin/which"
       }
     },
-    "node_modules/jasmine": {
-      "version": "2.8.0",
-      "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz";,
-      "integrity": 
"sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==",
-      "dev": true,
-      "dependencies": {
-        "exit": "^0.1.2",
-        "glob": "^7.0.6",
-        "jasmine-core": "~2.8.0"
-      },
-      "bin": {
-        "jasmine": "bin/jasmine.js"
-      }
-    },
     "node_modules/jasmine-core": {
       "version": "3.99.1",
       "resolved": 
"https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.99.1.tgz";,
@@ -10131,21 +9590,6 @@
         "node": ">=0.1.90"
       }
     },
-    "node_modules/jasmine/node_modules/jasmine-core": {
-      "version": "2.8.0",
-      "resolved": 
"https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz";,
-      "integrity": 
"sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==",
-      "dev": true
-    },
-    "node_modules/jasminewd2": {
-      "version": "2.2.0",
-      "resolved": 
"https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz";,
-      "integrity": 
"sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==",
-      "dev": true,
-      "engines": {
-        "node": ">= 6.9.x"
-      }
-    },
     "node_modules/jquery": {
       "version": "3.7.1",
       "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz";,
@@ -10205,12 +9649,6 @@
         "node": ">=4"
       }
     },
-    "node_modules/jsbn": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz";,
-      "integrity": 
"sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==",
-      "dev": true
-    },
     "node_modules/jsesc": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz";,
@@ -10387,12 +9825,6 @@
       "integrity": 
"sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
       "dev": true
     },
-    "node_modules/json-schema": {
-      "version": "0.4.0",
-      "resolved": 
"https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz";,
-      "integrity": 
"sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
-      "dev": true
-    },
     "node_modules/json-schema-traverse": {
       "version": "0.4.1",
       "resolved": 
"https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz";,
@@ -10417,12 +9849,6 @@
         "url": "https://github.com/sponsors/ljharb";
       }
     },
-    "node_modules/json-stringify-safe": {
-      "version": "5.0.1",
-      "resolved": 
"https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz";,
-      "integrity": 
"sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
-      "dev": true
-    },
     "node_modules/json3": {
       "version": "3.3.3",
       "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz";,
@@ -10455,21 +9881,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/jsprim": {
-      "version": "1.4.2",
-      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz";,
-      "integrity": 
"sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
-      "dev": true,
-      "dependencies": {
-        "assert-plus": "1.0.0",
-        "extsprintf": "1.3.0",
-        "json-schema": "0.4.0",
-        "verror": "1.10.0"
-      },
-      "engines": {
-        "node": ">=0.6.0"
-      }
-    },
     "node_modules/jszip": {
       "version": "2.6.1",
       "resolved": "https://registry.npmjs.org/jszip/-/jszip-2.6.1.tgz";,
@@ -11004,18 +10415,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/lcid": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz";,
-      "integrity": 
"sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
-      "dev": true,
-      "dependencies": {
-        "invert-kv": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/levn": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz";,
@@ -11029,15 +10428,6 @@
         "node": ">= 0.8.0"
       }
     },
-    "node_modules/lie": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz";,
-      "integrity": 
"sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
-      "dev": true,
-      "dependencies": {
-        "immediate": "~3.0.5"
-      }
-    },
     "node_modules/load-grunt-tasks": {
       "version": "0.4.0",
       "resolved": 
"https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-0.4.0.tgz";,
@@ -11339,18 +10729,6 @@
         "node": ">=4"
       }
     },
-    "node_modules/map-age-cleaner": {
-      "version": "0.1.3",
-      "resolved": 
"https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz";,
-      "integrity": 
"sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
-      "dev": true,
-      "dependencies": {
-        "p-defer": "^1.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/map-cache": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz";,
@@ -11469,20 +10847,6 @@
         "node": ">= 0.6"
       }
     },
-    "node_modules/mem": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz";,
-      "integrity": 
"sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
-      "dev": true,
-      "dependencies": {
-        "map-age-cleaner": "^0.1.1",
-        "mimic-fn": "^2.0.0",
-        "p-is-promise": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/memfs": {
       "version": "3.5.3",
       "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz";,
@@ -12284,11 +11648,10 @@
       }
     },
     "node_modules/node-gyp-build": {
-      "version": "4.8.1",
-      "resolved": 
"https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz";,
-      "integrity": 
"sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==",
+      "version": "4.8.4",
+      "resolved": 
"https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz";,
+      "integrity": 
"sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
       "dev": true,
-      "license": "MIT",
       "optional": true,
       "peer": true,
       "bin": {
@@ -12472,18 +11835,6 @@
         "node": ">=4"
       }
     },
-    "node_modules/npm-run-path": {
-      "version": "2.0.2",
-      "resolved": 
"https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz";,
-      "integrity": 
"sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==",
-      "dev": true,
-      "dependencies": {
-        "path-key": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
     "node_modules/nth-check": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz";,
@@ -12518,15 +11869,6 @@
         "d3": "^3.4.4"
       }
     },
-    "node_modules/oauth-sign": {
-      "version": "0.9.0",
-      "resolved": 
"https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz";,
-      "integrity": 
"sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
-      "dev": true,
-      "engines": {
-        "node": "*"
-      }
-    },
     "node_modules/object-assign": {
       "version": "4.1.1",
       "resolved": 
"https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz";,
@@ -12857,20 +12199,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/os-locale": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz";,
-      "integrity": 
"sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
-      "dev": true,
-      "dependencies": {
-        "execa": "^1.0.0",
-        "lcid": "^2.0.0",
-        "mem": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/os-tmpdir": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz";,
@@ -12891,33 +12219,6 @@
         "object-assign": "^4.1.0"
       }
     },
-    "node_modules/p-defer": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz";,
-      "integrity": 
"sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==",
-      "dev": true,
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/p-finally": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz";,
-      "integrity": 
"sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
-      "dev": true,
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/p-is-promise": {
-      "version": "2.1.0",
-      "resolved": 
"https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz";,
-      "integrity": 
"sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
-      "dev": true,
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/p-limit": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz";,
@@ -13197,12 +12498,6 @@
         "node": ">= 0.8.0"
       }
     },
-    "node_modules/performance-now": {
-      "version": "2.1.0",
-      "resolved": 
"https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz";,
-      "integrity": 
"sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
-      "dev": true
-    },
     "node_modules/picocolors": {
       "version": "0.2.1",
       "resolved": 
"https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz";,
@@ -14128,48 +13423,6 @@
       "integrity": 
"sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==",
       "dev": true
     },
-    "node_modules/protractor": {
-      "version": "5.4.4",
-      "resolved": 
"https://registry.npmjs.org/protractor/-/protractor-5.4.4.tgz";,
-      "integrity": 
"sha512-BaL4vePgu3Vfa/whvTUAlgaCAId4uNSGxIFSCXMgj7LMYENPWLp85h5RBi9pdpX/bWQ8SF6flP7afmi2TC4eHw==",
-      "deprecated": "We have news to share - Protractor is deprecated and will 
reach end-of-life by Summer 2023. To learn more and find out about other 
options please refer to this post on the Angular blog. Thank you for using and 
contributing to Protractor. https://goo.gle/state-of-e2e-in-angular";,
-      "dev": true,
-      "dependencies": {
-        "@types/q": "^0.0.32",
-        "@types/selenium-webdriver": "^3.0.0",
-        "blocking-proxy": "^1.0.0",
-        "browserstack": "^1.5.1",
-        "chalk": "^1.1.3",
-        "glob": "^7.0.3",
-        "jasmine": "2.8.0",
-        "jasminewd2": "^2.1.0",
-        "q": "1.4.1",
-        "saucelabs": "^1.5.0",
-        "selenium-webdriver": "3.6.0",
-        "source-map-support": "~0.4.0",
-        "webdriver-js-extender": "2.1.0",
-        "webdriver-manager": "^12.0.6",
-        "yargs": "^12.0.5"
-      },
-      "bin": {
-        "protractor": "bin/protractor",
-        "webdriver-manager": "bin/webdriver-manager"
-      },
-      "engines": {
-        "node": ">=6.9.x"
-      }
-    },
-    "node_modules/protractor/node_modules/q": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz";,
-      "integrity": 
"sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==",
-      "deprecated": "You or someone you depend on is using Q, the JavaScript 
Promise library that gave JavaScript developers strong feelings about promises. 
They can almost certainly migrate to the native JavaScript promise now. Thank 
you literally everyone for joining me in this bet against the odds. Be 
excellent to each other.\n\n(For a CapTP with native promises, see 
@endo/eventual-send and @endo/captp)",
-      "dev": true,
-      "engines": {
-        "node": ">=0.6.0",
-        "teleport": ">=0.2.0"
-      }
-    },
     "node_modules/proxy-addr": {
       "version": "2.0.7",
       "resolved": 
"https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz";,
@@ -14195,12 +13448,6 @@
       "integrity": 
"sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
       "dev": true
     },
-    "node_modules/psl": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz";,
-      "integrity": 
"sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
-      "dev": true
-    },
     "node_modules/public-encrypt": {
       "version": "4.0.3",
       "resolved": 
"https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz";,
@@ -15078,56 +14325,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/request": {
-      "version": "2.88.2",
-      "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz";,
-      "integrity": 
"sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
-      "deprecated": "request has been deprecated, see 
https://github.com/request/request/issues/3142";,
-      "dev": true,
-      "dependencies": {
-        "aws-sign2": "~0.7.0",
-        "aws4": "^1.8.0",
-        "caseless": "~0.12.0",
-        "combined-stream": "~1.0.6",
-        "extend": "~3.0.2",
-        "forever-agent": "~0.6.1",
-        "form-data": "~2.3.2",
-        "har-validator": "~5.1.3",
-        "http-signature": "~1.2.0",
-        "is-typedarray": "~1.0.0",
-        "isstream": "~0.1.2",
-        "json-stringify-safe": "~5.0.1",
-        "mime-types": "~2.1.19",
-        "oauth-sign": "~0.9.0",
-        "performance-now": "^2.1.0",
-        "qs": "~6.5.2",
-        "safe-buffer": "^5.1.2",
-        "tough-cookie": "~2.5.0",
-        "tunnel-agent": "^0.6.0",
-        "uuid": "^3.3.2"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/request/node_modules/qs": {
-      "version": "6.5.3",
-      "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz";,
-      "integrity": 
"sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.6"
-      }
-    },
-    "node_modules/require-directory": {
-      "version": "2.1.1",
-      "resolved": 
"https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz";,
-      "integrity": 
"sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/require-from-string": {
       "version": "2.0.2",
       "resolved": 
"https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz";,
@@ -15137,12 +14334,6 @@
         "node": ">=0.10.0"
       }
     },
-    "node_modules/require-main-filename": {
-      "version": "1.0.1",
-      "resolved": 
"https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz";,
-      "integrity": 
"sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==",
-      "dev": true
-    },
     "node_modules/require-uncached": {
       "version": "1.0.3",
       "resolved": 
"https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz";,
@@ -15415,18 +14606,6 @@
       "integrity": 
"sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
       "dev": true
     },
-    "node_modules/saucelabs": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz";,
-      "integrity": 
"sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==",
-      "dev": true,
-      "dependencies": {
-        "https-proxy-agent": "^2.2.1"
-      },
-      "engines": {
-        "node": "*"
-      }
-    },
     "node_modules/sax": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz";,
@@ -15468,58 +14647,6 @@
       "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.13.tgz";,
       "integrity": 
"sha512-1JeB87s6oN/TDxQQYCvS5EFoQyvV6eYMZZ0AeA4tdFDYWN3BAGZ8npr17UBFddU0lgAt3H0yjX3X6/ekOj1yjw=="
     },
-    "node_modules/selenium-webdriver": {
-      "version": "3.6.0",
-      "resolved": 
"https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz";,
-      "integrity": 
"sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==",
-      "dev": true,
-      "dependencies": {
-        "jszip": "^3.1.3",
-        "rimraf": "^2.5.4",
-        "tmp": "0.0.30",
-        "xml2js": "^0.4.17"
-      },
-      "engines": {
-        "node": ">= 6.9.0"
-      }
-    },
-    "node_modules/selenium-webdriver/node_modules/jszip": {
-      "version": "3.10.1",
-      "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz";,
-      "integrity": 
"sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
-      "dev": true,
-      "dependencies": {
-        "lie": "~3.3.0",
-        "pako": "~1.0.2",
-        "readable-stream": "~2.3.6",
-        "setimmediate": "^1.0.5"
-      }
-    },
-    "node_modules/selenium-webdriver/node_modules/rimraf": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz";,
-      "integrity": 
"sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
-      "deprecated": "Rimraf versions prior to v4 are no longer supported",
-      "dev": true,
-      "dependencies": {
-        "glob": "^7.1.3"
-      },
-      "bin": {
-        "rimraf": "bin.js"
-      }
-    },
-    "node_modules/selenium-webdriver/node_modules/tmp": {
-      "version": "0.0.30",
-      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz";,
-      "integrity": 
"sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==",
-      "dev": true,
-      "dependencies": {
-        "os-tmpdir": "~1.0.1"
-      },
-      "engines": {
-        "node": ">=0.4.0"
-      }
-    },
     "node_modules/selfsigned": {
       "version": "2.4.1",
       "resolved": 
"https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz";,
@@ -15685,12 +14812,6 @@
         "node": ">= 0.8.0"
       }
     },
-    "node_modules/set-blocking": {
-      "version": "2.0.0",
-      "resolved": 
"https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz";,
-      "integrity": 
"sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
-      "dev": true
-    },
     "node_modules/set-function-length": {
       "version": "1.2.2",
       "resolved": 
"https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz";,
@@ -16312,31 +15433,6 @@
       "integrity": 
"sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
       "dev": true
     },
-    "node_modules/sshpk": {
-      "version": "1.18.0",
-      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz";,
-      "integrity": 
"sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==",
-      "dev": true,
-      "dependencies": {
-        "asn1": "~0.2.3",
-        "assert-plus": "^1.0.0",
-        "bcrypt-pbkdf": "^1.0.0",
-        "dashdash": "^1.12.0",
-        "ecc-jsbn": "~0.1.1",
-        "getpass": "^0.1.1",
-        "jsbn": "~0.1.0",
-        "safer-buffer": "^2.0.2",
-        "tweetnacl": "~0.14.0"
-      },
-      "bin": {
-        "sshpk-conv": "bin/sshpk-conv",
-        "sshpk-sign": "bin/sshpk-sign",
-        "sshpk-verify": "bin/sshpk-verify"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/ssri": {
       "version": "5.3.0",
       "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz";,
@@ -16695,15 +15791,6 @@
         "node": ">=4"
       }
     },
-    "node_modules/strip-eof": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz";,
-      "integrity": 
"sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==",
-      "dev": true,
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/strip-final-newline": {
       "version": "2.0.0",
       "resolved": 
"https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz";,
@@ -17572,28 +16659,6 @@
       "integrity": 
"sha512-FclLrw8b9bMWf4QlCJuHBEVhSRsqDj6u3nIjAzPeJvgl//1hBlffdlk0MALceL14+koWEdU4ofRAXofbODxQzg==",
       "dev": true
     },
-    "node_modules/tough-cookie": {
-      "version": "2.5.0",
-      "resolved": 
"https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz";,
-      "integrity": 
"sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
-      "dev": true,
-      "dependencies": {
-        "psl": "^1.1.28",
-        "punycode": "^2.1.1"
-      },
-      "engines": {
-        "node": ">=0.8"
-      }
-    },
-    "node_modules/tough-cookie/node_modules/punycode": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz";,
-      "integrity": 
"sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
-      "dev": true,
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/trim-newlines": {
       "version": "1.0.0",
       "resolved": 
"https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz";,
@@ -17648,24 +16713,6 @@
       "integrity": 
"sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==",
       "dev": true
     },
-    "node_modules/tunnel-agent": {
-      "version": "0.6.0",
-      "resolved": 
"https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz";,
-      "integrity": 
"sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
-      "dev": true,
-      "dependencies": {
-        "safe-buffer": "^5.0.1"
-      },
-      "engines": {
-        "node": "*"
-      }
-    },
-    "node_modules/tweetnacl": {
-      "version": "0.14.5",
-      "resolved": 
"https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz";,
-      "integrity": 
"sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==",
-      "dev": true
-    },
     "node_modules/type": {
       "version": "2.7.3",
       "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz";,
@@ -18237,26 +17284,6 @@
         "url": "https://github.com/sponsors/wooorm";
       }
     },
-    "node_modules/verror": {
-      "version": "1.10.0",
-      "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz";,
-      "integrity": 
"sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
-      "dev": true,
-      "engines": [
-        "node >=0.6.0"
-      ],
-      "dependencies": {
-        "assert-plus": "^1.0.0",
-        "core-util-is": "1.0.2",
-        "extsprintf": "^1.2.0"
-      }
-    },
-    "node_modules/verror/node_modules/core-util-is": {
-      "version": "1.0.2",
-      "resolved": 
"https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz";,
-      "integrity": 
"sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
-      "dev": true
-    },
     "node_modules/vm-browserify": {
       "version": "1.1.2",
       "resolved": 
"https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz";,
@@ -18785,57 +17812,6 @@
         "minimalistic-assert": "^1.0.0"
       }
     },
-    "node_modules/webdriver-js-extender": {
-      "version": "2.1.0",
-      "resolved": 
"https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz";,
-      "integrity": 
"sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==",
-      "dev": true,
-      "dependencies": {
-        "@types/selenium-webdriver": "^3.0.0",
-        "selenium-webdriver": "^3.0.1"
-      },
-      "engines": {
-        "node": ">=6.9.x"
-      }
-    },
-    "node_modules/webdriver-manager": {
-      "version": "12.1.9",
-      "resolved": 
"https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz";,
-      "integrity": 
"sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==",
-      "dev": true,
-      "dependencies": {
-        "adm-zip": "^0.5.2",
-        "chalk": "^1.1.1",
-        "del": "^2.2.0",
-        "glob": "^7.0.3",
-        "ini": "^1.3.4",
-        "minimist": "^1.2.0",
-        "q": "^1.4.1",
-        "request": "^2.87.0",
-        "rimraf": "^2.5.2",
-        "semver": "^5.3.0",
-        "xml2js": "^0.4.17"
-      },
-      "bin": {
-        "webdriver-manager": "bin/webdriver-manager"
-      },
-      "engines": {
-        "node": ">=6.9.x"
-      }
-    },
-    "node_modules/webdriver-manager/node_modules/rimraf": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz";,
-      "integrity": 
"sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
-      "deprecated": "Rimraf versions prior to v4 are no longer supported",
-      "dev": true,
-      "dependencies": {
-        "glob": "^7.1.3"
-      },
-      "bin": {
-        "rimraf": "bin.js"
-      }
-    },
     "node_modules/webpack": {
       "version": "4.47.0",
       "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz";,
@@ -19165,12 +18141,11 @@
       }
     },
     "node_modules/webpack-dev-server/node_modules/bufferutil": {
-      "version": "4.0.8",
-      "resolved": 
"https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz";,
-      "integrity": 
"sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==",
+      "version": "4.1.0",
+      "resolved": 
"https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz";,
+      "integrity": 
"sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==",
       "dev": true,
       "hasInstallScript": true,
-      "license": "MIT",
       "optional": true,
       "peer": true,
       "dependencies": {
@@ -19352,12 +18327,11 @@
       }
     },
     "node_modules/webpack-dev-server/node_modules/utf-8-validate": {
-      "version": "6.0.4",
-      "resolved": 
"https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.4.tgz";,
-      "integrity": 
"sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==",
+      "version": "6.0.6",
+      "resolved": 
"https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.6.tgz";,
+      "integrity": 
"sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA==",
       "dev": true,
       "hasInstallScript": true,
-      "license": "MIT",
       "optional": true,
       "peer": true,
       "dependencies": {
@@ -19719,12 +18693,6 @@
         "url": "https://github.com/sponsors/ljharb";
       }
     },
-    "node_modules/which-module": {
-      "version": "2.0.1",
-      "resolved": 
"https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz";,
-      "integrity": 
"sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
-      "dev": true
-    },
     "node_modules/which-typed-array": {
       "version": "1.1.15",
       "resolved": 
"https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz";,
@@ -19782,19 +18750,6 @@
         "errno": "~0.1.7"
       }
     },
-    "node_modules/wrap-ansi": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz";,
-      "integrity": 
"sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==",
-      "dev": true,
-      "dependencies": {
-        "string-width": "^1.0.1",
-        "strip-ansi": "^3.0.1"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz";,
@@ -19833,28 +18788,6 @@
       "integrity": 
"sha512-NpTtJIGjrofxyTNuc497ZTI/LfhWMSTWbCnAQ8w7DZLgIwn7pWjHNcOhghCEPgzdrwXSZJNxh/dHjunId2jhNQ==",
       "dev": true
     },
-    "node_modules/xml2js": {
-      "version": "0.4.23",
-      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz";,
-      "integrity": 
"sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
-      "dev": true,
-      "dependencies": {
-        "sax": ">=0.6.0",
-        "xmlbuilder": "~11.0.0"
-      },
-      "engines": {
-        "node": ">=4.0.0"
-      }
-    },
-    "node_modules/xmlbuilder": {
-      "version": "11.0.1",
-      "resolved": 
"https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz";,
-      "integrity": 
"sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
-      "dev": true,
-      "engines": {
-        "node": ">=4.0"
-      }
-    },
     "node_modules/xmlhttprequest-ssl": {
       "version": "1.5.5",
       "resolved": 
"https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz";,
@@ -19885,140 +18818,6 @@
       "integrity": 
"sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
       "dev": true
     },
-    "node_modules/yargs": {
-      "version": "12.0.5",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz";,
-      "integrity": 
"sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
-      "dev": true,
-      "dependencies": {
-        "cliui": "^4.0.0",
-        "decamelize": "^1.2.0",
-        "find-up": "^3.0.0",
-        "get-caller-file": "^1.0.1",
-        "os-locale": "^3.0.0",
-        "require-directory": "^2.1.1",
-        "require-main-filename": "^1.0.1",
-        "set-blocking": "^2.0.0",
-        "string-width": "^2.0.0",
-        "which-module": "^2.0.0",
-        "y18n": "^3.2.1 || ^4.0.0",
-        "yargs-parser": "^11.1.1"
-      }
-    },
-    "node_modules/yargs-parser": {
-      "version": "11.1.1",
-      "resolved": 
"https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz";,
-      "integrity": 
"sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
-      "dev": true,
-      "dependencies": {
-        "camelcase": "^5.0.0",
-        "decamelize": "^1.2.0"
-      }
-    },
-    "node_modules/yargs/node_modules/ansi-regex": {
-      "version": "3.0.1",
-      "resolved": 
"https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz";,
-      "integrity": 
"sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
-      "dev": true,
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/yargs/node_modules/find-up": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz";,
-      "integrity": 
"sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
-      "dev": true,
-      "dependencies": {
-        "locate-path": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/yargs/node_modules/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": 
"sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==",
-      "dev": true,
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/yargs/node_modules/locate-path": {
-      "version": "3.0.0",
-      "resolved": 
"https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz";,
-      "integrity": 
"sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
-      "dev": true,
-      "dependencies": {
-        "p-locate": "^3.0.0",
-        "path-exists": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/yargs/node_modules/p-limit": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz";,
-      "integrity": 
"sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-      "dev": true,
-      "dependencies": {
-        "p-try": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/sindresorhus";
-      }
-    },
-    "node_modules/yargs/node_modules/p-locate": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz";,
-      "integrity": 
"sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
-      "dev": true,
-      "dependencies": {
-        "p-limit": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/yargs/node_modules/p-try": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz";,
-      "integrity": 
"sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-      "dev": true,
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/yargs/node_modules/string-width": {
-      "version": "2.1.1",
-      "resolved": 
"https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz";,
-      "integrity": 
"sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
-      "dev": true,
-      "dependencies": {
-        "is-fullwidth-code-point": "^2.0.0",
-        "strip-ansi": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
-    "node_modules/yargs/node_modules/strip-ansi": {
-      "version": "4.0.0",
-      "resolved": 
"https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz";,
-      "integrity": 
"sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==",
-      "dev": true,
-      "dependencies": {
-        "ansi-regex": "^3.0.0"
-      },
-      "engines": {
-        "node": ">=4"
-      }
-    },
     "node_modules/yeast": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz";,
diff --git a/zeppelin-web/package.json b/zeppelin-web/package.json
index 1b5cf1fc60..484fe4a431 100644
--- a/zeppelin-web/package.json
+++ b/zeppelin-web/package.json
@@ -19,8 +19,6 @@
     "dev:watch": "grunt watch-webpack-dev",
     "dev": "npm-run-all --parallel dev:server lint:watch dev:watch",
     "test:watch": "karma start karma.conf.js --single-run=false",
-    "pree2e": "webdriver-manager update --gecko false --versions.chrome=2.35",
-    "e2e": "protractor protractor.conf.js",
     "karma-test": "karma start karma.conf.js"
   },
   "dependencies": {
@@ -130,7 +128,6 @@
     "ng-annotate-loader": "^0.2.0",
     "npm-run-all": "^4.1.5",
     "postcss-loader": "^3.0.0",
-    "protractor": "^5.4.1",
     "raw-loader": "^0.5.1",
     "rimraf": "^3.0.2",
     "string-replace-webpack-plugin": "^0.1.3",
diff --git a/zeppelin-web/pom.xml b/zeppelin-web/pom.xml
index 3dfb3a9da8..b929568046 100644
--- a/zeppelin-web/pom.xml
+++ b/zeppelin-web/pom.xml
@@ -31,9 +31,8 @@
   <name>Zeppelin: web Application</name>
 
   <properties>
-    <web.e2e.disabled>true</web.e2e.disabled>
-    <web.e2e.enabled>false</web.e2e.enabled>
-    <zeppelin.daemon.package.base>../bin</zeppelin.daemon.package.base>
+    <web.unit.test.disabled>true</web.unit.test.disabled>
+    <web.unit.test.enabled>false</web.unit.test.enabled>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 
     <!--plugin versions-->
@@ -122,7 +121,7 @@
               <goal>npm</goal>
             </goals>
             <configuration>
-              <skip>${web.e2e.enabled}</skip>
+              <skip>${web.unit.test.enabled}</skip>
               <arguments>ci</arguments>
             </configuration>
           </execution>
@@ -133,7 +132,7 @@
               <goal>npm</goal>
             </goals>
             <configuration>
-              <skip>${web.e2e.enabled}</skip>
+              <skip>${web.unit.test.enabled}</skip>
               <arguments>${web.build.command}</arguments>
             </configuration>
           </execution>
@@ -145,61 +144,10 @@
             </goals>
             <phase>test</phase>
             <configuration>
-              <skip>${web.e2e.disabled}</skip>
+              <skip>${web.unit.test.disabled}</skip>
               <arguments>run karma-test</arguments>
             </configuration>
           </execution>
-
-            <execution>
-              <id>npm e2e</id>
-              <goals>
-                <goal>npm</goal>
-              </goals>
-              <phase>integration-test</phase>
-              <configuration>
-                <skip>${web.e2e.disabled}</skip>
-                <arguments>run e2e</arguments>
-              </configuration>
-            </execution>
-
-        </executions>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-antrun-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>start-zeppelin</id>
-            <phase>pre-integration-test</phase>
-            <configuration>
-              <skip>${web.e2e.disabled}</skip>
-              <target unless="skipTests">
-                <exec executable="./zeppelin-daemon.sh" 
dir="${zeppelin.daemon.package.base}" spawn="false">
-                  <arg value="start" />
-                </exec>
-              </target>
-            </configuration>
-            <goals>
-              <goal>run</goal>
-            </goals>
-          </execution>
-
-          <execution>
-            <id>stop-zeppelin</id>
-            <phase>post-integration-test</phase>
-            <configuration>
-              <skip>${web.e2e.disabled}</skip>
-              <target unless="skipTests">
-                <exec executable="./zeppelin-daemon.sh" 
dir="${zeppelin.daemon.package.base}" spawn="false">
-                  <arg value="stop" />
-                </exec>
-              </target>
-            </configuration>
-            <goals>
-              <goal>run</goal>
-            </goals>
-          </execution>
         </executions>
       </plugin>
 
@@ -274,14 +222,14 @@
         <web.build.command>run build:ci</web.build.command>
       </properties>
     </profile>
-
     <profile>
-      <id>web-e2e</id>
+      <id>web-unit-test</id>
       <properties>
-        <web.e2e.disabled>false</web.e2e.disabled>
-        <web.e2e.enabled>true</web.e2e.enabled>
+        <web.unit.test.disabled>false</web.unit.test.disabled>
+        <web.unit.test.enabled>true</web.unit.test.enabled>
       </properties>
     </profile>
+
     <!-- Include some test dependencies depending on the spark-scala profile 
-->
     <profile>
       <id>spark-scala-2.13</id>
diff --git a/zeppelin-web/protractor.conf.js b/zeppelin-web/protractor.conf.js
deleted file mode 100644
index 6d55ab7406..0000000000
--- a/zeppelin-web/protractor.conf.js
+++ /dev/null
@@ -1,44 +0,0 @@
-var baseConfig = {
-  baseUrl: 'http://localhost:8080/classic',
-  directConnect: true,
-  capabilities: {
-    browserName: 'chrome',
-  },
-  allScriptsTimeout: 300000, // 5 min
-
-  framework: 'jasmine',
-  specs: ['e2e/**/*.js'],
-  jasmineNodeOpts: {
-    showTiming: true,
-    showColors: true,
-    isVerbose: true,
-    includeStackTrace: false,
-    defaultTimeoutInterval: 300000, // 5 min
-    print: function() {}, // remove protractor dot reporter, we are using 
jasmine-spec-reporter
-  },
-
-  onPrepare: function() {
-    // should be false for angular apps
-    // browser.ignoreSynchronization = true;
-
-    browser.manage().timeouts().pageLoadTimeout(300000);
-    // with the implicitlyWait() this will even though you expect the element 
not to be there
-    browser.manage().timeouts().implicitlyWait(30000);
-
-    // add reporter to display executed tests in console
-    var SpecReporter = require('jasmine-spec-reporter').SpecReporter;
-    jasmine.getEnv().addReporter(new SpecReporter({
-      spec: {
-        displayStacktrace: true
-      }
-    }));
-  },
-};
-
-var chromeOptions = {
-  args: ['--disable-gpu', '--no-sandbox', 'window-size=1920, 1080', 
'--disable-browser-side-navigation']
-}
-
-baseConfig.capabilities.chromeOptions = chromeOptions;
-
-exports.config = baseConfig;

Reply via email to