diff --git a/.drone.env b/.drone.env index 3340a88f603..8fca5da4328 100644 --- a/.drone.env +++ b/.drone.env @@ -1,7 +1,7 @@ # The version of OCIS to use in pipelines that test against OCIS -OCIS_COMMITID=45bd133a706ea031f905a159184e6fdb63faa885 +OCIS_COMMITID=a07c1e77a0a3bcb10b109ea4b468472cea10fbb3 OCIS_BRANCH=master # The test runner source for API tests -CORE_COMMITID=08e27f0d73bca5352d87b42936d6d956bc0eaea5 +CORE_COMMITID=d2d63df18170e5e62dbc4d77492ba9a9156af80e CORE_BRANCH=master diff --git a/.drone.star b/.drone.star index 5fda8442c13..4390214c2ac 100644 --- a/.drone.star +++ b/.drone.star @@ -1505,7 +1505,7 @@ def installCore(version, db): stepDefinition = { "name": "install-core", - "image": "owncloudci/core", + "image": "owncloudci/core:nodejs14", "pull": "always", } @@ -1553,7 +1553,7 @@ def installFederatedServer(version, db, dbSuffix = "-federated"): stepDefinition = { "name": "install-federated", - "image": "owncloudci/core", + "image": "owncloudci/core:nodejs14", "pull": "always", } if version: diff --git a/.eslintrc.js b/.eslintrc.js index aef92da42fa..8adcbf2ea62 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -21,6 +21,7 @@ module.exports = { */ 'require-await': 'warn', 'no-new': 'off', + 'jest/no-standalone-expect': 'off', 'node/no-callback-literal': 'off' }, globals: { diff --git a/cucumber.js b/cucumber.js new file mode 100644 index 00000000000..2d41fba19d9 --- /dev/null +++ b/cucumber.js @@ -0,0 +1,12 @@ +module.exports = { + smoke: ` + --require ./tests/smoke/**/*.ts + --require-module ts-node/register + --format @cucumber/pretty-formatter + --publish-quiet + --format-options ${JSON.stringify({ + snippetInterface: 'async-await', + snippetSyntax: './tests/smoke/support/cucumber/snippets-syntax.js' + })} + ` +} diff --git a/package.json b/package.json index 7422a5eb343..97e5314751d 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,9 @@ "depcheck": "depcheck", "lint": "eslint '{packages,tests}/**/*.{js,ts,vue}' --color", "serve": "SERVER=true yarn build:w", - "test:acceptance:oc10": "cucumber-js --require-module @babel/register --require-module @babel/polyfill --require tests/acceptance/setup.js --require tests/acceptance/stepDefinitions --format node_modules/cucumber-pretty -t \"${TEST_TAGS:-not @skip and not @skipOnOC10}\" -f json:tests/report/cucumber_report.json", - "test:acceptance:ocis": "NODE_TLS_REJECT_UNAUTHORIZED=0 RUN_ON_OCIS=true cucumber-js --require-module @babel/register --require-module @babel/polyfill --require tests/acceptance/setup.js --require tests/acceptance/stepDefinitions --format node_modules/cucumber-pretty -t \"${TEST_TAGS:-not @skip and not @skipOnOCIS and not @notToImplementOnOCIS}\" -f json:tests/report/cucumber_report.json", + "test:acceptance:oc10": "cucumber-js --require-module @babel/register --require-module @babel/polyfill --require tests/acceptance/setup.js --require tests/acceptance/stepDefinitions --format @cucumber/pretty-formatter -t \"${TEST_TAGS:-not @skip and not @skipOnOC10}\" -f json:tests/report/cucumber_report.json", + "test:acceptance:ocis": "NODE_TLS_REJECT_UNAUTHORIZED=0 RUN_ON_OCIS=true cucumber-js --require-module @babel/register --require-module @babel/polyfill --require tests/acceptance/setup.js --require tests/acceptance/stepDefinitions --format @cucumber/pretty-formatter -t \"${TEST_TAGS:-not @skip and not @skipOnOCIS and not @notToImplementOnOCIS}\" -f json:tests/report/cucumber_report.json", + "test:smoke:experimental": "NODE_TLS_REJECT_UNAUTHORIZED=0 cucumber-js --profile=smoke", "test:unit": "jest --coverage --config ./tests/unit/config/jest.config.js", "test:integration": "jest --config ./tests/integration/config/jest.config.js" }, @@ -36,16 +37,21 @@ "@babel/polyfill": "^7.12.1", "@babel/preset-env": "^7.14.7", "@babel/register": "^7.13.16", + "@cucumber/cucumber": "^7.3.1", + "@cucumber/pretty-formatter": "^1.0.0-alpha.1", "@erquhart/rollup-plugin-node-builtins": "^2.1.5", + "@playwright/test": "^1.14.0", "@rollup/plugin-commonjs": "^17.0.0", "@rollup/plugin-html": "^0.2.0", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-typescript": "^8.2.5", "@testing-library/jest-dom": "^5.13.0", "@testing-library/vue": "^5.6.2", + "@types/cucumber": "^7.0.0", "@types/jest": "^26.0.23", "@types/jest-axe": "^3.5.2", "@types/lodash-es": "^4.17.4", + "@types/node-fetch": "^2.5.12", "@types/vue": "^2.0.0", "@typescript-eslint/eslint-plugin": "^4.28.3", "@typescript-eslint/parser": "^4.28.3", @@ -58,9 +64,7 @@ "chromedriver": "^89.0.0", "commander": "^8.1.0", "core-js": "^3.15.2", - "cucumber": ">=6.0.5", "cucumber-html-reporter": "^5.4.0", - "cucumber-pretty": "^6.0.0", "depcheck": "^1.3.1", "ejs": "^3.1.5", "eslint": "^7.30.0", @@ -90,6 +94,7 @@ "nightwatch-api": "3.0.1", "nightwatch-vrt": "^0.2.10", "node-fetch": "^2.6.1", + "playwright": "^1.14.0", "postcss": "^8.3.6", "regenerator-runtime": "^0.13.7", "requirejs": "^2.3.6", @@ -111,6 +116,7 @@ "rollup-plugin-vue": "^5.1.4", "sync-fetch": "^0.3.0", "ts-jest": "^26.5.6", + "ts-node": "^10.2.0", "tslib": "^2.2.0", "typescript": "^4.3.2", "url-search-params-polyfill": "^8.0.0", diff --git a/tests/acceptance/run.sh b/tests/acceptance/run.sh index 1be21b08d6e..5ce7c40937e 100755 --- a/tests/acceptance/run.sh +++ b/tests/acceptance/run.sh @@ -161,13 +161,13 @@ then TEST_PATHS+=( "${FEATURES_DIR}" ) fi -RUN_ACCEPTANCE_TESTS="cucumber-js --retry 1 --require-module @babel/register --require-module @babel/polyfill --require tests/acceptance/setup.js --require tests/acceptance/stepDefinitions --format node_modules/cucumber-pretty" +RUN_ACCEPTANCE_TESTS="cucumber-js --retry 1 --require-module @babel/register --require-module @babel/polyfill --require tests/acceptance/setup.js --require tests/acceptance/stepDefinitions --format @cucumber/pretty-formatter" if [ -z "${TEST_TAGS}" ] then - yarn ${RUN_ACCEPTANCE_TESTS} ${TEST_PATHS[@]} | tee -a 'logfile.txt' + CUCUMBER_PUBLISH_ENABLED=false yarn ${RUN_ACCEPTANCE_TESTS} ${TEST_PATHS[@]} | tee -a 'logfile.txt' else - yarn ${RUN_ACCEPTANCE_TESTS} ${TEST_PATHS[@]} -t "${TEST_TAGS}" | tee -a 'logfile.txt' + CUCUMBER_PUBLISH_ENABLED=false yarn ${RUN_ACCEPTANCE_TESTS} ${TEST_PATHS[@]} -t "${TEST_TAGS}" | tee -a 'logfile.txt' fi ACCEPTANCE_TESTS_EXIT_STATUS=${PIPESTATUS[0]} diff --git a/tests/acceptance/setup.js b/tests/acceptance/setup.js index 10b3c14cb17..e1c7aed72e8 100644 --- a/tests/acceptance/setup.js +++ b/tests/acceptance/setup.js @@ -1,4 +1,4 @@ -import { setDefaultTimeout, After, Before, defineParameterType } from 'cucumber' +import { setDefaultTimeout, After, Before, defineParameterType } from '@cucumber/cucumber' import { createSession, closeSession, client, startWebDriver, stopWebDriver } from 'nightwatch-api' import { rollbackConfigs, cacheConfigs } from './helpers/config' import { getAllLogsWithDateTime } from './helpers/browserConsole.js' diff --git a/tests/acceptance/stepDefinitions/accountContext.js b/tests/acceptance/stepDefinitions/accountContext.js index 16de7d62859..4d6eb25bd0a 100644 --- a/tests/acceptance/stepDefinitions/accountContext.js +++ b/tests/acceptance/stepDefinitions/accountContext.js @@ -1,5 +1,5 @@ const { client } = require('nightwatch-api') -const { When, Then } = require('cucumber') +const { When, Then } = require('@cucumber/cucumber') const assert = require('assert') const _ = require('lodash') diff --git a/tests/acceptance/stepDefinitions/filesContext.js b/tests/acceptance/stepDefinitions/filesContext.js index 5f5e1a8b7e1..482d7adb8ec 100644 --- a/tests/acceptance/stepDefinitions/filesContext.js +++ b/tests/acceptance/stepDefinitions/filesContext.js @@ -1,7 +1,7 @@ /* eslint-disable no-unused-expressions */ const { client } = require('nightwatch-api') const assert = require('assert') -const { Given, When, Then, Before } = require('cucumber') +const { Given, When, Then, Before } = require('@cucumber/cucumber') const webdav = require('../helpers/webdavHelper') const _ = require('lodash') const loginHelper = require('../helpers/loginHelper') diff --git a/tests/acceptance/stepDefinitions/generalContext.js b/tests/acceptance/stepDefinitions/generalContext.js index 26fc05d1978..65e803700eb 100644 --- a/tests/acceptance/stepDefinitions/generalContext.js +++ b/tests/acceptance/stepDefinitions/generalContext.js @@ -1,5 +1,5 @@ const { client } = require('nightwatch-api') -const { After, Before, Given, Then, When } = require('cucumber') +const { After, Before, Given, Then, When } = require('@cucumber/cucumber') const webdavHelper = require('../helpers/webdavHelper') const httpHelper = require('../helpers/httpHelper') const backendHelper = require('../helpers/backendHelper') @@ -8,7 +8,7 @@ const fs = require('fs') const occHelper = require('../helpers/occHelper') let initialConfigJsonSettings -let createdFiles = [] +const createdFiles = [] Given( 'a file with the size of {string} bytes and the name {string} has been created locally', @@ -244,7 +244,7 @@ After(async function(testCase) { }) Before(function(testCase) { - createdFiles = [] + testCase.pickle.createdFiles = [] if ( typeof process.env.SCREEN_RESOLUTION !== 'undefined' && process.env.SCREEN_RESOLUTION.trim() !== '' @@ -264,7 +264,8 @@ Before(function(testCase) { } else { client.maximizeWindow() } - console.log(' ' + testCase.sourceLocation.uri + ':' + testCase.sourceLocation.line + '\n') + // todo + // console.log(' ' + testCase.sourceLocation.uri + ':' + testCase.sourceLocation.line + '\n') }) After(async function(testCase) { @@ -273,7 +274,13 @@ After(async function(testCase) { } console.log('\n Result: ' + testCase.result.status + '\n') - createdFiles.forEach(fileName => fs.unlinkSync(fileName)) + createdFiles.forEach(fileName => { + try { + fs.unlinkSync(fileName) + } catch (err) { + console.info(err.message) + } + }) // clear file locks const body = new URLSearchParams() diff --git a/tests/acceptance/stepDefinitions/loginContext.js b/tests/acceptance/stepDefinitions/loginContext.js index 1abe9358c32..aaf733f0df8 100644 --- a/tests/acceptance/stepDefinitions/loginContext.js +++ b/tests/acceptance/stepDefinitions/loginContext.js @@ -1,5 +1,5 @@ const { client } = require('nightwatch-api') -const { Given, Then, When } = require('cucumber') +const { Given, Then, When } = require('@cucumber/cucumber') const loginHelper = require('../helpers/loginHelper') const assert = require('assert') diff --git a/tests/acceptance/stepDefinitions/markdownEditorContext.js b/tests/acceptance/stepDefinitions/markdownEditorContext.js index df8a10dfbbb..ec91649a96f 100644 --- a/tests/acceptance/stepDefinitions/markdownEditorContext.js +++ b/tests/acceptance/stepDefinitions/markdownEditorContext.js @@ -1,7 +1,7 @@ const { client } = require('nightwatch-api') const assert = require('assert') const _ = require('lodash') -const { Given, When, Then } = require('cucumber') +const { Given, When, Then } = require('@cucumber/cucumber') const markdownEditor = client.page.markdownEditorPage() const filesList = client.page.FilesPageElement.filesList() diff --git a/tests/acceptance/stepDefinitions/messagesContext.js b/tests/acceptance/stepDefinitions/messagesContext.js index 70498461676..185c64311cb 100644 --- a/tests/acceptance/stepDefinitions/messagesContext.js +++ b/tests/acceptance/stepDefinitions/messagesContext.js @@ -1,5 +1,5 @@ const { client } = require('nightwatch-api') -const { When } = require('cucumber') +const { When } = require('@cucumber/cucumber') When('the user closes the message', function() { return client.page.webPage().closeMessage() diff --git a/tests/acceptance/stepDefinitions/notificationsContext.js b/tests/acceptance/stepDefinitions/notificationsContext.js index 7172ff940f7..cf595bf6dad 100644 --- a/tests/acceptance/stepDefinitions/notificationsContext.js +++ b/tests/acceptance/stepDefinitions/notificationsContext.js @@ -1,5 +1,5 @@ const { client } = require('nightwatch-api') -const { Given, When, Then } = require('cucumber') +const { Given, When, Then } = require('@cucumber/cucumber') const httpHelper = require('../helpers/httpHelper') const codify = require('../helpers/codify') const assert = require('assert') diff --git a/tests/acceptance/stepDefinitions/previewContext.js b/tests/acceptance/stepDefinitions/previewContext.js index 2838c5d60fa..caa2756758d 100644 --- a/tests/acceptance/stepDefinitions/previewContext.js +++ b/tests/acceptance/stepDefinitions/previewContext.js @@ -1,5 +1,5 @@ const { client } = require('nightwatch-api') -const { Given, When, Then } = require('cucumber') +const { Given, When, Then } = require('@cucumber/cucumber') const mediaViewerPage = client.page.FilesPageElement.mediaViewerPage() const filesList = client.page.FilesPageElement.filesList() const assert = require('assert') diff --git a/tests/acceptance/stepDefinitions/privateLinksContext.js b/tests/acceptance/stepDefinitions/privateLinksContext.js index 630670a2f8e..e6afb07c77f 100644 --- a/tests/acceptance/stepDefinitions/privateLinksContext.js +++ b/tests/acceptance/stepDefinitions/privateLinksContext.js @@ -1,5 +1,5 @@ const { client } = require('nightwatch-api') -const { When } = require('cucumber') +const { When } = require('@cucumber/cucumber') const webdav = require('../helpers/webdavHelper') When( diff --git a/tests/acceptance/stepDefinitions/provisioningContext.js b/tests/acceptance/stepDefinitions/provisioningContext.js index 5a3a94d9263..3b349031c6a 100644 --- a/tests/acceptance/stepDefinitions/provisioningContext.js +++ b/tests/acceptance/stepDefinitions/provisioningContext.js @@ -1,5 +1,5 @@ const { client } = require('nightwatch-api') -const { Given, After } = require('cucumber') +const { Given, After } = require('@cucumber/cucumber') const fs = require('fs-extra') const assert = require('assert') require('url-search-params-polyfill') diff --git a/tests/acceptance/stepDefinitions/publicLinkContext.js b/tests/acceptance/stepDefinitions/publicLinkContext.js index bde43c7dec0..481c599c3e2 100644 --- a/tests/acceptance/stepDefinitions/publicLinkContext.js +++ b/tests/acceptance/stepDefinitions/publicLinkContext.js @@ -1,5 +1,5 @@ const { client } = require('nightwatch-api') -const { When, Then } = require('cucumber') +const { When, Then } = require('@cucumber/cucumber') require('url-search-params-polyfill') const sharingHelper = require('../helpers/sharingHelper') const assert = require('assert') diff --git a/tests/acceptance/stepDefinitions/searchContext.js b/tests/acceptance/stepDefinitions/searchContext.js index b69d9a35c3f..5023b044968 100644 --- a/tests/acceptance/stepDefinitions/searchContext.js +++ b/tests/acceptance/stepDefinitions/searchContext.js @@ -1,5 +1,5 @@ const { client } = require('nightwatch-api') -const { When } = require('cucumber') +const { When } = require('@cucumber/cucumber') When('the user searches for {string} using the webUI', function(searchTerm) { return client.page.webPage().search(searchTerm) diff --git a/tests/acceptance/stepDefinitions/sharingContext.js b/tests/acceptance/stepDefinitions/sharingContext.js index 58a3eb0ea89..eaf03ca617f 100644 --- a/tests/acceptance/stepDefinitions/sharingContext.js +++ b/tests/acceptance/stepDefinitions/sharingContext.js @@ -1,5 +1,5 @@ const { client } = require('nightwatch-api') -const { When, Given, Then } = require('cucumber') +const { When, Given, Then } = require('@cucumber/cucumber') const assert = require('assert') const { URLSearchParams } = require('url') require('url-search-params-polyfill') diff --git a/tests/acceptance/stepDefinitions/visualContext.js b/tests/acceptance/stepDefinitions/visualContext.js index aa7fc653304..9bae6c5ff9d 100644 --- a/tests/acceptance/stepDefinitions/visualContext.js +++ b/tests/acceptance/stepDefinitions/visualContext.js @@ -1,4 +1,4 @@ -const { Then } = require('cucumber') +const { Then } = require('@cucumber/cucumber') const { client } = require('nightwatch-api') const _ = require('lodash') const path = require('path') diff --git a/tests/acceptance/stepDefinitions/webdavContext.js b/tests/acceptance/stepDefinitions/webdavContext.js index b7514697e4e..85bd7f5449a 100644 --- a/tests/acceptance/stepDefinitions/webdavContext.js +++ b/tests/acceptance/stepDefinitions/webdavContext.js @@ -1,4 +1,4 @@ -const { Given, Then } = require('cucumber') +const { Given, Then } = require('@cucumber/cucumber') require('url-search-params-polyfill') const httpHelper = require('../helpers/httpHelper') const backendHelper = require('../helpers/backendHelper') diff --git a/tests/smoke/README.md b/tests/smoke/README.md new file mode 100644 index 00000000000..c4fbc262c5a --- /dev/null +++ b/tests/smoke/README.md @@ -0,0 +1,100 @@ +# WEB-Smoke-Tests (EXPERIMENTAL POC) + +Use with care, the smoke-test package introduces many new concepts and is still under heavy development. + +## Why smoke tests + +Before we release a new web version, we always take care that nothing breaks and the core features are working as +expected. Till now this was a manual process which consumed a lot of time and effort. + +Manual steps are error-prone by nature, on the one hand they can bring up unknown issues, but on the other it's easy to +forget some test steps. The main problem we faced, was that it's never a good thing to manually test your own code. + +To get closer to the point where we are able to release faster and more often, we started to develop the WEB-Smoke-Tests +package. + +## Why not as part of the tests/acceptance package + +The tests/acceptance package has a much broader test scope and is here to test every little element // interaction in +ci. To guarantee that process, a lot of steps are required which takes a lot of time and isn't the perfect fit for local +development. + +The WEB-Smoke-Tests are much smaller and are still in an early phase. Many things are still not there compared to the +mature tests/acceptance package. + +**The main reasons why we decided to split out the smoke tests are:** + +* we wanted to test on a persona // use-case level +* testing should be easy, fast and reliable +* no external dependencies expect a backend +* strongly typed page-objects, steps and helpers +* develop, test manually, extend automatic tests, release, repeat + +## Run a smoke test + +Please make sure to point http://host.docker.internal/ to 127.0.0.1 by adding it to your hosts. + +```shell +$ yarn && yarn build:w +$ docker-compose up oc10 ocis +$ yarn test:smoke:experimental tests/smoke/features/kindergarten.feature +``` + +## Available options + +To run the tests with below options, you have to set them as environment variable in you shell. + +```shell +$ OPTION_1=foo OPTION_2=bar yarn test:smoke:experimental ... +``` + +* **OCIS=boolean** + * defines if the tests should use ocis as backend + * **default**: false +* **SLOW_MO=time-in-ms** + * run the tests with a timeout between every interaction + * **default**: 0 +* **HEADLESS=boolean** + * run the tests without opening a browser + * **default**: false +* **BROWSER=string** + * define which browser is used to run the tests + * **default**: chrome + * **values**: firefox | webkit | chrome | chromium + +## Package structure + +This package is still in an early stage, design could change over time. + +### Features +`./tests/smoke/features` +[Gherkin features](https://cucumber.io/docs/gherkin/reference/) and corresponding [Cucumber step definitions](https://cucumber.io/docs/cucumber/step-definitions/) placed in there, it follows + +### Support +`./tests/smoke/support` +everything that is needed to run the tests organize as package + +`./tests/smoke/support/api` +Every call that is used to provision, configure or even request data from backend will be placed here + +`./tests/smoke/support/cta` +(Call to action) - Snippets that can be used across the entire livecycle of a test + +`./tests/smoke/support/cucumber` +Mainly all cucumber related things, for now only setup is done here + +`./tests/smoke/support/page` +With the option in mind that the smoke-test package could grow, we decided to already group interactions inside page +objects. To get more background what page objects are, you can read +the [introduction here](https://playwright.dev/docs/pom/) + +`./tests/smoke/support/store` +Simple store to persist data for the lifetime of a test + +`./tests/smoke/support/world` +Custom world that is used across the tests, global objects like services get initialized there. [Read more](https://github.com/cucumber/cucumber-js/blob/main/docs/support_files/world.md) + +## Packages we use + +* [cucumber-js](https://github.com/cucumber/cucumber-js) +* [playwright](https://github.com/microsoft/playwright) diff --git a/tests/smoke/features/kindergarten.feature b/tests/smoke/features/kindergarten.feature new file mode 100644 index 00000000000..c9ed4693276 --- /dev/null +++ b/tests/smoke/features/kindergarten.feature @@ -0,0 +1,68 @@ +Feature: Kindergarten can use web to organize a day + + As a kindergarten operator named Alice + I want to manage all file related operations by using ownCloud WEB + So that i'm sure all parents are informed and have the latest information in a easy and secure way + + Background: + Given following users have been created + | Alice | + | Brian | + | Carol | + + Scenario: Alice can share this weeks meal plan with all parents + Given "Alice" has logged in + Then "Alice" opens the "files" app + Then "Alice" navigates to the files page + Then "Alice" creates following folders + | groups/Kindergarten Koalas/meal plan | + | groups/Pre-Schools Pirates/meal plan | + | groups/Teddy Bear Daycare/meal plan | + And "Alice" uploads following resources + | resource | to | + | PARENT/parent.txt | groups/Kindergarten Koalas/meal plan | + | lorem.txt | groups/Kindergarten Koalas/meal plan | + | lorem-big.txt | groups/Kindergarten Koalas/meal plan | + | data.zip | groups/Pre-Schools Pirates/meal plan | + | lorem.txt | groups/Pre-Schools Pirates/meal plan | + | lorem-big.txt | groups/Pre-Schools Pirates/meal plan | + | data.zip | groups/Teddy Bear Daycare/meal plan | + | lorem.txt | groups/Teddy Bear Daycare/meal plan | + | lorem-big.txt | groups/Teddy Bear Daycare/meal plan | + Then "Alice" shares following resources + | resource | user | + | groups/Pre-Schools Pirates/meal plan | Brian | + | groups/Pre-Schools Pirates/meal plan | Carol | + Given "Brian" has logged in + Then "Brian" opens the "files" app + Then "Brian" navigates to the shared with me page + Then "Brian" downloads following files + | resource | from | + | data.zip | meal plan | + Given "Carol" has logged in + Then "Carol" opens the "files" app + Then "Carol" navigates to the shared with me page + Then "Carol" downloads following files + | resource | from | + | data.zip | meal plan | + | lorem.txt | meal plan | + | lorem-big.txt | meal plan | + Then "Carol" has logged out + Then "Brian" downloads following files + | resource | from | + | lorem.txt | meal plan | + | lorem-big.txt | meal plan | + Then "Brian" has logged out + Then "Alice" downloads following files + | resource | from | + | parent.txt | groups/Kindergarten Koalas/meal plan | + | lorem.txt | groups/Kindergarten Koalas/meal plan | + | lorem-big.txt | groups/Kindergarten Koalas/meal plan | + | data.zip | groups/Pre-Schools Pirates/meal plan | + | lorem.txt | groups/Pre-Schools Pirates/meal plan | + | lorem-big.txt | groups/Pre-Schools Pirates/meal plan | + | data.zip | groups/Teddy Bear Daycare/meal plan | + | lorem.txt | groups/Teddy Bear Daycare/meal plan | + | lorem-big.txt | groups/Teddy Bear Daycare/meal plan | + Then "Alice" has logged out + diff --git a/tests/smoke/features/step_definitions/api.ts b/tests/smoke/features/step_definitions/api.ts new file mode 100644 index 00000000000..6f3a7cf5cc7 --- /dev/null +++ b/tests/smoke/features/step_definitions/api.ts @@ -0,0 +1,15 @@ +import { Given, DataTable } from '@cucumber/cucumber' +import { World, api } from '../../support' + +Given('following users have been created', async function( + this: World, + stepUsers: DataTable +): Promise { + const users = stepUsers.raw().map(u => this.userContinent.get({ id: u[0] })) + const admin = this.userContinent.get({ id: 'admin' }) + + for (const user of users) { + await api.user.deleteUser({ user, admin }) + await api.user.createUser({ user, admin }) + } +}) diff --git a/tests/smoke/features/step_definitions/app.files.ts b/tests/smoke/features/step_definitions/app.files.ts new file mode 100644 index 00000000000..ffa01f3b9b9 --- /dev/null +++ b/tests/smoke/features/step_definitions/app.files.ts @@ -0,0 +1,116 @@ +import { DataTable, Given, When } from '@cucumber/cucumber' +import { FilesPage, World } from '../../support' +import { expect } from '@playwright/test' + +When('{string} navigates to the files page', async function( + this: World, + stepUser: string +): Promise { + const actor = this.actorContinent.get({ id: stepUser }) + const { allFiles: allFilesPage } = new FilesPage({ actor }) + + await allFilesPage.navigate() +}) + +When('{string} navigates to the shared with me page', async function( + this: World, + stepUser: string +): Promise { + const actor = this.actorContinent.get({ id: stepUser }) + const { sharedWithMe: sharedWithMePage } = new FilesPage({ actor }) + + await sharedWithMePage.navigate() +}) + +When('{string} creates following folder(s)', async function( + this: World, + stepUser: string, + stepTable: DataTable +): Promise { + const actor = this.actorContinent.get({ id: stepUser }) + const { allFiles: allFilesPage } = new FilesPage({ actor }) + const folders = stepTable.raw().map(f => f[0]) + + for (const folder of folders) { + await allFilesPage.createFolder({ name: folder }) + } +}) + +When('{string} uploads following resource(s)', async function( + this: World, + stepUser: string, + stepTable: DataTable +): Promise { + const actor = this.actorContinent.get({ id: stepUser }) + const { allFiles: allFilesPage } = new FilesPage({ actor }) + const uploadInfo = stepTable.hashes().reduce((acc, stepRow) => { + const { to, resource } = stepRow + + if (!acc[to]) { + acc[to] = [] + } + + acc[to].push(this.fileContinent.get({ name: resource })) + + return acc + }, {}) + + for (const folder of Object.keys(uploadInfo)) { + await allFilesPage.uploadFiles({ folder, files: uploadInfo[folder] }) + } +}) + +When('{string} shares following resource(s)', async function( + this: World, + stepUser: string, + stepTable: DataTable +) { + const actor = this.actorContinent.get({ id: stepUser }) + const { allFiles: allFilesPage } = new FilesPage({ actor }) + + const shareInfo = stepTable.hashes().reduce((acc, stepRow) => { + const { user, resource } = stepRow + + if (!acc[resource]) { + acc[resource] = [] + } + + acc[resource].push(this.userContinent.get({ id: user })) + + return acc + }, {}) + + for (const folder of Object.keys(shareInfo)) { + await allFilesPage.shareFolder({ folder, users: shareInfo[folder] }) + } +}) + +Given('{string} downloads following files', async function( + this: World, + stepUser: string, + stepTable: DataTable +) { + const actor = this.actorContinent.get({ id: stepUser }) + const { allFiles: allFilesPage } = new FilesPage({ actor }) + const downloadInfo = stepTable.hashes().reduce((acc, stepRow) => { + const { resource, from } = stepRow + + if (!acc[from]) { + acc[from] = [] + } + + acc[from].push(resource) + + return acc + }, {}) + + for (const folder of Object.keys(downloadInfo)) { + const files = downloadInfo[folder] + const downloads = await allFilesPage.downloadFiles({ folder, names: files }) + + expect(files.length).toBe(downloads.length) + downloads.forEach(download => { + expect(files).toContain(download.suggestedFilename()) + }) + } +}) diff --git a/tests/smoke/features/step_definitions/runtime.ts b/tests/smoke/features/step_definitions/runtime.ts new file mode 100644 index 00000000000..ff5da545000 --- /dev/null +++ b/tests/smoke/features/step_definitions/runtime.ts @@ -0,0 +1,13 @@ +import { When } from '@cucumber/cucumber' +import { World, RuntimePage } from '../../support' + +When('{string} opens the {string} app', async function( + this: World, + stepUser: string, + stepApp: string +): Promise { + const actor = this.actorContinent.get({ id: stepUser }) + const runtimePage = new RuntimePage({ actor }) + + await runtimePage.navigateToApp({ name: stepApp }) +}) diff --git a/tests/smoke/features/step_definitions/session.ts b/tests/smoke/features/step_definitions/session.ts new file mode 100644 index 00000000000..b7006145a17 --- /dev/null +++ b/tests/smoke/features/step_definitions/session.ts @@ -0,0 +1,18 @@ +import { Given } from '@cucumber/cucumber' +import { World, config, LoginPage, RuntimePage } from '../../support' + +Given('{string} has logged in', async function(this: World, stepUser: string): Promise { + const user = this.userContinent.get({ id: stepUser }) + const actor = await this.actorContinent.create({ id: stepUser }) + const loginPage = new LoginPage({ actor }) + + await actor.page.goto(config.frontendUrl) + await loginPage.login({ user }) +}) + +Given('{string} has logged out', async function(this: World, stepUser: string): Promise { + const actor = await this.actorContinent.get({ id: stepUser }) + const runtimePage = new RuntimePage({ actor }) + await runtimePage.logout() + await actor.close() +}) diff --git a/tests/smoke/support/api/http.ts b/tests/smoke/support/api/http.ts new file mode 100644 index 00000000000..497d4882d7d --- /dev/null +++ b/tests/smoke/support/api/http.ts @@ -0,0 +1,52 @@ +import join from 'join-path' +import fetch, { BodyInit, Response } from 'node-fetch' +import { User } from '../types' +import { config } from '../config' +import _ from 'lodash' + +export const request = async ({ + method, + path, + body, + user +}: { + method: 'POST' | 'DELETE' | 'PUT' | 'GET' + path: string + body?: BodyInit + user?: User +}): Promise => { + return await fetch( + join( + config.backendUrl, + 'ocs', + 'v2.php', + path + (path.includes('?') ? '&' : '?') + 'format=json' + ), + { + method, + body, + headers: { + 'OCS-APIREQUEST': true as any, + ...(user && { + Authorization: 'Basic ' + Buffer.from(user.id + ':' + user.password).toString('base64') + }) + } + } + ) +} + +export const checkResponseStatus = (response: Response, message = ''): void => { + // response.status >= 200 && response.status < 300 + if (!response.ok) { + throw Error(`HTTP Request Failed: ${message}, Status: ${response.status}`) + } +} + +export const checkOCJsonStatus = (json: JSON, message = ''): void => { + const statusCode = _.get(json, 'ocs.meta.statuscode') + const ocsMessage = _.get(json, 'ocs.meta.message') + + if (statusCode !== 200) { + throw Error(`OCS Request Failed: ${message}, Status: ${statusCode}, Message: ${ocsMessage}`) + } +} diff --git a/tests/smoke/support/api/index.ts b/tests/smoke/support/api/index.ts new file mode 100644 index 00000000000..9122b621443 --- /dev/null +++ b/tests/smoke/support/api/index.ts @@ -0,0 +1,7 @@ +import * as http from './http' +import * as user from './user' + +export const api = { + http, + user +} diff --git a/tests/smoke/support/api/user.ts b/tests/smoke/support/api/user.ts new file mode 100644 index 00000000000..7baaaf6aae8 --- /dev/null +++ b/tests/smoke/support/api/user.ts @@ -0,0 +1,70 @@ +import { checkResponseStatus, checkOCJsonStatus, request } from './http' +import { User } from '../types' +import { URLSearchParams } from 'url' +import join from 'join-path' + +export const createUser = async ({ user, admin }: { user: User; admin: User }): Promise => { + const promChain = [] + { + const body = new URLSearchParams() + body.append('username', user.id) + body.append('email', user.email) + body.append('userid', user.id) + body.append('password', user.password) + body.append('displayname', user.displayName) + + const response = await request({ + method: 'POST', + path: join('cloud', 'users'), + body: body, + user: admin + }) + checkResponseStatus(response, 'Failed while creating user') + + const json = await response.json() + checkOCJsonStatus(json, 'Failed while creating user') + } + + ;[ + ['display', user.displayName], + ['email', user.email] + ].forEach(kv => { + const body = new URLSearchParams() + body.append('key', kv[0]) + body.append('value', kv[1]) + promChain.push( + request({ + method: 'PUT', + path: join('cloud', 'users', encodeURIComponent(user.id)), + body, + user: admin + }) + ) + }) + + // initUser is there because ocis needs to have at least 1 request to the created user to perform deleteRequests later + // twice because it works, known issue and needs to be cleaned up once the ocis users service is moved to reva + for (const prom of [await initUser({ user }), ...promChain, await initUser({ user })]) { + await prom + } +} + +export const deleteUser = async ({ user, admin }: { user: User; admin: User }): Promise => { + await request({ + method: 'DELETE', + path: `cloud/users/${encodeURIComponent(user.id)}`, + user: admin + }) + + return user +} + +export const initUser = async ({ user }: { user: User }): Promise => { + await request({ + method: 'GET', + path: join('cloud', 'users', user.id), + user + }) + + return user +} diff --git a/tests/smoke/support/config.ts b/tests/smoke/support/config.ts new file mode 100644 index 00000000000..bb5c3be35f4 --- /dev/null +++ b/tests/smoke/support/config.ts @@ -0,0 +1,23 @@ +const withHttp = url => (/^https?:\/\//i.test(url) ? url : `http://${url}`) + +export const config = { + ocis: process.env.OCIS === 'true', + assets: './tests/acceptance/filesForUpload', + slowMo: parseInt(process.env.SLOW_MO) || 0, + headless: process.env.HEADLESS === 'true', + browser: process.env.BROWSER ?? 'chrome', + get backendUrl(): string { + return withHttp( + process.env.BACKEND_HOST || + (this.ocis ? 'https://host.docker.internal:9200' : 'http://host.docker.internal:8080') + ) + }, + get frontendUrl(): string { + return withHttp( + process.env.SERVER_HOST || + (this.ocis + ? 'https://host.docker.internal:9200' + : 'http://host.docker.internal:8080/index.php/apps/web/index.html') + ) + } +} diff --git a/tests/smoke/support/cta/files/index.ts b/tests/smoke/support/cta/files/index.ts new file mode 100644 index 00000000000..97b66747d22 --- /dev/null +++ b/tests/smoke/support/cta/files/index.ts @@ -0,0 +1,3 @@ +/* eslint-disable */ +export * as sidebar from './sidebar' +export * from './misc' diff --git a/tests/smoke/support/cta/files/misc.ts b/tests/smoke/support/cta/files/misc.ts new file mode 100644 index 00000000000..fc7de945ee4 --- /dev/null +++ b/tests/smoke/support/cta/files/misc.ts @@ -0,0 +1,36 @@ +import { Page } from 'playwright' + +export const navigateToFolder = async ({ + page, + path +}: { + page: Page + path: string +}): Promise => { + const paths = path.split('/') + + for (const name of paths) { + await page.click(`[data-test-resource-name="${name}"]`) + } +} + +export const resourceExists = async ({ + page, + name +}: { + page: Page + name: string +}): Promise => { + const resource = await page.$(`[data-test-resource-name="${name}"]`) + return !!resource +} + +export const waitForResources = async ({ + page, + names +}: { + page: Page + names: string[] +}): Promise => { + await Promise.all(names.map(name => page.waitForSelector(`[data-test-resource-name="${name}"]`))) +} diff --git a/tests/smoke/support/cta/files/sidebar.ts b/tests/smoke/support/cta/files/sidebar.ts new file mode 100644 index 00000000000..0bc8b86a13c --- /dev/null +++ b/tests/smoke/support/cta/files/sidebar.ts @@ -0,0 +1,33 @@ +import { Page } from 'playwright' + +export const open = async ({ page, resource }: { page: Page; resource: string }): Promise => { + await page.click( + `//span[@data-test-resource-name="${resource}"]/ancestor::tr[contains(@class, "oc-tbody-tr")]//button[contains(@class, "oc-table-files-btn-show-details")]` + ) +} + +export const close = async ({ page }: { page: Page }): Promise => { + await page.click('.sidebar-panel.is-active .header__close') +} + +export const openPanel = async ({ + page, + name +}: { + page: Page + name: 'actions' | 'sharing' | 'links' | 'versions' | 'details' +}): Promise => { + if (await page.$eval(`#sidebar-panel-${name}-item`, el => el.classList.contains('.is-active'))) { + return + } + + const backElement = await page.$('.sidebar-panel.is-active .header__back') + if (backElement) { + await backElement.click() + } + + const panelOpenElement = await page.$(`#sidebar-panel-${name}-item-select`) + if (panelOpenElement) { + await panelOpenElement.click() + } +} diff --git a/tests/smoke/support/cta/index.ts b/tests/smoke/support/cta/index.ts new file mode 100644 index 00000000000..88b819df4ce --- /dev/null +++ b/tests/smoke/support/cta/index.ts @@ -0,0 +1,5 @@ +import * as files from './files' + +export const cta = { + files +} diff --git a/tests/smoke/support/cucumber/index.ts b/tests/smoke/support/cucumber/index.ts new file mode 100644 index 00000000000..be1b1dad737 --- /dev/null +++ b/tests/smoke/support/cucumber/index.ts @@ -0,0 +1,16 @@ +import { + Before, + setDefaultTimeout, + setWorldConstructor, + ITestCaseHookParameter +} from '@cucumber/cucumber' + +import { World } from '../world' + +setDefaultTimeout(process.env.PWDEBUG ? -1 : 60 * 1000) + +Before(function(this: World, { pickle }: ITestCaseHookParameter) { + this.feature = pickle +}) + +setWorldConstructor(World) diff --git a/tests/smoke/support/cucumber/snippets-syntax.js b/tests/smoke/support/cucumber/snippets-syntax.js new file mode 100644 index 00000000000..4e7a758b222 --- /dev/null +++ b/tests/smoke/support/cucumber/snippets-syntax.js @@ -0,0 +1,60 @@ +// borrowed from https://github.com/orieken/playwright-cucumber-starter +// thanks @orieken if you will ever read this + +function TypeScriptSnippetSyntax(snippetInterface) { + this.snippetInterface = snippetInterface +} + +function addParameters(allParameterNames) { + let prefix = '' + if (allParameterNames.length > 0) { + prefix = ', ' + } + return prefix + allParameterNames.join(', ') +} + +TypeScriptSnippetSyntax.prototype.build = function({ + generatedExpressions, + functionName, + stepParameterNames +}) { + let functionKeyword = '' + const functionInterfaceKeywords = { + generator: `${functionKeyword}*`, + 'async-await': `async ${functionKeyword}`, + promise: 'async ' + } + + if (this.snippetInterface) { + functionKeyword = `${functionKeyword}${functionInterfaceKeywords[this.snippetInterface]}` + } + + const implementation = [ + 'const { feature, actorContinent, userContinent, fileContinent } = this\n', + 'await new Promise(resolve => setTimeout(resolve, 10))' + ] + .map(str => ` ${str}`) + .join('\n') + + const definitionChoices = generatedExpressions.map((generatedExpression, index) => { + const prefix = index === 0 ? '' : '// ' + + const allParameterNames = generatedExpression.parameterNames + .map(parameterName => `${parameterName}: any`) + .concat(stepParameterNames.map(stepParameterName => `${stepParameterName}: any`)) + + return ( + `${prefix}${functionName}('` + + generatedExpression.source.replace(/'/g, "\\'") + + "', " + + functionKeyword + + 'function (this: World' + + addParameters(allParameterNames) + + '): Promise {\n' + ) + }) + + return definitionChoices.join('') + `${implementation}\n});` +} + +module.exports = TypeScriptSnippetSyntax diff --git a/tests/smoke/support/index.ts b/tests/smoke/support/index.ts new file mode 100644 index 00000000000..650a6cd9c5c --- /dev/null +++ b/tests/smoke/support/index.ts @@ -0,0 +1,5 @@ +export { api } from './api' +export { cta } from './cta' +export * from './page' +export { config } from './config' +export { World } from './world' diff --git a/tests/smoke/support/page/files/allFiles.ts b/tests/smoke/support/page/files/allFiles.ts new file mode 100644 index 00000000000..5caef8cf273 --- /dev/null +++ b/tests/smoke/support/page/files/allFiles.ts @@ -0,0 +1,120 @@ +import { Download } from 'playwright' +import { User, Actor, File } from '../../types' +import { cta } from '../../cta' +import path from 'path' + +export class AllFilesPage { + private readonly actor: Actor + + constructor({ actor }: { actor: Actor }) { + this.actor = actor + } + + async navigate(): Promise { + const { page } = this.actor + await page.click('a[href="#/files/list/all"]') + } + + async createFolder({ name }: { name: string }): Promise { + const { page } = this.actor + + const paths = name.split('/') + const startUrl = page.url() + + for (const folderName of paths) { + const folderExists = await cta.files.resourceExists({ + page: page, + name: folderName + }) + + if (!folderExists) { + await page.click('#new-file-menu-btn') + await page.click('#new-folder-btn') + await page.fill('.oc-modal input', folderName) + await page.click('.oc-modal-body-actions-confirm') + } + + await cta.files.navigateToFolder({ page: page, path: folderName }) + } + + await page.goto(startUrl) + await page.waitForSelector('#files-personal-table') + } + + async uploadFiles({ files, folder }: { files: File[]; folder?: string }): Promise { + const { page } = this.actor + const startUrl = page.url() + + if (folder) { + await cta.files.navigateToFolder({ page: page, path: folder }) + } + + await page.click('#new-file-menu-btn') + await page.setInputFiles( + '#fileUploadInput', + files.map(file => file.path) + ) + + await cta.files.waitForResources({ + page: page, + names: files.map(file => path.basename(file.name)) + }) + + await page.goto(startUrl) + await page.click('body') + } + + async downloadFiles({ names, folder }: { names: string[]; folder: string }): Promise { + const { page } = this.actor + const startUrl = page.url() + const downloads = [] + + if (folder) { + await cta.files.navigateToFolder({ page: page, path: folder }) + } + + for (const name of names) { + await cta.files.sidebar.open({ page: page, resource: name }) + await cta.files.sidebar.openPanel({ page: page, name: 'actions' }) + + const [download] = await Promise.all([ + page.waitForEvent('download'), + page.click('.oc-files-actions-download-trigger') + ]) + + await cta.files.sidebar.close({ page: page }) + + downloads.push(download) + } + + await page.goto(startUrl) + + return downloads + } + + async shareFolder({ folder, users }: { folder: string; users: User[] }): Promise { + const { page } = this.actor + const startUrl = page.url() + const folderPaths = folder.split('/') + const folderName = folderPaths.pop() + + if (folderPaths.length) { + await cta.files.navigateToFolder({ page: page, path: folderPaths.join('/') }) + } + + await cta.files.sidebar.open({ page: page, resource: folderName }) + await cta.files.sidebar.openPanel({ page: page, name: 'sharing' }) + await page.click('.files-collaborators-open-add-share-dialog-button') + + for (const user of users) { + await page.fill('#files-share-invite-input', user.displayName) + await page.waitForSelector('.vs--open') + await page.press('#files-share-invite-input', 'Enter') + } + + await page.click('#files-collaborators-collaborator-save-new-share-button') + await cta.files.sidebar.close({ page: page }) + + await page.goto(startUrl) + } +} diff --git a/tests/smoke/support/page/files/index.ts b/tests/smoke/support/page/files/index.ts new file mode 100644 index 00000000000..9083353fa53 --- /dev/null +++ b/tests/smoke/support/page/files/index.ts @@ -0,0 +1,13 @@ +import { Actor } from '../../types' +import { AllFilesPage } from './allFiles' +import { SharedWithMePage } from './sharedWithMe' + +export class FilesPage { + allFiles: AllFilesPage + sharedWithMe: SharedWithMePage + + constructor({ actor }: { actor: Actor }) { + this.allFiles = new AllFilesPage({ actor }) + this.sharedWithMe = new SharedWithMePage({ actor }) + } +} diff --git a/tests/smoke/support/page/files/sharedWithMe.ts b/tests/smoke/support/page/files/sharedWithMe.ts new file mode 100644 index 00000000000..8461cac15e0 --- /dev/null +++ b/tests/smoke/support/page/files/sharedWithMe.ts @@ -0,0 +1,14 @@ +import { Actor } from '../../types' + +export class SharedWithMePage { + private readonly actor: Actor + + constructor({ actor }: { actor: Actor }) { + this.actor = actor + } + + async navigate(): Promise { + const { page } = this.actor + await page.click('a[href="#/files/list/shared-with-me"]') + } +} diff --git a/tests/smoke/support/page/index.ts b/tests/smoke/support/page/index.ts new file mode 100644 index 00000000000..f81b766d1a6 --- /dev/null +++ b/tests/smoke/support/page/index.ts @@ -0,0 +1,3 @@ +export { FilesPage } from './files' +export { LoginPage } from './login' +export { RuntimePage } from './runtime' diff --git a/tests/smoke/support/page/login/index.ts b/tests/smoke/support/page/login/index.ts new file mode 100644 index 00000000000..0bb8beca217 --- /dev/null +++ b/tests/smoke/support/page/login/index.ts @@ -0,0 +1,25 @@ +import { config } from '../../config' +import { Oc10LoginAdapter } from './oc10' +import { OcisLoginAdapter } from './ocis' +import { Actor, User } from '../../types' + +export interface LoginAdapter { + login({ user }: { user: User }): Promise +} + +export class LoginPage { + private readonly actor: Actor + private readonly adapter: LoginAdapter + + constructor({ actor }: { actor: Actor }) { + this.actor = actor + this.adapter = config.ocis ? new OcisLoginAdapter({ actor }) : new Oc10LoginAdapter({ actor }) + } + + async login({ user }: { user: User }): Promise { + const { page } = this.actor + + await this.adapter.login({ user }) + await page.waitForSelector('#web') + } +} diff --git a/tests/smoke/support/page/login/oc10.ts b/tests/smoke/support/page/login/oc10.ts new file mode 100644 index 00000000000..eedb03d196f --- /dev/null +++ b/tests/smoke/support/page/login/oc10.ts @@ -0,0 +1,21 @@ +import {Actor, User} from '../../types' +/* eslint-disable-next-line */ +import type { LoginAdapter } from './index' + +export class Oc10LoginAdapter implements LoginAdapter{ + private readonly actor: Actor + + constructor({ actor }: { actor: Actor }) { + this.actor = actor + } + + async login({ user }: { user: User }): Promise { + const { page } = this.actor + const { id, password } = user + + await page.fill('input[name="user"]', id) + await page.fill('input[name="password"]', password) + await page.click('#submit') + await page.click('button[type="submit"]') + } +} diff --git a/tests/smoke/support/page/login/ocis.ts b/tests/smoke/support/page/login/ocis.ts new file mode 100644 index 00000000000..b7546c85c51 --- /dev/null +++ b/tests/smoke/support/page/login/ocis.ts @@ -0,0 +1,20 @@ +import {Actor, User} from '../../types' +/* eslint-disable-next-line */ +import type { LoginAdapter } from './index' + +export class OcisLoginAdapter implements LoginAdapter{ + private readonly actor: Actor + + constructor({ actor }: { actor: Actor }) { + this.actor = actor + } + + async login({ user }: { user: User }): Promise { + const { page } = this.actor + const { id, password } = user + + await page.fill('#oc-login-username', id) + await page.fill('#oc-login-password', password) + await page.click('button[type="submit"]') + } +} diff --git a/tests/smoke/support/page/runtime.ts b/tests/smoke/support/page/runtime.ts new file mode 100644 index 00000000000..45cb5d390b2 --- /dev/null +++ b/tests/smoke/support/page/runtime.ts @@ -0,0 +1,22 @@ +import { Actor } from '../types' + +export class RuntimePage { + private readonly actor: Actor + + constructor({ actor }: { actor: Actor }) { + this.actor = actor + } + + async navigateToApp({ name }: { name: string }): Promise { + const { page } = this.actor + await page.click('#_appSwitcherButton') + await page.click(`a[href="#/${name}"]`) + } + + async logout(): Promise { + const { page } = this.actor + + await page.click('#_userMenuButton') + await page.click('#oc-topbar-account-logout') + } +} diff --git a/tests/smoke/support/store/actor.ts b/tests/smoke/support/store/actor.ts new file mode 100644 index 00000000000..4d0f146c2c3 --- /dev/null +++ b/tests/smoke/support/store/actor.ts @@ -0,0 +1,3 @@ +import { Actor } from '../types' + +export const actorStore = new Map() diff --git a/tests/smoke/support/store/index.ts b/tests/smoke/support/store/index.ts new file mode 100644 index 00000000000..c647df48fba --- /dev/null +++ b/tests/smoke/support/store/index.ts @@ -0,0 +1,2 @@ +export * from './user' +export * from './actor' diff --git a/tests/smoke/support/store/user.ts b/tests/smoke/support/store/user.ts new file mode 100644 index 00000000000..589e19accd9 --- /dev/null +++ b/tests/smoke/support/store/user.ts @@ -0,0 +1,40 @@ +import { User } from '../types' + +export const userStore = new Map([ + [ + 'admin', + { + id: 'admin', + displayName: process.env.ADMIN_USERNAME || 'admin', + password: 'admin', + email: 'admin@example.org' + } + ], + [ + 'Alice', + { + id: 'Alice', + displayName: 'Alice Hansen', + password: '1234', + email: 'alice@example.org' + } + ], + [ + 'Brian', + { + id: 'Brian', + displayName: 'Brian Murphy', + password: '1234', + email: 'brian@example.org' + } + ], + [ + 'Carol', + { + id: 'Carol', + displayName: 'Carol King', + password: '1234', + email: 'carol@example.org' + } + ] +]) diff --git a/tests/smoke/support/types.ts b/tests/smoke/support/types.ts new file mode 100644 index 00000000000..e19266e41df --- /dev/null +++ b/tests/smoke/support/types.ts @@ -0,0 +1,19 @@ +import { BrowserContext, Page } from 'playwright' + +export interface Actor { + context: BrowserContext + page: Page + close(): Promise +} + +export interface User { + id: string + displayName: string + password: string + email: string +} + +export interface File { + name: string + path: string +} diff --git a/tests/smoke/support/world/actor.setup.ts b/tests/smoke/support/world/actor.setup.ts new file mode 100644 index 00000000000..5f7f87ff29a --- /dev/null +++ b/tests/smoke/support/world/actor.setup.ts @@ -0,0 +1,28 @@ +import { Browser, chromium, firefox, LaunchOptions, webkit } from 'playwright' +import { AfterAll, BeforeAll } from '@cucumber/cucumber' +import { config } from '../config' + +export let browser: Browser + +const browserOptions: LaunchOptions = { + slowMo: config.slowMo, + args: ['--use-fake-ui-for-media-stream', '--use-fake-device-for-media-stream'], + firefoxUserPrefs: { + 'media.navigator.streams.fake': true, + 'media.navigator.permission.disabled': true + }, + headless: config.headless +} + +BeforeAll( + async (): Promise => { + browser = await { + firefox: async (): Promise => await firefox.launch(browserOptions), + webkit: async (): Promise => await webkit.launch(browserOptions), + chrome: async (): Promise => + await chromium.launch({ ...browserOptions, channel: 'chrome' }), + chromium: async (): Promise => await chromium.launch(browserOptions) + }[config.browser]() + } +) +AfterAll(() => browser && browser.close()) diff --git a/tests/smoke/support/world/actor.ts b/tests/smoke/support/world/actor.ts new file mode 100644 index 00000000000..73aa797c39e --- /dev/null +++ b/tests/smoke/support/world/actor.ts @@ -0,0 +1,38 @@ +import { browser } from './actor.setup' +import { actorStore } from '../store' +import { Actor } from '../types' + +export class ActorContinent { + private store = actorStore + + public get({ id }: { id: string }): Actor { + if (!this.store.has(id)) { + throw new Error(`Actor '${id}' does not exist.`) + } + + return this.store.get(id) + } + + public async create({ id }: { id: string }): Promise { + if (this.store.has(id)) { + throw new Error(`Actor '${id}' already exists.`) + } + + const context = await browser.newContext({ + acceptDownloads: true, + ignoreHTTPSErrors: true + }) + const page = await context.newPage() + + return this.store + .set(id, { + context, + page, + close: async (): Promise => { + await page.close() + await context.close() + } + }) + .get(id) + } +} diff --git a/tests/smoke/support/world/file.ts b/tests/smoke/support/world/file.ts new file mode 100644 index 00000000000..07d6bdce798 --- /dev/null +++ b/tests/smoke/support/world/file.ts @@ -0,0 +1,16 @@ +import fs from 'fs' +import path from 'path' +import { config } from '../config' +import { File } from '../types' + +export class FileContinent { + get({ name }: { name: string }): File { + const relPath = path.join(config.assets, name) + + if (!fs.existsSync(relPath)) { + throw new Error('TODO: fixture files') + } + + return { name, path: path.resolve(relPath) } + } +} diff --git a/tests/smoke/support/world/index.ts b/tests/smoke/support/world/index.ts new file mode 100644 index 00000000000..4f99f1ef9f0 --- /dev/null +++ b/tests/smoke/support/world/index.ts @@ -0,0 +1,23 @@ +import { World as CucumberWorld, IWorldOptions } from '@cucumber/cucumber' +import { Pickle } from '@cucumber/messages' +import { ActorContinent } from './actor' +import { UserContinent } from './user' +import { FileContinent } from './file' + +interface WorldOptions extends IWorldOptions { + parameters: { [key: string]: string } +} + +export class World extends CucumberWorld { + feature: Pickle + actorContinent: ActorContinent + userContinent: UserContinent + fileContinent: FileContinent + + constructor(options: WorldOptions) { + super(options) + this.actorContinent = new ActorContinent() + this.userContinent = new UserContinent() + this.fileContinent = new FileContinent() + } +} diff --git a/tests/smoke/support/world/user.ts b/tests/smoke/support/world/user.ts new file mode 100644 index 00000000000..709e0e29938 --- /dev/null +++ b/tests/smoke/support/world/user.ts @@ -0,0 +1,14 @@ +import { User } from '../types' +import { userStore } from '../store' + +export class UserContinent { + private store = userStore + + get({ id }: { id: string }): User { + if (!this.store.has(id)) { + throw new Error(`user with id '${id}' not found`) + } + + return this.store.get(id) + } +} diff --git a/tsconfig.json b/tsconfig.json index ce5e235a18b..9081c8883ec 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,9 +4,9 @@ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "es5", + "target": "esnext", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ - "module": "ESNext", + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ "lib": [ "ESNext", diff --git a/yarn.lock b/yarn.lock index 8088d0e16a1..098fd87b802 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21,6 +21,11 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz" integrity sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw== +"@babel/compat-data@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" + integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== + "@babel/core@^7.1.0", "@babel/core@^7.11.6", "@babel/core@^7.12.10", "@babel/core@^7.14.3", "@babel/core@^7.7.5": version "7.14.6" resolved "https://registry.npmjs.org/@babel/core/-/core-7.14.6.tgz" @@ -42,6 +47,27 @@ semver "^6.3.0" source-map "^0.5.0" +"@babel/core@^7.14.8": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.0.tgz#749e57c68778b73ad8082775561f67f5196aafa8" + integrity sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.0" + "@babel/helper-module-transforms" "^7.15.0" + "@babel/helpers" "^7.14.8" + "@babel/parser" "^7.15.0" + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + "@babel/generator@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.14.5.tgz" @@ -51,6 +77,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.0.tgz#a7d0c172e0d814974bad5aa77ace543b97917f15" + integrity sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ== + dependencies: + "@babel/types" "^7.15.0" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz" @@ -76,6 +111,16 @@ browserslist "^4.16.6" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz#973df8cbd025515f3ff25db0c05efc704fa79818" + integrity sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A== + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.16.6" + semver "^6.3.0" + "@babel/helper-create-class-features-plugin@^7.14.5": version "7.14.6" resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.6.tgz" @@ -88,6 +133,18 @@ "@babel/helper-replace-supers" "^7.14.5" "@babel/helper-split-export-declaration" "^7.14.5" +"@babel/helper-create-class-features-plugin@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.0.tgz#c9a137a4d137b2d0e2c649acf536d7ba1a76c0f7" + integrity sha512-MdmDXgvTIi4heDVX/e9EFfeGpugqm9fobBVg/iioE8kueXrOHdRDe36FAY7SnE9xXLVeYCoJR/gdrBEIHRC83Q== + dependencies: + "@babel/helper-annotate-as-pure" "^7.14.5" + "@babel/helper-function-name" "^7.14.5" + "@babel/helper-member-expression-to-functions" "^7.15.0" + "@babel/helper-optimise-call-expression" "^7.14.5" + "@babel/helper-replace-supers" "^7.15.0" + "@babel/helper-split-export-declaration" "^7.14.5" + "@babel/helper-create-regexp-features-plugin@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz" @@ -147,6 +204,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-member-expression-to-functions@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz#0ddaf5299c8179f27f37327936553e9bba60990b" + integrity sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg== + dependencies: + "@babel/types" "^7.15.0" + "@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz" @@ -168,6 +232,20 @@ "@babel/traverse" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/helper-module-transforms@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz#679275581ea056373eddbe360e1419ef23783b08" + integrity sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg== + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-replace-supers" "^7.15.0" + "@babel/helper-simple-access" "^7.14.8" + "@babel/helper-split-export-declaration" "^7.14.5" + "@babel/helper-validator-identifier" "^7.14.9" + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + "@babel/helper-optimise-call-expression@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz" @@ -199,6 +277,16 @@ "@babel/traverse" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/helper-replace-supers@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz#ace07708f5bf746bf2e6ba99572cce79b5d4e7f4" + integrity sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.15.0" + "@babel/helper-optimise-call-expression" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + "@babel/helper-simple-access@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.5.tgz" @@ -206,6 +294,13 @@ dependencies: "@babel/types" "^7.14.5" +"@babel/helper-simple-access@^7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz#82e1fec0644a7e775c74d305f212c39f8fe73924" + integrity sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg== + dependencies: + "@babel/types" "^7.14.8" + "@babel/helper-skip-transparent-expression-wrappers@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz" @@ -225,6 +320,11 @@ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz" integrity sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg== +"@babel/helper-validator-identifier@^7.14.9": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" + integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== + "@babel/helper-validator-option@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz" @@ -249,6 +349,15 @@ "@babel/traverse" "^7.14.5" "@babel/types" "^7.14.5" +"@babel/helpers@^7.14.8": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.3.tgz#c96838b752b95dcd525b4e741ed40bb1dc2a1357" + integrity sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g== + dependencies: + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + "@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz" @@ -263,6 +372,11 @@ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.14.6.tgz" integrity sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ== +"@babel/parser@^7.15.0": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.3.tgz#3416d9bea748052cfcb63dbcc27368105b1ed862" + integrity sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA== + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz" @@ -512,6 +626,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/plugin-syntax-typescript@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz#b82c6ce471b165b5ce420cf92914d6fb46225716" + integrity sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-arrow-functions@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz" @@ -757,6 +878,15 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/plugin-transform-typescript@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.15.0.tgz#553f230b9d5385018716586fc48db10dd228eb7e" + integrity sha512-WIIEazmngMEEHDaPTx0IZY48SaAmjVWe3TRSX7cmJXn0bEv9midFzAjxiruOWYIVf5iQ10vFx7ASDpgEO08L5w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.15.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-typescript" "^7.14.5" + "@babel/plugin-transform-unicode-escapes@^7.14.5": version "7.14.5" resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz" @@ -870,6 +1000,15 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" +"@babel/preset-typescript@^7.14.5": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.15.0.tgz#e8fca638a1a0f64f14e1119f7fe4500277840945" + integrity sha512-lt0Y/8V3y06Wq/8H/u0WakrqciZ7Fz7mwPDHWUJAXlABL5hiUG42BNlRXiELNjeWjO5rWmnNKlx+yzJvxezHow== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-transform-typescript" "^7.15.0" + "@babel/register@^7.13.16": version "7.14.5" resolved "https://registry.npmjs.org/@babel/register/-/register-7.14.5.tgz" @@ -881,7 +1020,7 @@ pirates "^4.0.0" source-map-support "^0.5.16" -"@babel/runtime-corejs3@^7.10.2", "@babel/runtime-corejs3@^7.12.1": +"@babel/runtime-corejs3@^7.10.2": version "7.14.6" resolved "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.14.6.tgz" integrity sha512-Xl8SPYtdjcMoCsIM4teyVRg7jIcgl8F2kRtoCcXuHzXswt9UxZCS6BzRo8fcnCuP6u2XtPgvyonmEPF57Kxo9Q== @@ -920,6 +1059,21 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.0.tgz#4cca838fd1b2a03283c1f38e141f639d60b3fc98" + integrity sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.0" + "@babel/helper-function-name" "^7.14.5" + "@babel/helper-hoist-variables" "^7.14.5" + "@babel/helper-split-export-declaration" "^7.14.5" + "@babel/parser" "^7.15.0" + "@babel/types" "^7.15.0" + debug "^4.1.0" + globals "^11.1.0" + "@babel/types@^7.0.0", "@babel/types@^7.12.0", "@babel/types@^7.13.0", "@babel/types@^7.14.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.6.1", "@babel/types@^7.7.0", "@babel/types@^7.9.6": version "7.14.5" resolved "https://registry.npmjs.org/@babel/types/-/types-7.14.5.tgz" @@ -928,6 +1082,14 @@ "@babel/helper-validator-identifier" "^7.14.5" to-fast-properties "^2.0.0" +"@babel/types@^7.14.8", "@babel/types@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.0.tgz#61af11f2286c4e9c69ca8deb5f4375a73c72dcbd" + integrity sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ== + dependencies: + "@babel/helper-validator-identifier" "^7.14.9" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" @@ -941,6 +1103,131 @@ exec-sh "^0.3.2" minimist "^1.2.0" +"@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + +"@cspotcode/source-map-support@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz#118511f316e2e87ee4294761868e254d3da47960" + integrity sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + +"@cucumber/create-meta@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@cucumber/create-meta/-/create-meta-5.0.0.tgz#baea1a40ec823881eeefc29a523d6c87d13f4016" + integrity sha512-Z5kMZkUff00S3/KSnKzB/KOm2UIxMXY1xXmj2dQMlD49lV6v/W8EEvgDMNtQotQNSOQU5bDupmWQpk+o16tXIw== + dependencies: + "@cucumber/messages" "^16.0.0" + +"@cucumber/cucumber-expressions@^12.1.1": + version "12.1.2" + resolved "https://registry.yarnpkg.com/@cucumber/cucumber-expressions/-/cucumber-expressions-12.1.2.tgz#b80cb59e18e988eb284b5b8a4b97c9dfb3c6e6f3" + integrity sha512-3iSezyIpuc5NlEphh5gNiqGx4p9l+3n9qnhMbKP7ouJ1BjbTa7w+f8f5g13+n+i6TkJ08l+CtUrFXanoBbsxIQ== + dependencies: + becke-ch--regex--s0-0-v1--base--pl--lib "1.4.0" + +"@cucumber/cucumber@*", "@cucumber/cucumber@^7.3.1": + version "7.3.1" + resolved "https://registry.yarnpkg.com/@cucumber/cucumber/-/cucumber-7.3.1.tgz#1339abc92044f865043eceb2993da15cee0cd255" + integrity sha512-x1+/AvouZy205ZvfYbeEVat5aBAj4EeLt9TZfD7pO9j+tQ3W6uxSuDB1TKfxAXFU3WYrswor0CXoJBYOIZhzMw== + dependencies: + "@cucumber/create-meta" "^5.0.0" + "@cucumber/cucumber-expressions" "^12.1.1" + "@cucumber/gherkin" "^19.0.3" + "@cucumber/gherkin-streams" "^2.0.2" + "@cucumber/html-formatter" "^15.0.2" + "@cucumber/messages" "^16.0.1" + "@cucumber/tag-expressions" "^3.0.1" + assertion-error-formatter "^3.0.0" + bluebird "^3.7.2" + capital-case "^1.0.4" + cli-table3 "^0.6.0" + colors "^1.4.0" + commander "^7.0.0" + create-require "^1.1.1" + duration "^0.2.2" + durations "^3.4.2" + figures "^3.2.0" + glob "^7.1.6" + indent-string "^4.0.0" + is-generator "^1.0.3" + is-stream "^2.0.0" + knuth-shuffle-seeded "^1.0.6" + lodash "^4.17.21" + mz "^2.7.0" + progress "^2.0.3" + resolve "^1.19.0" + resolve-pkg "^2.0.0" + stack-chain "^2.0.0" + stacktrace-js "^2.0.2" + string-argv "^0.3.1" + tmp "^0.2.1" + util-arity "^1.1.0" + verror "^1.10.0" + +"@cucumber/gherkin-streams@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@cucumber/gherkin-streams/-/gherkin-streams-2.0.2.tgz#de09e279fe793e93ee83606376df291954fef83b" + integrity sha512-cKmXOBz4OwGlrHMBCc4qCC3KzLaqcEZ11nWWskIbv6jyfvlIRuM2OgEF6VLcNVewczifW1p6DrDj0OO+BeXocA== + dependencies: + "@cucumber/gherkin" "^19.0.1" + "@cucumber/message-streams" "^2.0.0" + "@cucumber/messages" "^16.0.0" + commander "7.2.0" + source-map-support "0.5.19" + +"@cucumber/gherkin@^19.0.1", "@cucumber/gherkin@^19.0.3": + version "19.0.3" + resolved "https://registry.yarnpkg.com/@cucumber/gherkin/-/gherkin-19.0.3.tgz#61036ca4940e66f8a787be5f92ce229ae3815ebf" + integrity sha512-gWdMm8mfRk3P+VugJWvNALaQV5QnT+5RkqWy3tO+4NsMSQZPo5p4V4vXwriQZ/sZR1Wni5TDRztuRsKLgZ3XHA== + dependencies: + "@cucumber/message-streams" "^2.0.0" + "@cucumber/messages" "^16.0.1" + +"@cucumber/html-formatter@^15.0.2": + version "15.0.2" + resolved "https://registry.yarnpkg.com/@cucumber/html-formatter/-/html-formatter-15.0.2.tgz#0a4c7d3c5de7de0a1b87a8a9af9eca54280175aa" + integrity sha512-j+YGY4ytj78G/v1gZo53D+vuKXlTg/oxNwSCCGvRQo75+AqYDJSkm/vexXJQ5lY1rXAvlbZ9KI6jhg6LDs0YdQ== + dependencies: + "@cucumber/messages" "^16.0.1" + commander "7.2.0" + source-map-support "0.5.19" + +"@cucumber/message-streams@^2.0.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@cucumber/message-streams/-/message-streams-2.1.0.tgz#07a7a814ee7c39386a939d5afec2902f5199ffd2" + integrity sha512-Yh3mw3qv6QL9NI/ihkZF8V9MX2GbnR6oktv34kC3uAbrQy9d/b2SZ3HNjG3J9JQqpV4B7Om3SPElJYIeo66TrA== + dependencies: + "@cucumber/messages" "^16.0.1" + +"@cucumber/messages@^16.0.0", "@cucumber/messages@^16.0.1": + version "16.0.1" + resolved "https://registry.yarnpkg.com/@cucumber/messages/-/messages-16.0.1.tgz#8a9f9bb6ad0430d8ddd044dd49cb45ef37ee67b7" + integrity sha512-80JcaAfQragFqR1rMhRwiqWL9HcR6Z4LDD2mfF0Lxg/lFkCNvmWa9Jl10NUNfFXYD555NKPzP/8xFo55abw8TQ== + dependencies: + "@types/uuid" "8.3.0" + class-transformer "0.4.0" + reflect-metadata "0.1.13" + uuid "8.3.2" + +"@cucumber/pretty-formatter@^1.0.0-alpha.1": + version "1.0.0-alpha.1" + resolved "https://registry.yarnpkg.com/@cucumber/pretty-formatter/-/pretty-formatter-1.0.0-alpha.1.tgz#361eb972036c6cf114f2978b42c79c48ea800f0e" + integrity sha512-emVFdRkEFAqksd3X9cMWn7cOE2fIPB0aTwZAFZPMO55ZRf+7IaZ7VlEY2Pd5qPxhTXNmyZvaBf6AOoZmx47pmA== + dependencies: + ansi-styles "^5.0.0" + cli-table3 "^0.6.0" + figures "^3.2.0" + ts-dedent "^2.0.0" + +"@cucumber/tag-expressions@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@cucumber/tag-expressions/-/tag-expressions-3.0.1.tgz#ca0702342bc4234ad73d9de3f1bf97461c3b5eb7" + integrity sha512-OGCXaJ1BQXmQ5b9pw+JYsBGumK2/LPZiLmbj1o1JFVeSNs2PY8WPQFSyXrskhrHz5Nd/6lYg7lvGMtFHOncC4w== + "@erquhart/browserify-fs@^1.0.2": version "1.0.2" resolved "https://registry.npmjs.org/@erquhart/browserify-fs/-/browserify-fs-1.0.2.tgz" @@ -1234,6 +1521,50 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@playwright/test@^1.14.0": + version "1.14.0" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.14.0.tgz#8df90c554c3d10895bab1b3e921e417fdb61f416" + integrity sha512-8jCS6fmzGZTW7e/Tri0tfxhl5bYpsQSDmCA7TtU6F4WV3CgxnOh44KOynol623p5ftVQ08Jdodu/x4WJ1dNqrg== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/core" "^7.14.8" + "@babel/plugin-proposal-class-properties" "^7.14.5" + "@babel/plugin-proposal-dynamic-import" "^7.14.5" + "@babel/plugin-proposal-export-namespace-from" "^7.14.5" + "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5" + "@babel/plugin-proposal-numeric-separator" "^7.14.5" + "@babel/plugin-proposal-optional-chaining" "^7.14.5" + "@babel/plugin-proposal-private-methods" "^7.14.5" + "@babel/plugin-proposal-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-transform-modules-commonjs" "^7.14.5" + "@babel/preset-typescript" "^7.14.5" + colors "^1.4.0" + commander "^6.1.0" + debug "^4.1.1" + expect "^26.4.2" + extract-zip "^2.0.1" + https-proxy-agent "^5.0.0" + jpeg-js "^0.4.2" + mime "^2.4.6" + minimatch "^3.0.3" + ms "^2.1.2" + pirates "^4.0.1" + pixelmatch "^5.2.1" + pngjs "^5.0.0" + progress "^2.0.3" + proper-lockfile "^4.1.1" + proxy-from-env "^1.1.0" + rimraf "^3.0.2" + source-map-support "^0.4.18" + stack-utils "^2.0.3" + ws "^7.4.6" + yazl "^2.5.1" + "@popperjs/core@^2.8.3": version "2.9.2" resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.9.2.tgz" @@ -1351,6 +1682,26 @@ resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@tsconfig/node10@^1.0.7": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" + integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + +"@tsconfig/node12@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" + integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + +"@tsconfig/node14@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" + integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + +"@tsconfig/node16@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" + integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + "@types/aria-query@^4.2.0": version "4.2.1" resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.1.tgz" @@ -1389,6 +1740,13 @@ dependencies: "@babel/types" "^7.3.0" +"@types/cucumber@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@types/cucumber/-/cucumber-7.0.0.tgz#941b25135a0212e315380ab39f7f674c66711b0b" + integrity sha512-cr5NN8/jmbw3vDKTQfGW0cSzDtkvxixu9bUD6po9U6OEF04XLuukTDldFG34ccDscLkA8bYnZ7VjxP79cIC7tg== + dependencies: + "@cucumber/cucumber" "*" + "@types/debug@^4.1.5": version "4.1.5" resolved "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz" @@ -1488,6 +1846,14 @@ resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz" integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA== +"@types/node-fetch@^2.5.12": + version "2.5.12" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66" + integrity sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + "@types/node@*", "@types/node@^15.9.0": version "15.12.2" resolved "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz" @@ -1557,6 +1923,11 @@ resolved "https://registry.npmjs.org/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz" integrity sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ== +"@types/uuid@8.3.0": + version "8.3.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" + integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== + "@types/vue@^2.0.0": version "2.0.0" resolved "https://registry.npmjs.org/@types/vue/-/vue-2.0.0.tgz" @@ -1851,6 +2222,11 @@ acorn-walk@^8.0.0: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.1.0.tgz" integrity sha512-mjmzmv12YIG/G8JQdQuz2MUDShEJ6teYpT5bmWA4q7iwoGen8xtt3twF3OvzIUl+Q06aWIjvnwQUKvQ6TtMRjg== +acorn-walk@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.1.1.tgz#3ddab7f84e4a7e2313f6c414c5b7dac85f4e3ebc" + integrity sha512-FbJdceMlPHEAWJOILDk1fXD8lnTlEIWFkqtfk+MvmL5q/qlHfN7GEHcsFZWt/Tea9jRNPWUZG4G976nqAAmU9w== + acorn@^5.7.3: version "5.7.4" resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz" @@ -1866,6 +2242,11 @@ acorn@^8.2.4: resolved "https://registry.npmjs.org/acorn/-/acorn-8.4.0.tgz" integrity sha512-ULr0LDaEqQrMFGyQ3bhJkLsbtrQ8QibAseGZeaSUiT/6zb9IvIkomWHJIvgvwad+hinRAgsI51JcWk2yvwyL+w== +acorn@^8.4.1: + version "8.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c" + integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA== + agent-base@4, agent-base@^4.2.0, agent-base@^4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz" @@ -1976,6 +2357,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + any-promise@^1.0.0: version "1.3.0" resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" @@ -2026,6 +2412,11 @@ archiver@^3.0.0: tar-stream "^2.1.0" zip-stream "^2.1.2" +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + argparse@^1.0.7: version "1.0.10" resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" @@ -2520,9 +2911,9 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -becke-ch--regex--s0-0-v1--base--pl--lib@^1.4.0: +becke-ch--regex--s0-0-v1--base--pl--lib@1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/becke-ch--regex--s0-0-v1--base--pl--lib/-/becke-ch--regex--s0-0-v1--base--pl--lib-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/becke-ch--regex--s0-0-v1--base--pl--lib/-/becke-ch--regex--s0-0-v1--base--pl--lib-1.4.0.tgz#429ceebbfa5f7e936e78d73fbdc7da7162b20e20" integrity sha1-Qpzuu/pffpNueNc/vcfacWKyDiA= bezier-easing@2.1.0: @@ -2566,7 +2957,7 @@ bl@^4.0.3: inherits "^2.0.4" readable-stream "^3.4.0" -bluebird@^3.1.1, bluebird@^3.4.1, bluebird@^3.5.0, bluebird@^3.7.2: +bluebird@^3.1.1, bluebird@^3.5.0, bluebird@^3.7.2: version "3.7.2" resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== @@ -2857,6 +3248,15 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001228, can resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001237.tgz" integrity sha512-pDHgRndit6p1NR2GhzMbQ6CkRrp4VKuSsqbcLeOQppYPKOYkKT/6ZvZDvKJUqcmtyWIAHuZq3SVS2vc1egCZzw== +capital-case@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" + integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + upper-case-first "^2.0.2" + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz" @@ -3006,6 +3406,11 @@ cjs-module-lexer@^0.6.0: resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz" integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== +class-transformer@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.4.0.tgz#b52144117b423c516afb44cc1c76dbad31c2165b" + integrity sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA== + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz" @@ -3040,13 +3445,13 @@ cli-spinners@^2.2.0: resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz" integrity sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q== -cli-table3@^0.5.1: - version "0.5.1" - resolved "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz" - integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== +cli-table3@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.0.tgz#b7b1bc65ca8e7b5cef9124e13dc2b21e2ce4faee" + integrity sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ== dependencies: object-assign "^4.1.0" - string-width "^2.1.1" + string-width "^4.2.0" optionalDependencies: colors "^1.1.2" @@ -3193,15 +3598,20 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +commander@7.2.0, commander@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + commander@^2.19.0, commander@^2.20.0: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^3.0.1: - version "3.0.2" - resolved "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz" - integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== +commander@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== commander@^8.1.0: version "8.1.0" @@ -3424,6 +3834,11 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +create-require@^1.1.0, create-require@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + cross-fetch@^3.0.4, cross-fetch@^3.0.6: version "3.1.4" resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz" @@ -3686,14 +4101,6 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -cucumber-expressions@^8.1.0: - version "8.3.0" - resolved "https://registry.npmjs.org/cucumber-expressions/-/cucumber-expressions-8.3.0.tgz" - integrity sha512-cP2ya0EiorwXBC7Ll7Cj7NELYbasNv9Ty42L4u7sso9KruWemWG1ZiTq4PMqir3SNDSrbykoqI5wZgMbLEDjLQ== - dependencies: - becke-ch--regex--s0-0-v1--base--pl--lib "^1.4.0" - xregexp "^4.2.4" - cucumber-html-reporter@^5.4.0: version "5.4.0" resolved "https://registry.npmjs.org/cucumber-html-reporter/-/cucumber-html-reporter-5.4.0.tgz" @@ -3709,53 +4116,6 @@ cucumber-html-reporter@^5.4.0: open "^6.4.0" uuid "^3.3.3" -cucumber-pretty@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/cucumber-pretty/-/cucumber-pretty-6.0.0.tgz" - integrity sha512-ddx/VInPVKFB7N86QujgLivihJhuzexKwExMuFaUjSlEs5zVVqBgaf55f88h97VafXTWX+ZAcxTUwMBS4mYj/g== - dependencies: - cli-table3 "^0.5.1" - colors "^1.4.0" - figures "^3.0.0" - -cucumber-tag-expressions@^2.0.2: - version "2.0.3" - resolved "https://registry.npmjs.org/cucumber-tag-expressions/-/cucumber-tag-expressions-2.0.3.tgz" - integrity sha512-+x5j1IfZrBtbvYHuoUX0rl4nUGxaey6Do9sM0CABmZfDCcWXuuRm1fQeCaklIYQgOFHQ6xOHvDSdkMHHpni6tQ== - -cucumber@>=6.0.5: - version "6.0.5" - resolved "https://registry.npmjs.org/cucumber/-/cucumber-6.0.5.tgz" - integrity sha512-x+W9Fwk6TvcapQsYMxwFU5AsQJDOIJVGrPKmH15OC7jzb9/Dk7Hb0ZAyw4WcpaDcUDRc8bi2k2yJejDp5eTRlg== - dependencies: - assertion-error-formatter "^3.0.0" - bluebird "^3.4.1" - cli-table3 "^0.5.1" - colors "^1.1.2" - commander "^3.0.1" - cucumber-expressions "^8.1.0" - cucumber-tag-expressions "^2.0.2" - duration "^0.2.1" - escape-string-regexp "^2.0.0" - figures "^3.0.0" - gherkin "5.0.0" - glob "^7.1.3" - indent-string "^4.0.0" - is-generator "^1.0.2" - is-stream "^2.0.0" - knuth-shuffle-seeded "^1.0.6" - lodash "^4.17.14" - mz "^2.4.0" - progress "^2.0.0" - resolve "^1.3.3" - serialize-error "^4.1.0" - stack-chain "^2.0.0" - stacktrace-js "^2.0.0" - string-argv "^0.3.0" - title-case "^2.1.1" - util-arity "^1.0.2" - verror "^1.9.0" - custom-error-instance@2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/custom-error-instance/-/custom-error-instance-2.1.1.tgz" @@ -4147,14 +4507,19 @@ dropzone@^5.5.1: resolved "https://registry.npmjs.org/dropzone/-/dropzone-5.9.2.tgz" integrity sha512-5t2z51DzIsWDbTpwcJIvUlwxBbvcwdCApz0yb9ecKJwG155Xm92KMEZmHW1B0MzoXOKvFwdd0nPu5cpeVcvPHQ== -duration@^0.2.1: +duration@^0.2.2: version "0.2.2" - resolved "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz" + resolved "https://registry.yarnpkg.com/duration/-/duration-0.2.2.tgz#ddf149bc3bc6901150fe9017111d016b3357f529" integrity sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg== dependencies: d "1" es5-ext "~0.10.46" +durations@^3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/durations/-/durations-3.4.2.tgz#1de230454373cccfecab927de0bebae2295301db" + integrity sha512-V/lf7y33dGaypZZetVI1eu7BmvkbC4dItq12OElLRpKuaU5JxQstV2zHwLv8P7cNbQ+KL1WD80zMCTx5dNC4dg== + easygettext@^2.16.1: version "2.17.0" resolved "https://registry.npmjs.org/easygettext/-/easygettext-2.17.0.tgz" @@ -4746,9 +5111,9 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expect@^26.6.2: +expect@^26.4.2, expect@^26.6.2: version "26.6.2" - resolved "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz" + resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== dependencies: "@jest/types" "^26.6.2" @@ -4890,9 +5255,9 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" -figures@^3.0.0: +figures@^3.2.0: version "3.2.0" - resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== dependencies: escape-string-regexp "^1.0.5" @@ -5252,11 +5617,6 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -gherkin@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/gherkin/-/gherkin-5.0.0.tgz" - integrity sha1-lt70EZjsOQgli1Ea909lWidk0qE= - git-repo-info@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/git-repo-info/-/git-repo-info-2.1.1.tgz" @@ -5952,9 +6312,9 @@ is-generator-fn@^2.0.0: resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-generator@^1.0.2: +is-generator@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/is-generator/-/is-generator-1.0.3.tgz#c14c21057ed36e328db80347966c693f886389f3" integrity sha1-wUwhBX7TbjKNuANHlmxpP4hjifM= is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: @@ -6719,6 +7079,11 @@ jpeg-js@^0.2.0: resolved "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz" integrity sha1-U+RI7J0mPmgyZkZ+lELSxaLvVII= +jpeg-js@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b" + integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q== + js-base64@^2.1.9, js-base64@^2.3.2, js-base64@^2.4.9: version "2.6.4" resolved "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz" @@ -7451,10 +7816,12 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -lower-case@^1.1.1: - version "1.1.4" - resolved "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz" - integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" lru-cache@^4.1.2, lru-cache@^4.1.5: version "4.1.5" @@ -7529,7 +7896,7 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" -make-error@1.x: +make-error@1.x, make-error@^1.1.1: version "1.3.6" resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -7650,9 +8017,9 @@ mime-types@^2.1.12, mime-types@~2.1.19: dependencies: mime-db "1.48.0" -mime@>=2.4.6: +mime@>=2.4.6, mime@^2.4.6: version "2.5.2" - resolved "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== mime@^1.3.4, mime@^1.4.1: @@ -7687,7 +8054,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -minimatch@3.0.4, minimatch@^3.0.4: +minimatch@3.0.4, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -7787,9 +8154,9 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: +ms@^2.1.1, ms@^2.1.2: version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== multimatch@^5.0.0: @@ -7808,9 +8175,9 @@ mute-stream@0.0.8: resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -mz@^2.4.0: +mz@^2.7.0: version "2.7.0" - resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== dependencies: any-promise "^1.0.0" @@ -7910,12 +8277,13 @@ nightwatch@1.5.1: semver "^6.3.0" strip-ansi "^6.0.0" -no-case@^2.2.0: - version "2.3.2" - resolved "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz" - integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== dependencies: - lower-case "^1.1.1" + lower-case "^2.0.2" + tslib "^2.0.3" node-addon-api@^1.7.1: version "1.7.2" @@ -8582,6 +8950,13 @@ pixelmatch@^4.0.0: dependencies: pngjs "^3.0.0" +pixelmatch@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.2.1.tgz#9e4e4f4aa59648208a31310306a5bed5522b0d65" + integrity sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ== + dependencies: + pngjs "^4.0.1" + pkg-dir@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz" @@ -8610,6 +8985,26 @@ pkg-up@^2.0.0: dependencies: find-up "^2.1.0" +playwright@^1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.14.0.tgz#18301b11f5278a446d36b5cf96f67db36ce2cd20" + integrity sha512-aR5oZ1iVsjQkGfYCjgYAmyMAVu0MQ0i8MgdnfdqDu9EVLfbnpuuFmTv/Rb7/Yjno1kOrDUP9+RyNC+zfG3wozA== + dependencies: + commander "^6.1.0" + debug "^4.1.1" + extract-zip "^2.0.1" + https-proxy-agent "^5.0.0" + jpeg-js "^0.4.2" + mime "^2.4.6" + pngjs "^5.0.0" + progress "^2.0.3" + proper-lockfile "^4.1.1" + proxy-from-env "^1.1.0" + rimraf "^3.0.2" + stack-utils "^2.0.3" + ws "^7.4.6" + yazl "^2.5.1" + please-upgrade-node@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz" @@ -8622,6 +9017,16 @@ pngjs@^3.0.0: resolved "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz" integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== +pngjs@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-4.0.1.tgz#f803869bb2fc1bfe1bf99aa4ec21c108117cfdbe" + integrity sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg== + +pngjs@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" + integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== + pofile@^1.1.0: version "1.1.1" resolved "https://registry.npmjs.org/pofile/-/pofile-1.1.1.tgz" @@ -9096,9 +9501,9 @@ process@^0.11.10: resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= -progress@^2.0.0: +progress@^2.0.0, progress@^2.0.3: version "2.0.3" - resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== promise-polyfill@^8.1.3: @@ -9141,6 +9546,15 @@ proper-lockfile@^2.0.1: graceful-fs "^4.1.2" retry "^0.10.0" +proper-lockfile@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" + integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== + dependencies: + graceful-fs "^4.2.4" + retry "^0.12.0" + signal-exit "^3.0.2" + proto-list@~1.2.1: version "1.2.4" resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz" @@ -9479,6 +9893,11 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +reflect-metadata@0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + regenerate-unicode-properties@^8.2.0: version "8.2.0" resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz" @@ -9655,12 +10074,19 @@ resolve-from@^5.0.0: resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +resolve-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-2.0.0.tgz#ac06991418a7623edc119084edc98b0e6bf05a41" + integrity sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ== + dependencies: + resolve-from "^5.0.0" + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.15.1, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.3.3: +resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.15.1, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.19.0, resolve@^1.20.0: version "1.20.0" resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== @@ -9686,6 +10112,11 @@ retry@^0.10.0: resolved "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz" integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + reusify@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" @@ -10009,13 +10440,6 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -serialize-error@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/serialize-error/-/serialize-error-4.1.0.tgz" - integrity sha512-5j9GgyGsP9vV9Uj1S0lDCvlsd+gc2LEPVK7HHHte7IyPwOD4lVQFeaX143gx3U5AnoCi+wbcb3mvaxVysjpxEw== - dependencies: - type-fest "^0.3.0" - serialize-javascript@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz" @@ -10198,7 +10622,7 @@ source-map-resolve@^0.6.0: atob "^2.1.2" decode-uri-component "^0.2.0" -source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.19: +source-map-support@0.5.19, source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.19: version "0.5.19" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== @@ -10206,6 +10630,13 @@ source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.1 buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@^0.4.18: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" + source-map-url@^0.4.0: version "0.4.1" resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz" @@ -10311,9 +10742,9 @@ stack-generator@^2.0.5: dependencies: stackframe "^1.1.1" -stack-utils@^2.0.2: +stack-utils@^2.0.2, stack-utils@^2.0.3: version "2.0.3" - resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.3.tgz#cd5f030126ff116b78ccb3c027fe302713b61277" integrity sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw== dependencies: escape-string-regexp "^2.0.0" @@ -10331,9 +10762,9 @@ stacktrace-gps@^3.0.4: source-map "0.5.6" stackframe "^1.1.1" -stacktrace-js@^2.0.0: +stacktrace-js@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/stacktrace-js/-/stacktrace-js-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/stacktrace-js/-/stacktrace-js-2.0.2.tgz#4ca93ea9f494752d55709a081d400fdaebee897b" integrity sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg== dependencies: error-stack-parser "^2.0.6" @@ -10375,9 +10806,9 @@ strict-uri-encode@^2.0.0: resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz" integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= -string-argv@^0.3.0: +string-argv@^0.3.1: version "0.3.1" - resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== string-hash@^1.1.0, string-hash@^1.1.1: @@ -10398,7 +10829,7 @@ string-range@~1.2, string-range@~1.2.1: resolved "https://registry.npmjs.org/string-range/-/string-range-1.2.2.tgz" integrity sha1-qJPtNH5yKZvIO++78qaSqNI51d0= -"string-width@^1.0.2 || 2", string-width@^2.1.1: +"string-width@^1.0.2 || 2": version "2.1.1" resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -10752,13 +11183,12 @@ tippy.js@^6.3.1: dependencies: "@popperjs/core" "^2.8.3" -title-case@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz" - integrity sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o= +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== dependencies: - no-case "^2.2.0" - upper-case "^1.0.3" + rimraf "^3.0.0" tmpl@1.0.x: version "1.0.4" @@ -10866,6 +11296,11 @@ ts-clone-node@^0.3.23: dependencies: compatfactory "^0.0.8" +ts-dedent@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" + integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== + ts-jest@^26.5.6: version "26.5.6" resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz" @@ -10882,6 +11317,24 @@ ts-jest@^26.5.6: semver "7.x" yargs-parser "20.x" +ts-node@^10.2.0: + version "10.2.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.2.1.tgz#4cc93bea0a7aba2179497e65bb08ddfc198b3ab5" + integrity sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw== + dependencies: + "@cspotcode/source-map-support" "0.6.1" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + yn "3.1.1" + tsconfig-paths@^3.9.0: version "3.9.0" resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz" @@ -10912,6 +11365,11 @@ tslib@^2.0.1, tslib@^2.2.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz" integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== +tslib@^2.0.3: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" @@ -10978,11 +11436,6 @@ type-fest@^0.21.3: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -type-fest@^0.3.0: - version "0.3.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz" - integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== - type-fest@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz" @@ -11111,10 +11564,12 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" -upper-case@^1.0.3: - version "1.1.3" - resolved "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz" - integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= +upper-case-first@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" + integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== + dependencies: + tslib "^2.0.3" uri-js@^4.2.2: version "4.4.1" @@ -11168,9 +11623,9 @@ utf8@^3.0.0: resolved "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz" integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== -util-arity@^1.0.2: +util-arity@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/util-arity/-/util-arity-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/util-arity/-/util-arity-1.1.0.tgz#59d01af1fdb3fede0ac4e632b0ab5f6ce97c9330" integrity sha1-WdAa8f2z/t4KxOYysKtfbOl8kzA= util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: @@ -11188,16 +11643,16 @@ util.promisify@~1.0.0: has-symbols "^1.0.1" object.getownpropertydescriptors "^2.1.0" +uuid@8.3.2, uuid@^8.2.0, uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + uuid@^3.3.2, uuid@^3.3.3: version "3.4.0" resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.2.0, uuid@^8.3.0: - version "8.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - v8-compile-cache@^2.0.3: version "2.3.0" resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz" @@ -11237,9 +11692,9 @@ vendors@^1.0.0: resolved "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz" integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== -verror@1.10.0, verror@^1.8.1, verror@^1.9.0: +verror@1.10.0, verror@^1.10.0, verror@^1.8.1: version "1.10.0" - resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= dependencies: assert-plus "^1.0.0" @@ -11608,6 +12063,11 @@ ws@^7.4.3, ws@^7.4.5: resolved "https://registry.npmjs.org/ws/-/ws-7.5.0.tgz" integrity sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw== +ws@^7.4.6: + version "7.5.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" + integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg== + xhr@^2.0.1, xhr@^2.5.0: version "2.6.0" resolved "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz" @@ -11668,13 +12128,6 @@ xregexp@2.0.0: resolved "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz" integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM= -xregexp@^4.2.4: - version "4.4.1" - resolved "https://registry.npmjs.org/xregexp/-/xregexp-4.4.1.tgz" - integrity sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag== - dependencies: - "@babel/runtime-corejs3" "^7.12.1" - xtend@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/xtend/-/xtend-2.2.0.tgz" @@ -11807,6 +12260,18 @@ yauzl@^2.10.0: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" +yazl@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35" + integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw== + dependencies: + buffer-crc32 "~0.2.3" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + zip-stream@^2.1.2: version "2.1.3" resolved "https://registry.npmjs.org/zip-stream/-/zip-stream-2.1.3.tgz"