From cd1bee48862707ba9b8a0c24090dff98b558b975 Mon Sep 17 00:00:00 2001 From: miinhho Date: Mon, 13 Jul 2026 21:35:02 +0900 Subject: [PATCH 1/5] [ZEPPELIN-6527] Migrate classic web e2e tests to Playwright Move the active classic zeppelin-web e2e coverage from Protractor to the existing Playwright harness. Add a classic Playwright project for the legacy /classic UI, port the active home and search block checks, and remove the obsolete Protractor/webdriver-manager entry points from zeppelin-web. Also update the frontend CI job to build the classic UI and run the migrated checks through zeppelin-web-angular's Playwright e2e flow. --- .github/workflows/frontend.yml | 33 +- pom.xml | 1 - zeppelin-web-angular/e2e/cleanup-util.ts | 8 +- .../e2e/tests/classic/classic-home.spec.ts | 84 ++ .../classic/classic-search-block.spec.ts | 164 +++ zeppelin-web-angular/package-lock.json | 62 - zeppelin-web-angular/playwright.config.js | 39 +- zeppelin-web/README.md | 6 +- 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 | 1262 +---------------- zeppelin-web/package.json | 3 - zeppelin-web/pom.xml | 12 - zeppelin-web/protractor.conf.js | 44 - 15 files changed, 296 insertions(+), 1767 deletions(-) create mode 100644 zeppelin-web-angular/e2e/tests/classic/classic-home.spec.ts create mode 100644 zeppelin-web-angular/e2e/tests/classic/classic-search-block.spec.ts delete mode 100644 zeppelin-web/e2e/collaborativeMode.spec.js delete mode 100644 zeppelin-web/e2e/home.spec.js delete mode 100644 zeppelin-web/e2e/searchBlock.spec.js delete mode 100644 zeppelin-web/protractor.conf.js diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 68ce1c63a66..5240a699c63 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@v4 - - name: Tune Runner VM - uses: ./.github/actions/tune-runner-vm - - name: Set up JDK 11 - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: 11 - - name: Cache local Maven repository - uses: actions/cache@v4 - 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,7 @@ 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} - name: Setup Zeppelin Server (Shiro.ini) run: | export ZEPPELIN_CONF_DIR=./conf diff --git a/pom.xml b/pom.xml index 0b3a1803014..62fe3a5b2d0 100644 --- a/pom.xml +++ b/pom.xml @@ -998,7 +998,6 @@ **/.bowerrc .editorconfig **/.eslintrc - **/protractor.conf.js **/.tmp/** **/target/** **/node/** diff --git a/zeppelin-web-angular/e2e/cleanup-util.ts b/zeppelin-web-angular/e2e/cleanup-util.ts index a00678dedd8..48a0deefd5c 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-home.spec.ts b/zeppelin-web-angular/e2e/tests/classic/classic-home.spec.ts new file mode 100644 index 00000000000..c396b06a23a --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/classic/classic-home.spec.ts @@ -0,0 +1,84 @@ +/* + * 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(); + }); + + 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 00000000000..701e20b669c --- /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 => + (text.match(new RegExp(substring, 'g')) || []).length; + +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 => + 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-lock.json b/zeppelin-web-angular/package-lock.json index 9d0ccbc33e6..f1cd22c858a 100644 --- a/zeppelin-web-angular/package-lock.json +++ b/zeppelin-web-angular/package-lock.json @@ -610,18 +610,6 @@ } } }, - "node_modules/@angular-builders/custom-webpack/node_modules/@types/node": { - "version": "25.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", - "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" - } - }, "node_modules/@angular-builders/custom-webpack/node_modules/@vitejs/plugin-basic-ssl": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.4.tgz", @@ -1215,18 +1203,6 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@types/node": { - "version": "25.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", - "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -1641,23 +1617,6 @@ "typescript": "*" } }, - "node_modules/@angular/animations": { - "version": "21.2.15", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.15.tgz", - "integrity": "sha512-Z8AsLTwc++Fcu0fJnclAF9zMfumAd5KXrwtSdyECqLpqd+lEmmsOpeOl6P7loqdDz99KYh/8UF4eJxdMvnsaKw==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - }, - "peerDependencies": { - "@angular/core": "21.2.15" - } - }, "node_modules/@angular/cdk": { "version": "21.2.13", "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.13.tgz", @@ -2080,18 +2039,6 @@ "listr2": "9.0.5" } }, - "node_modules/@angular/cli/node_modules/@types/node": { - "version": "25.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", - "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" - } - }, "node_modules/@angular/cli/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -20489,15 +20436,6 @@ "node": ">=20.18.1" } }, - "node_modules/undici-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", - "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", diff --git a/zeppelin-web-angular/playwright.config.js b/zeppelin-web-angular/playwright.config.js index bc1bd46ebd5..b0426122422 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.argv.some(arg => arg.includes('--project=classic') || 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: defaultBaseURL, 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,19 @@ module.exports = defineConfig({ name: 'setup', testMatch: /global\.setup\.ts/ }, + { + 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 +77,7 @@ module.exports = defineConfig({ }, { name: 'Google Chrome', + testIgnore: classicTests, use: { ...devices['Desktop Chrome'], channel: 'chrome', @@ -71,6 +88,7 @@ module.exports = defineConfig({ }, { name: 'firefox', + testIgnore: classicTests, use: { ...devices['Desktop Firefox'], storageState: 'playwright/.auth/user.json' @@ -79,6 +97,7 @@ module.exports = defineConfig({ }, { name: 'webkit', + testIgnore: classicTests, use: { ...devices['Desktop Safari'], launchOptions: { @@ -90,6 +109,7 @@ module.exports = defineConfig({ }, { name: 'Microsoft Edge', + testIgnore: classicTests, use: { ...devices['Desktop Edge'], channel: 'msedge', @@ -99,12 +119,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 a7ab7117004..90cb9e2fed3 100644 --- a/zeppelin-web/README.md +++ b/zeppelin-web/README.md @@ -40,12 +40,12 @@ $ 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 classic UI e2e tests: make sure that a Zeppelin instance started (localhost:8080) +$ cd ../zeppelin-web-angular && npm run e2e -- --project=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 2c3dc1196ee..00000000000 --- 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 7a9dde07593..00000000000 --- 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 af59f42c0dc..00000000000 --- 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 5c97c383095..22da97876e2 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", @@ -12283,20 +11647,6 @@ "node": "*" } }, - "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==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, "node_modules/node-libs-browser": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", @@ -12472,18 +11822,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 +11856,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 +12186,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 +12206,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 +12485,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 +13410,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 +13435,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 +14312,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 +14321,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 +14593,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,62 +14634,10 @@ "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", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, "dependencies": { "@types/node-forge": "^1.3.0", @@ -15685,12 +14799,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 +15420,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 +15778,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 +16646,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 +16700,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 +17271,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 +17799,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", @@ -19164,22 +18127,6 @@ "node": ">=8" } }, - "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==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, "node_modules/webpack-dev-server/node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -19351,22 +18298,6 @@ "node": ">=8.0" } }, - "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==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { "version": "5.3.4", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", @@ -19719,12 +18650,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 +18707,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 +18745,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 +18775,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 1b5cf1fc607..484fe4a4318 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 3dfb3a9da83..5f8fd189e3b 100644 --- a/zeppelin-web/pom.xml +++ b/zeppelin-web/pom.xml @@ -150,18 +150,6 @@ - - npm e2e - - npm - - integration-test - - ${web.e2e.disabled} - run e2e - - - diff --git a/zeppelin-web/protractor.conf.js b/zeppelin-web/protractor.conf.js deleted file mode 100644 index 6d55ab74063..00000000000 --- 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; From 19c99b9c29e75ad24a231d3b6cc140ed42a5a934 Mon Sep 17 00:00:00 2001 From: miinhho Date: Mon, 13 Jul 2026 22:05:39 +0900 Subject: [PATCH 2/5] [ZEPPELIN-6527] Remove unrelated web angular lockfile churn --- zeppelin-web-angular/package-lock.json | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json index f1cd22c858a..9d0ccbc33e6 100644 --- a/zeppelin-web-angular/package-lock.json +++ b/zeppelin-web-angular/package-lock.json @@ -610,6 +610,18 @@ } } }, + "node_modules/@angular-builders/custom-webpack/node_modules/@types/node": { + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, "node_modules/@angular-builders/custom-webpack/node_modules/@vitejs/plugin-basic-ssl": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.4.tgz", @@ -1203,6 +1215,18 @@ } } }, + "node_modules/@angular-devkit/build-angular/node_modules/@types/node": { + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -1617,6 +1641,23 @@ "typescript": "*" } }, + "node_modules/@angular/animations": { + "version": "21.2.15", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.15.tgz", + "integrity": "sha512-Z8AsLTwc++Fcu0fJnclAF9zMfumAd5KXrwtSdyECqLpqd+lEmmsOpeOl6P7loqdDz99KYh/8UF4eJxdMvnsaKw==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/core": "21.2.15" + } + }, "node_modules/@angular/cdk": { "version": "21.2.13", "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.13.tgz", @@ -2039,6 +2080,18 @@ "listr2": "9.0.5" } }, + "node_modules/@angular/cli/node_modules/@types/node": { + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, "node_modules/@angular/cli/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -20436,6 +20489,15 @@ "node": ">=20.18.1" } }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", From eb7d1b1c0e828bd395f4149925a3bc545566f82a Mon Sep 17 00:00:00 2001 From: miinhho Date: Mon, 13 Jul 2026 22:16:59 +0900 Subject: [PATCH 3/5] [ZEPPELIN-6527] Sync classic web package lock after Protractor removal --- zeppelin-web/package-lock.json | 43 ++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/zeppelin-web/package-lock.json b/zeppelin-web/package-lock.json index 22da97876e2..19a8f4b58b6 100644 --- a/zeppelin-web/package-lock.json +++ b/zeppelin-web/package-lock.json @@ -11647,6 +11647,19 @@ "node": "*" } }, + "node_modules/node-gyp-build": { + "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, + "optional": true, + "peer": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-libs-browser": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", @@ -18127,6 +18140,21 @@ "node": ">=8" } }, + "node_modules/webpack-dev-server/node_modules/bufferutil": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz", + "integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/webpack-dev-server/node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -18298,6 +18326,21 @@ "node": ">=8.0" } }, + "node_modules/webpack-dev-server/node_modules/utf-8-validate": { + "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, + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { "version": "5.3.4", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", From 8597767c78f6db25abd0db8a1cd07125194070da Mon Sep 17 00:00:00 2001 From: miinhho Date: Mon, 13 Jul 2026 22:33:20 +0900 Subject: [PATCH 4/5] Re-trigger CI From 07dc3b5a277704770a4430fb7e1b3ee3cec7c01e Mon Sep 17 00:00:00 2001 From: miinhho Date: Tue, 14 Jul 2026 17:29:21 +0900 Subject: [PATCH 5/5] [ZEPPELIN-6527] Refine classic Playwright e2e configuration --- .github/workflows/frontend.yml | 2 ++ zeppelin-web-angular/e2e/AGENTS.md | 29 +++++++++++++++++++++++ zeppelin-web-angular/package.json | 1 + zeppelin-web-angular/playwright.config.js | 29 +++++++++++++---------- zeppelin-web/README.md | 2 +- 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 5240a699c63..3259ffbc72d 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -105,6 +105,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@v4 diff --git a/zeppelin-web-angular/e2e/AGENTS.md b/zeppelin-web-angular/e2e/AGENTS.md index 3a65bff2a31..d0b1dba9ef2 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,31 @@ 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, 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/package.json b/zeppelin-web-angular/package.json index 5e84360608e..441c4cb5eab 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 b0426122422..4e019e8fd52 100644 --- a/zeppelin-web-angular/playwright.config.js +++ b/zeppelin-web-angular/playwright.config.js @@ -13,7 +13,7 @@ const { defineConfig, devices } = require('@playwright/test'); const classicTests = /tests\/classic\/.*\.spec\.ts/; -const isClassicOnlyRun = process.argv.some(arg => arg.includes('--project=classic') || arg.includes('tests/classic')); +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; @@ -36,7 +36,7 @@ module.exports = defineConfig({ ['./e2e/reporter.coverage.ts'] ], use: { - baseURL: defaultBaseURL, + 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', @@ -55,16 +55,21 @@ module.exports = defineConfig({ name: 'setup', testMatch: /global\.setup\.ts/ }, - { - name: 'classic', - testMatch: classicTests, - use: { - ...devices['Desktop Chrome'], - baseURL: 'http://localhost:8080', - storageState: 'playwright/.auth/user.json' - }, - dependencies: ['setup'] - }, + // 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, diff --git a/zeppelin-web/README.md b/zeppelin-web/README.md index 90cb9e2fed3..480811f3965 100644 --- a/zeppelin-web/README.md +++ b/zeppelin-web/README.md @@ -41,7 +41,7 @@ $ WEB_PORT=YOUR_WEB_DEV_PORT npm run dev $ npm run karma-test # running classic UI e2e tests: make sure that a Zeppelin instance started (localhost:8080) -$ cd ../zeppelin-web-angular && npm run e2e -- --project=classic +$ cd ../zeppelin-web-angular && npm run e2e:classic ``` - to write unit tests, please refer [Angular Test Patterns](https://github.com/daniellmb/angular-test-patterns)