From 546ed16c77f44727d5b09e1e7197182e1bd41de9 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Thu, 14 Apr 2022 12:23:31 -0400 Subject: [PATCH 01/16] fix(cli): show additional mitigation steps for max path length error (#21047) --- cli/__snapshots__/errors_spec.js | 1 + cli/__snapshots__/unzip_spec.js | 20 +++++++++++++- cli/lib/errors.js | 8 ++++++ cli/lib/tasks/unzip.js | 29 +++++++++++++------- cli/test/lib/tasks/unzip_spec.js | 46 ++++++++++++++++++++++---------- 5 files changed, 79 insertions(+), 25 deletions(-) diff --git a/cli/__snapshots__/errors_spec.js b/cli/__snapshots__/errors_spec.js index e254269f2d30..e5ce248b8a71 100644 --- a/cli/__snapshots__/errors_spec.js +++ b/cli/__snapshots__/errors_spec.js @@ -32,6 +32,7 @@ exports['errors individual has the following errors 1'] = [ "childProcessKilled", "failedDownload", "failedUnzip", + "failedUnzipWindowsMaxPathLength", "incompatibleHeadlessFlags", "invalidCacheDirectory", "invalidCypressEnv", diff --git a/cli/__snapshots__/unzip_spec.js b/cli/__snapshots__/unzip_spec.js index 830187db819b..ec4edf9dc004 100644 --- a/cli/__snapshots__/unzip_spec.js +++ b/cli/__snapshots__/unzip_spec.js @@ -1,4 +1,4 @@ -exports['unzip error 1'] = ` +exports['lib/tasks/unzip throws when cannot unzip 1'] = ` Error: The Cypress App could not be unzipped. Search for an existing issue or open a GitHub issue at @@ -15,3 +15,21 @@ Platform: darwin-x64 (Foo-OsVersion) Cypress Version: 1.2.3 ` + +exports['lib/tasks/unzip throws max path length error when cannot unzip due to realpath ENOENT on windows 1'] = ` +Error: The Cypress App could not be unzipped. + +This is most likely because the maximum path length is being exceeded on your system. + +Read here for solutions to this problem: https://on.cypress.io/win-max-path-length-error + +---------- + +Error: failed + +---------- + +Platform: win32-x64 (Foo-OsVersion) +Cypress Version: 1.2.3 + +` diff --git a/cli/lib/errors.js b/cli/lib/errors.js index ca460ec41a37..397123d5da6e 100644 --- a/cli/lib/errors.js +++ b/cli/lib/errors.js @@ -58,6 +58,13 @@ const failedUnzip = { solution: genericErrorSolution, } +const failedUnzipWindowsMaxPathLength = { + description: 'The Cypress App could not be unzipped.', + solution: `This is most likely because the maximum path length is being exceeded on your system. + + Read here for solutions to this problem: https://on.cypress.io/win-max-path-length-error`, +} + const missingApp = (binaryDir) => { return { description: `No version of Cypress is installed in: ${chalk.cyan( @@ -404,6 +411,7 @@ module.exports = { unexpected, failedDownload, failedUnzip, + failedUnzipWindowsMaxPathLength, invalidCypressEnv, invalidCacheDirectory, CYPRESS_RUN_BINARY, diff --git a/cli/lib/tasks/unzip.js b/cli/lib/tasks/unzip.js index ce665dfcd738..5993bd2700a3 100644 --- a/cli/lib/tasks/unzip.js +++ b/cli/lib/tasks/unzip.js @@ -195,7 +195,11 @@ const unzip = ({ zipFilePath, installDir, progress }) => { }) } -const start = ({ zipFilePath, installDir, progress }) => { +function isMaybeWindowsMaxPathLengthError (err) { + return os.platform() === 'win32' && err.code === 'ENOENT' && err.syscall === 'realpath' +} + +const start = async ({ zipFilePath, installDir, progress }) => { la(is.unemptyString(installDir), 'missing installDir') if (!progress) { progress = { onProgress: () => { @@ -203,18 +207,23 @@ const start = ({ zipFilePath, installDir, progress }) => { } } } - return fs.pathExists(installDir) - .then((exists) => { - if (exists) { + try { + const installDirExists = await fs.pathExists(installDir) + + if (installDirExists) { debug('removing existing unzipped binary', installDir) - return fs.removeAsync(installDir) + await fs.removeAsync(installDir) } - }) - .then(() => { - return unzip({ zipFilePath, installDir, progress }) - }) - .catch(throwFormErrorText(errors.failedUnzip)) + + await unzip({ zipFilePath, installDir, progress }) + } catch (err) { + const errorTemplate = isMaybeWindowsMaxPathLengthError(err) ? + errors.failedUnzipWindowsMaxPathLength + : errors.failedUnzip + + await throwFormErrorText(errorTemplate)(err) + } } module.exports = { diff --git a/cli/test/lib/tasks/unzip_spec.js b/cli/test/lib/tasks/unzip_spec.js index c16cac91c3a5..286439f67010 100644 --- a/cli/test/lib/tasks/unzip_spec.js +++ b/cli/test/lib/tasks/unzip_spec.js @@ -30,26 +30,44 @@ describe('lib/tasks/unzip', function () { afterEach(function () { stdout.restore() + }) + + it('throws when cannot unzip', async function () { + try { + await unzip.start({ + zipFilePath: path.join('test', 'fixture', 'bad_example.zip'), + installDir, + }) + } catch (err) { + logger.error(err) - // return fs.removeAsync(installationDir) + return snapshot(normalize(this.stdout.toString())) + } + + throw new Error('should have failed') }) - it('throws when cannot unzip', function () { - const ctx = this + it('throws max path length error when cannot unzip due to realpath ENOENT on windows', async function () { + const err = new Error('failed') - return unzip - .start({ - zipFilePath: path.join('test', 'fixture', 'bad_example.zip'), - installDir, - }) - .then(() => { - throw new Error('should have failed') - }) - .catch((err) => { + err.code = 'ENOENT' + err.syscall = 'realpath' + + os.platform.returns('win32') + sinon.stub(fs, 'ensureDirAsync').rejects(err) + + try { + await unzip.start({ + zipFilePath: path.join('test', 'fixture', 'bad_example.zip'), + installDir, + }) + } catch (err) { logger.error(err) - snapshot('unzip error 1', normalize(ctx.stdout.toString())) - }) + return snapshot(normalize(this.stdout.toString())) + } + + throw new Error('should have failed') }) it('can really unzip', function () { From e5002f0368ead86b4d0471834aeac37379474e5c Mon Sep 17 00:00:00 2001 From: Kukhyeon Heo Date: Fri, 15 Apr 2022 02:24:08 +0900 Subject: [PATCH 02/16] fix: cy.type('{enter}') on elements submits the form correctly after Firefox 98. (#21042) * fix: cy.type('{enter}') submits the form correctly after Firefox 98. * simplify condition. --- packages/driver/src/cy/commands/actions/type.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/driver/src/cy/commands/actions/type.ts b/packages/driver/src/cy/commands/actions/type.ts index a00836000ef6..e131970b38f8 100644 --- a/packages/driver/src/cy/commands/actions/type.ts +++ b/packages/driver/src/cy/commands/actions/type.ts @@ -174,6 +174,8 @@ export default function (Commands, Cypress, cy, state, config) { } const type = function () { + const isFirefoxBefore98 = Cypress.isBrowser('firefox') && Cypress.browserMajorVersion() < 98 + const simulateSubmitHandler = function () { const form = options.$el.parents('form') @@ -231,11 +233,11 @@ export default function (Commands, Cypress, cy, state, config) { return } - // In Firefox, submit event is automatically fired + // Before Firefox 98, submit event is automatically fired // when we send {Enter} KeyboardEvent to the input fields. // Because of that, we don't have to click the submit buttons. // Otherwise, we trigger submit events twice. - if (!Cypress.isBrowser('firefox')) { + if (!isFirefoxBefore98) { // issue the click event to the 'default button' of the form // we need this to be synchronous so not going through our // own click command @@ -274,7 +276,6 @@ export default function (Commands, Cypress, cy, state, config) { const isContentEditable = $elements.isContentEditable(options.$el.get(0)) const isTextarea = $elements.isTextarea(options.$el.get(0)) - const isFirefoxBefore98 = Cypress.isBrowser('firefox') && Cypress.browserMajorVersion() < 98 const fireClickEvent = (el) => { const ctor = $dom.getDocumentFromElement(el).defaultView!.PointerEvent From 71a18e4321d93e5ae4a34a182494e619f22f2850 Mon Sep 17 00:00:00 2001 From: Tyler Biethman Date: Thu, 14 Apr 2022 13:42:21 -0500 Subject: [PATCH 03/16] chore(deps): Bumping electron dependency to 15.5.1 (#21072) * chore(deps): Bumping electron dependency to 15.5.1 * Updating Settings test that was producing flaky snapshots --- packages/desktop-gui/cypress/integration/settings_spec.js | 1 + packages/electron/package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/desktop-gui/cypress/integration/settings_spec.js b/packages/desktop-gui/cypress/integration/settings_spec.js index 1dbb21318d21..ce5bb6db1e8f 100644 --- a/packages/desktop-gui/cypress/integration/settings_spec.js +++ b/packages/desktop-gui/cypress/integration/settings_spec.js @@ -447,6 +447,7 @@ describe('Settings', () => { cy.get('.settings-record-key') .contains(`cypress run --record --key ${this.keys[0].id}`) + cy.ensureAnimationsFinished() cy.percySnapshot() }) diff --git a/packages/electron/package.json b/packages/electron/package.json index 9cca9c9c043a..b26f05540947 100644 --- a/packages/electron/package.json +++ b/packages/electron/package.json @@ -23,7 +23,7 @@ "minimist": "1.2.6" }, "devDependencies": { - "electron": "15.3.5", + "electron": "15.5.1", "electron-packager": "15.4.0", "execa": "4.1.0", "mocha": "3.5.3" diff --git a/yarn.lock b/yarn.lock index 6a2bbffbe0ae..e593d6a0a68b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18141,10 +18141,10 @@ electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.378, electron-to-chromi resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.727.tgz#857e310ca00f0b75da4e1db6ff0e073cc4a91ddf" integrity sha512-Mfz4FIB4FSvEwBpDfdipRIrwd6uo8gUDoRDF4QEYb4h4tSuI3ov594OrjU6on042UlFHouIJpClDODGkPcBSbg== -electron@15.3.5: - version "15.3.5" - resolved "https://registry.yarnpkg.com/electron/-/electron-15.3.5.tgz#62fc7d2289d3f47e9e05c0aa9bb6d929a6faf398" - integrity sha512-z0/7+p3uZYBmjf7UEVBfcMTVgW6ThGgfI4jdbQ1TH4XOLYkj560/abv91/s8kK0MZ7JQg4KRP1JwQZ4q6+BPFw== +electron@15.5.1: + version "15.5.1" + resolved "https://registry.yarnpkg.com/electron/-/electron-15.5.1.tgz#6c2a7080dfbe4f8571098ce0dc230101b7e0c3f4" + integrity sha512-V3tOikVM7tGK4n5+MkLN+v73h0tndDeaQXy8kjkHj5NFIgQPwKD9S8XjQOBa+Cm5l3xbQrUsN5X6OmYS2WfPlg== dependencies: "@electron/get" "^1.13.0" "@types/node" "^14.6.2" From 92d94252ca90c10d65b4d8ce4a5b6bbebed87b18 Mon Sep 17 00:00:00 2001 From: Ahmed Tarek Date: Fri, 15 Apr 2022 17:35:45 +0200 Subject: [PATCH 04/16] fix: types for Cypress.Commands.add (#20376) (#20377) Co-authored-by: Emily Rohrbough --- cli/types/cypress.d.ts | 9 ++++++--- cli/types/tests/cypress-tests.ts | 15 +++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index bfb7c84822fd..7988514d92e5 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -10,10 +10,12 @@ declare namespace Cypress { type PrevSubject = keyof PrevSubjectMap type TestingType = 'e2e' | 'component' type PluginConfig = (on: PluginEvents, config: PluginConfigOptions) => void | ConfigOptions | Promise - + interface JQueryWithSelector extends JQuery { + selector?: string | null + } interface PrevSubjectMap { optional: O - element: JQuery + element: JQueryWithSelector document: Document window: Window } @@ -467,8 +469,9 @@ declare namespace Cypress { Commands: { add(name: T, fn: CommandFn): void add(name: T, options: CommandOptions & {prevSubject: false}, fn: CommandFn): void + add(name: T, options: CommandOptions & {prevSubject: true}, fn: CommandFnWithSubject): void add( - name: T, options: CommandOptions & { prevSubject: true | S | ['optional'] }, fn: CommandFnWithSubject, + name: T, options: CommandOptions & { prevSubject: S | ['optional'] }, fn: CommandFnWithSubject, ): void add( name: T, options: CommandOptions & { prevSubject: S[] }, fn: CommandFnWithSubject[S]>, diff --git a/cli/types/tests/cypress-tests.ts b/cli/types/tests/cypress-tests.ts index eecb36f65909..9c8bf219cff7 100644 --- a/cli/types/tests/cypress-tests.ts +++ b/cli/types/tests/cypress-tests.ts @@ -83,7 +83,7 @@ namespace CypressCommandsTests { arg // $ExpectType string }) Cypress.Commands.add('newCommand', { prevSubject: true }, (subject, arg) => { - subject // $ExpectType unknown + subject // $ExpectType any arg // $ExpectType string return }) @@ -113,11 +113,13 @@ namespace CypressCommandsTests { arg // $ExpectType string }) Cypress.Commands.add('newCommand', { prevSubject: 'element' }, (subject, arg) => { - subject // $ExpectType JQuery + subject // $ExpectType JQueryWithSelector + subject.selector // $ExpectType string | null | undefined arg // $ExpectType string }) Cypress.Commands.add('newCommand', { prevSubject: ['element'] }, (subject, arg) => { - subject // $ExpectType JQuery + subject // $ExpectType JQueryWithSelector + subject.selector // $ExpectType string | null | undefined arg // $ExpectType string }) Cypress.Commands.add('newCommand', { prevSubject: ['element', 'document', 'window'] }, (subject, arg) => { @@ -126,7 +128,8 @@ namespace CypressCommandsTests { } else if (subject instanceof Document) { subject // $ExpectType Document } else { - subject // $ExpectType JQuery + subject // $ExpectType JQueryWithSelector + subject.selector // $ExpectType string | null | undefined } arg // $ExpectType string }) @@ -136,7 +139,7 @@ namespace CypressCommandsTests { } else if (subject instanceof Document) { subject // $ExpectType Document } else if (subject) { - subject // $ExpectType JQuery + subject // $ExpectType JQueryWithSelector } else { subject // $ExpectType void } @@ -271,7 +274,7 @@ namespace CypressCommandsTests { originalFn.apply(this, [arg]) // $ExpectType Chainable }) Cypress.Commands.overwrite<'type', 'element'>('type', (originalFn, element, text, options?: Partial) => { - element // $ExpectType JQuery + element // $ExpectType JQueryWithSelector text // $ExpectType string if (options && options.sensitive) { From a0ed4a08e9844285e9edc570ba7618d82d55d3d6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Apr 2022 11:26:43 -0500 Subject: [PATCH 05/16] chore: Update Chrome (stable) to 100.0.4896.127 and Chrome (beta) to 101.0.4951.34 (#21083) Co-authored-by: cypress-bot[bot] <2f0651858c6e38e0+cypress-bot[bot]@users.noreply.github.com> --- browser-versions.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browser-versions.json b/browser-versions.json index 02d247ccea58..7cda3cd22949 100644 --- a/browser-versions.json +++ b/browser-versions.json @@ -1,4 +1,4 @@ { - "chrome:beta": "101.0.4951.26", - "chrome:stable": "100.0.4896.88" + "chrome:beta": "101.0.4951.34", + "chrome:stable": "100.0.4896.127" } From 79267ddc0fdc5e82fcd2fba2e08ecd1e7a5c362e Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Fri, 15 Apr 2022 15:03:36 -0400 Subject: [PATCH 06/16] fix: revert "fix: types for Cypress.Commands.add (#20376)" (#21104) --- cli/types/cypress.d.ts | 9 +++------ cli/types/tests/cypress-tests.ts | 15 ++++++--------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index 7988514d92e5..bfb7c84822fd 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -10,12 +10,10 @@ declare namespace Cypress { type PrevSubject = keyof PrevSubjectMap type TestingType = 'e2e' | 'component' type PluginConfig = (on: PluginEvents, config: PluginConfigOptions) => void | ConfigOptions | Promise - interface JQueryWithSelector extends JQuery { - selector?: string | null - } + interface PrevSubjectMap { optional: O - element: JQueryWithSelector + element: JQuery document: Document window: Window } @@ -469,9 +467,8 @@ declare namespace Cypress { Commands: { add(name: T, fn: CommandFn): void add(name: T, options: CommandOptions & {prevSubject: false}, fn: CommandFn): void - add(name: T, options: CommandOptions & {prevSubject: true}, fn: CommandFnWithSubject): void add( - name: T, options: CommandOptions & { prevSubject: S | ['optional'] }, fn: CommandFnWithSubject, + name: T, options: CommandOptions & { prevSubject: true | S | ['optional'] }, fn: CommandFnWithSubject, ): void add( name: T, options: CommandOptions & { prevSubject: S[] }, fn: CommandFnWithSubject[S]>, diff --git a/cli/types/tests/cypress-tests.ts b/cli/types/tests/cypress-tests.ts index 9c8bf219cff7..eecb36f65909 100644 --- a/cli/types/tests/cypress-tests.ts +++ b/cli/types/tests/cypress-tests.ts @@ -83,7 +83,7 @@ namespace CypressCommandsTests { arg // $ExpectType string }) Cypress.Commands.add('newCommand', { prevSubject: true }, (subject, arg) => { - subject // $ExpectType any + subject // $ExpectType unknown arg // $ExpectType string return }) @@ -113,13 +113,11 @@ namespace CypressCommandsTests { arg // $ExpectType string }) Cypress.Commands.add('newCommand', { prevSubject: 'element' }, (subject, arg) => { - subject // $ExpectType JQueryWithSelector - subject.selector // $ExpectType string | null | undefined + subject // $ExpectType JQuery arg // $ExpectType string }) Cypress.Commands.add('newCommand', { prevSubject: ['element'] }, (subject, arg) => { - subject // $ExpectType JQueryWithSelector - subject.selector // $ExpectType string | null | undefined + subject // $ExpectType JQuery arg // $ExpectType string }) Cypress.Commands.add('newCommand', { prevSubject: ['element', 'document', 'window'] }, (subject, arg) => { @@ -128,8 +126,7 @@ namespace CypressCommandsTests { } else if (subject instanceof Document) { subject // $ExpectType Document } else { - subject // $ExpectType JQueryWithSelector - subject.selector // $ExpectType string | null | undefined + subject // $ExpectType JQuery } arg // $ExpectType string }) @@ -139,7 +136,7 @@ namespace CypressCommandsTests { } else if (subject instanceof Document) { subject // $ExpectType Document } else if (subject) { - subject // $ExpectType JQueryWithSelector + subject // $ExpectType JQuery } else { subject // $ExpectType void } @@ -274,7 +271,7 @@ namespace CypressCommandsTests { originalFn.apply(this, [arg]) // $ExpectType Chainable }) Cypress.Commands.overwrite<'type', 'element'>('type', (originalFn, element, text, options?: Partial) => { - element // $ExpectType JQueryWithSelector + element // $ExpectType JQuery text // $ExpectType string if (options && options.sensitive) { From afca88e7a99a0ca7edae0db62d68b4685daf2704 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Tue, 19 Apr 2022 10:51:21 -0400 Subject: [PATCH 07/16] chore: remove unused dependencies (#21092) --- package.json | 13 - .../driver/cypress/fixtures/dropdown.html | 44 - .../driver/cypress/fixtures/fixed-nav.html | 32 - packages/driver/package.json | 9 - packages/errors/package.json | 1 - packages/extension/package.json | 3 - packages/launcher/package.json | 1 - packages/net-stubbing/package.json | 1 - packages/reporter/package.json | 7 +- packages/rewriter/package.json | 1 - packages/runner-shared/package.json | 3 +- packages/runner/package.json | 11 +- packages/server/package.json | 21 +- packages/server/test/support/watch | 10 - packages/ui-components/package.json | 6 +- packages/web-config/package.json | 1 - yarn.lock | 1733 +---------------- 17 files changed, 108 insertions(+), 1789 deletions(-) delete mode 100644 packages/driver/cypress/fixtures/dropdown.html delete mode 100644 packages/driver/cypress/fixtures/fixed-nav.html delete mode 100755 packages/server/test/support/watch diff --git a/package.json b/package.json index db45f9795d48..d4bdf9869630 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "ensure-deps": "./scripts/ensure-dependencies.sh", "get-next-version": "node scripts/get-next-version.js", "postinstall": "patch-package && ./scripts/run-if-not-ci.sh yarn-deduplicate --strategy=highest && ./scripts/run-if-not-ci.sh yarn build", - "jscodeshift": "jscodeshift -t ./node_modules/js-codemod/transforms/arrow-function-arguments.js", "lint": "eslint --ext .js,.jsx,.ts,.tsx,.json .", "lint-changed": "lint-changed", "prepare-release-artifacts": "node ./scripts/prepare-release-artifacts.js", @@ -74,12 +73,10 @@ "devDependencies": { "@aws-sdk/credential-providers": "3.53.0", "@cypress/commit-message-install": "3.1.3", - "@cypress/env-or-json-file": "2.0.0", "@cypress/github-commit-status-check": "1.5.0", "@cypress/questions-remain": "1.0.1", "@cypress/request": "2.88.10", "@cypress/request-promise": "4.2.6", - "@fellow/eslint-plugin-coffee": "0.4.13", "@percy/cli": "1.0.0-beta.48", "@percy/cypress": "^3.1.0", "@semantic-release/changelog": "5.0.1", @@ -105,11 +102,9 @@ "@typescript-eslint/eslint-plugin": "4.18.0", "@typescript-eslint/parser": "4.18.0", "arg": "4.1.2", - "ascii-table": "0.0.9", "aws-sdk": "2.814.0", "babel-eslint": "10.1.0", "bluebird": "3.5.3", - "bluebird-retry": "0.11.0", "chai": "4.2.0", "chai-as-promised": "7.1.1", "chalk": "2.4.2", @@ -147,10 +142,6 @@ "inquirer": "3.3.0", "inquirer-confirm": "2.0.3", "jest": "24.9.0", - "js-codemod": "cpojer/js-codemod", - "jscodemods": "cypress-io/jscodemods#01b546e", - "jscodeshift": "0.7.0", - "konfig": "0.2.1", "lazy-ass": "1.6.0", "lerna": "3.20.2", "lint-staged": "11.1.2", @@ -163,11 +154,8 @@ "mocha-multi-reporters": "1.1.7", "mock-fs": "5.1.1", "patch-package": "6.4.7", - "plist": "3.0.5", "pluralize": "8.0.0", "postinstall-postinstall": "2.0.0", - "prefixed-list": "1.0.1", - "pretty-ms": "7.0.0", "print-arch": "1.0.0", "proxyquire": "2.1.3", "semantic-release": "17.2.3", @@ -182,7 +170,6 @@ "strip-ansi": "6.0.0", "term-to-html": "1.2.0", "terminal-banner": "1.1.0", - "through": "2.3.8", "ts-node": "8.3.0", "typescript": "^4.4.4", "yarn-deduplicate": "3.1.0" diff --git a/packages/driver/cypress/fixtures/dropdown.html b/packages/driver/cypress/fixtures/dropdown.html deleted file mode 100644 index ab0c2cc0520e..000000000000 --- a/packages/driver/cypress/fixtures/dropdown.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - DOM Fixture - - - - -
- - - - - - - - - -
- - diff --git a/packages/driver/cypress/fixtures/fixed-nav.html b/packages/driver/cypress/fixtures/fixed-nav.html deleted file mode 100644 index 9c031b95256b..000000000000 --- a/packages/driver/cypress/fixtures/fixed-nav.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - DOM Fixture - - - - - -
- - - -
- -
-
- - diff --git a/packages/driver/package.json b/packages/driver/package.json index 59ba9b392c07..14ac9cf26243 100644 --- a/packages/driver/package.json +++ b/packages/driver/package.json @@ -12,18 +12,15 @@ "dependencies": {}, "devDependencies": { "@babel/code-frame": "7.8.3", - "@cypress/bower-kendo-ui": "0.0.2", "@cypress/sinon-chai": "2.9.1", "@cypress/unique-selector": "0.4.4", "@cypress/webpack-preprocessor": "0.0.0-development", "@cypress/what-is-circular": "1.0.1", "@packages/config": "0.0.0-development", "@packages/network": "0.0.0-development", - "@packages/resolve-dist": "0.0.0-development", "@packages/runner": "0.0.0-development", "@packages/server": "0.0.0-development", "@packages/ts": "0.0.0-development", - "@rollup/plugin-node-resolve": "^13.0.4", "@sinonjs/fake-timers": "8.1.0", "@types/chalk": "^2.2.0", "@types/common-tags": "^1.8.0", @@ -36,12 +33,9 @@ "blob-util": "2.0.2", "bluebird": "3.5.3", "body-parser": "1.19.0", - "bootstrap": "4.4.1", "bytes": "3.1.0", "chai": "4.2.0", - "chai-as-promised": "7.1.1", "chai-subset": "1.6.0", - "chokidar-cli": "2.1.0", "clone": "2.1.2", "compression": "1.7.4", "cors": "2.8.5", @@ -56,7 +50,6 @@ "is-valid-hostname": "1.0.1", "jquery": "3.1.1", "js-cookie": "2.2.1", - "jsdom": "14.1.0", "json-stable-stringify": "1.0.1", "lodash": "^4.17.21", "md5": "2.3.0", @@ -64,9 +57,7 @@ "methods": "1.1.2", "mime-types": "2.1.27", "minimatch": "3.0.4", - "minimist": "1.2.6", "mocha": "7.0.1", - "morgan": "1.9.1", "multer": "1.4.2", "ordinal": "1.0.3", "react-15.6.1": "npm:react@15.6.1", diff --git a/packages/errors/package.json b/packages/errors/package.json index 38d492e2ccce..d6909490b2ea 100644 --- a/packages/errors/package.json +++ b/packages/errors/package.json @@ -25,7 +25,6 @@ "@types/chai": "4.2.15", "@types/mocha": "8.2.2", "@types/node": "14.14.31", - "@types/pixelmatch": "^5.2.4", "@types/pngjs": "^6.0.1", "@types/strip-ansi": "^5.2.1", "ansi-styles": "^5", diff --git a/packages/extension/package.json b/packages/extension/package.json index 8dc10fc6256f..88d3874634c3 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -23,13 +23,10 @@ "@cypress/icons": "0.7.0", "@packages/socket": "0.0.0-development", "chai": "3.5.0", - "coffeescript": "1.12.7", "cross-env": "6.0.3", "eol": "0.9.1", "fs-extra": "9.1.0", "gulp": "4.0.2", - "gulp-clean": "0.4.0", - "gulp-rename": "1.4.0", "mocha": "3.5.3", "mock-require": "3.0.3", "rimraf": "3.0.2", diff --git a/packages/launcher/package.json b/packages/launcher/package.json index 9e569f4482f1..065b990a924e 100644 --- a/packages/launcher/package.json +++ b/packages/launcher/package.json @@ -24,7 +24,6 @@ "@packages/ts": "0.0.0-development", "chai": "3.5.0", "chai-as-promised": "7.1.1", - "cross-env": "6.0.3", "mocha": "3.5.3", "shelljs": "0.8.5", "sinon": "^10.0.0", diff --git a/packages/net-stubbing/package.json b/packages/net-stubbing/package.json index e5e44eaf5a15..a7f89da73a0e 100644 --- a/packages/net-stubbing/package.json +++ b/packages/net-stubbing/package.json @@ -18,7 +18,6 @@ "throttle": "^1.0.3" }, "devDependencies": { - "bin-up": "1.2.0", "chai": "4.2.0", "mocha": "7.1.2" }, diff --git a/packages/reporter/package.json b/packages/reporter/package.json index fa38d2a24ae1..f36efd0fe8b9 100644 --- a/packages/reporter/package.json +++ b/packages/reporter/package.json @@ -16,14 +16,10 @@ "@fontsource/open-sans": "4.3.0", "@fortawesome/fontawesome-free": "5.11.2", "@packages/driver": "0.0.0-development", - "@packages/resolve-dist": "0.0.0-development", - "@packages/socket": "0.0.0-development", "@packages/web-config": "0.0.0-development", "@reach/dialog": "0.10.5", - "@reach/visually-hidden": "0.10.4", "classnames": "2.3.1", "css-element-queries": "1.2.3", - "cypress-multi-reporters": "1.4.0", "cypress-real-events": "1.4.0", "lodash": "^4.17.21", "markdown-it": "11.0.0", @@ -34,8 +30,7 @@ "react": "16.8.6", "react-dom": "16.8.6", "sinon": "7.5.0", - "webpack": "4.35.3", - "webpack-cli": "3.3.2" + "webpack": "4.35.3" }, "files": [] } diff --git a/packages/rewriter/package.json b/packages/rewriter/package.json index 0c0a5a7a2655..17053ae1425f 100644 --- a/packages/rewriter/package.json +++ b/packages/rewriter/package.json @@ -23,7 +23,6 @@ "@cypress/request-promise": "4.2.6", "@types/parse5-html-rewriting-stream": "5.1.1", "fs-extra": "9.1.0", - "nock": "12.0.3", "sinon": "9.0.2", "sinon-chai": "3.5.0", "snap-shot-it": "7.9.3" diff --git a/packages/runner-shared/package.json b/packages/runner-shared/package.json index af36b0b19daf..71ef6ed4b40a 100644 --- a/packages/runner-shared/package.json +++ b/packages/runner-shared/package.json @@ -30,7 +30,6 @@ "react-dom": "16.8.6", "react-popper": "2.2.5", "react-shadow-dom-retarget-events": "1.0.11", - "sinon": "7.5.0", - "sinon-chai": "3.3.0" + "sinon": "7.5.0" } } diff --git a/packages/runner/package.json b/packages/runner/package.json index f94cd80cd246..15ec1452af13 100644 --- a/packages/runner/package.json +++ b/packages/runner/package.json @@ -16,14 +16,10 @@ "test-watch": "yarn test-unit --watch", "watch": "webpack --watch --progress" }, - "dependencies": { - "fs-extra": "9.1.0" - }, "devDependencies": { "@cypress/design-system": "0.0.0-development", "@cypress/icons": "0.7.0", "@cypress/react-tooltip": "0.5.3", - "@cypress/webpack-preprocessor": "0.0.0-development", "@fontsource/mulish": "4.3.0", "@fontsource/open-sans": "4.3.0", "@fortawesome/fontawesome-free": "5.12.1", @@ -31,8 +27,6 @@ "@packages/reporter": "0.0.0-development", "@packages/socket": "0.0.0-development", "@packages/web-config": "0.0.0-development", - "@reach/dialog": "0.10.5", - "@reach/visually-hidden": "0.10.4", "babel-plugin-prismjs": "1.0.2", "bluebird": "3.5.3", "chai": "4.2.0", @@ -45,7 +39,6 @@ "enzyme": "3.11.0", "enzyme-adapter-react-16": "1.15.2", "jquery": "3.1.1", - "jsdom": "14.1.0", "lodash": "^4.17.21", "mobx": "5.15.4", "mobx-react": "6.1.8", @@ -55,10 +48,8 @@ "react": "16.8.6", "react-dom": "16.8.6", "sinon": "7.5.0", - "sinon-chai": "3.3.0", "snap-shot-core": "10.2.1", - "webpack": "4.35.3", - "webpack-cli": "3.3.2" + "webpack": "4.35.3" }, "files": [ "dist" diff --git a/packages/server/package.json b/packages/server/package.json index a28b5738426c..f253231ad479 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -15,8 +15,7 @@ "test": "node ./test/scripts/run.js", "test-integration": "node ./test/scripts/run.js --glob-in-dir=test/integration", "test-performance": "node ./test/scripts/run.js --glob-in-dir=test/performance", - "test-unit": "node ./test/scripts/run.js --glob-in-dir=test/unit", - "test-watch": "./test/support/watch test" + "test-unit": "node ./test/scripts/run.js --glob-in-dir=test/unit" }, "dependencies": { "@babel/parser": "7.13.0", @@ -30,7 +29,6 @@ "@cypress/webpack-batteries-included-preprocessor": "0.0.0-development", "@cypress/webpack-preprocessor": "0.0.0-development", "@ffmpeg-installer/ffmpeg": "1.1.0", - "ansi_up": "5.0.0", "ast-types": "0.13.3", "black-hole-stream": "0.0.1", "bluebird": "3.7.2", @@ -114,7 +112,6 @@ "tree-kill": "1.2.2", "ts-node": "8.5.4", "tsconfig-paths": "3.10.1", - "tslib": "2.3.0", "underscore.string": "3.3.5", "url-parse": "1.5.9", "uuid": "8.3.2", @@ -128,7 +125,6 @@ "@cypress/debugging-proxy": "2.0.1", "@cypress/json-schemas": "5.39.0", "@cypress/sinon-chai": "2.9.1", - "@ffprobe-installer/ffprobe": "1.1.0", "@packages/config": "0.0.0-development", "@packages/desktop-gui": "0.0.0-development", "@packages/electron": "0.0.0-development", @@ -138,7 +134,6 @@ "@packages/launcher": "0.0.0-development", "@packages/net-stubbing": "0.0.0-development", "@packages/network": "0.0.0-development", - "@packages/reporter": "0.0.0-development", "@packages/resolve-dist": "0.0.0-development", "@packages/root": "0.0.0-development", "@packages/socket": "0.0.0-development", @@ -148,23 +143,15 @@ "@types/chrome": "0.0.101", "@types/http-proxy": "1.17.4", "@types/node": "14.14.31", - "awesome-typescript-loader": "5.2.1", "babel-loader": "8.1.0", - "body-parser": "1.19.0", "chai-as-promised": "7.1.1", "chai-subset": "1.6.0", "chai-uuid": "1.0.6", - "chokidar-cli": "2.1.0", "chrome-har-capturer": "0.13.4", - "cors": "2.8.5", - "cross-env": "6.0.3", "devtools-protocol": "0.0.839267", "eol": "0.9.1", "eventsource": "1.0.7", - "express-session": "1.16.1", - "express-useragent": "1.0.15", "https-proxy-agent": "3.0.1", - "istanbul": "0.4.5", "mocha": "7.1.0", "mocha-banner": "1.1.2", "mochawesome-1.5.2": "npm:mochawesome@1.5.2", @@ -173,21 +160,15 @@ "mock-fs": "5.1.1", "mocked-env": "1.2.4", "mockery": "2.1.0", - "multer": "1.4.2", "nock": "12.0.2", "proxyquire": "2.1.3", - "react": "16.8.6", - "repl.history": "0.1.4", "sinon": "5.1.1", "snap-shot-it": "7.9.3", "ssestream": "1.0.1", "supertest": "4.0.2", "supertest-session": "4.0.0", - "through2": "2.0.5", - "ts-loader": "7.0.4", "webpack": "4.43.0", "ws": "5.2.3", - "xvfb": "cypress-io/node-xvfb#22e3783c31d81ebe64d8c0df491ea00cdc74726a", "xvfb-maybe": "0.2.1" }, "files": [ diff --git a/packages/server/test/support/watch b/packages/server/test/support/watch deleted file mode 100755 index f759dbc758f6..000000000000 --- a/packages/server/test/support/watch +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash - -CMD="$1" -ARGS="$2" - -npm run --silent $CMD $ARGS & \ -chokidar 'test/**/*' 'lib/**/*' \ --c "yarn --silent $CMD $ARGS" \ ---polling \ ---poll-interval=250 diff --git a/packages/ui-components/package.json b/packages/ui-components/package.json index e11203e70575..084e4b0ead17 100644 --- a/packages/ui-components/package.json +++ b/packages/ui-components/package.json @@ -28,7 +28,6 @@ "browser-logos": "github:alrra/browser-logos", "chai-subset": "1.6.0", "classnames": "2.3.1", - "cypress-multi-reporters": "1.4.0", "file-loader": "4.3.0", "lodash": "^4.17.19", "mobx": "5.15.4", @@ -36,7 +35,6 @@ "prop-types": "15.7.2", "react": "16.8.6", "react-dom": "16.8.6", - "webpack": "4.41.6", - "webpack-cli": "3.3.11" + "webpack": "4.41.6" } -} \ No newline at end of file +} diff --git a/packages/web-config/package.json b/packages/web-config/package.json index 341418a8ccfb..db7465c33b17 100644 --- a/packages/web-config/package.json +++ b/packages/web-config/package.json @@ -26,7 +26,6 @@ "copy-webpack-plugin": "5.1.2", "css-loader": "2.1.1", "css-modules-typescript-loader": "4.0.1", - "execa": "^5.0.0", "extract-text-webpack-plugin": "4.0.0-beta.0", "file-loader": "4.3.0", "html-webpack-plugin": "4.5.2", diff --git a/yarn.lock b/yarn.lock index e593d6a0a68b..48a88615239f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1231,7 +1231,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.0.1", "@babel/core@^7.1.0", "@babel/core@^7.1.6", "@babel/core@^7.11.0", "@babel/core@^7.11.1", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.4.5", "@babel/core@^7.5.4", "@babel/core@^7.7.5", "@babel/core@^7.8.6", "@babel/core@^7.9.6": +"@babel/core@^7.0.1", "@babel/core@^7.1.0", "@babel/core@^7.11.0", "@babel/core@^7.11.1", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.4.5", "@babel/core@^7.5.4", "@babel/core@^7.7.5", "@babel/core@^7.8.6", "@babel/core@^7.9.6": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.0.tgz#47299ff3ec8d111b493f1a9d04bf88c04e728d88" integrity sha512-8YqpRig5NmIHlMLw09zMlPTvUVMILjqCOtVgu+TVNWEBvy9b5I3RRyhqnrV4hjgEK7n8P9OqvkWJAFmEL6Wwfw== @@ -1496,7 +1496,7 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.0.tgz#49b9b6ee213e5634fa80361dae139effef893f78" integrity sha512-w80kxEMFhE3wjMOQkfdTvv0CSdRSJZptIlLhU4eU/coNJeWjduspUFz+IRnBbAq6m5XYBFMoT1TNkk9K9yf10g== -"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.1.6", "@babel/parser@^7.12.0", "@babel/parser@^7.12.10", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.13.9", "@babel/parser@^7.14.0", "@babel/parser@^7.14.5", "@babel/parser@^7.14.8", "@babel/parser@^7.4.3", "@babel/parser@^7.4.5", "@babel/parser@^7.6.0", "@babel/parser@^7.7.0", "@babel/parser@^7.8.3", "@babel/parser@^7.9.0", "@babel/parser@^7.9.6": +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.12.0", "@babel/parser@^7.12.10", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7", "@babel/parser@^7.13.9", "@babel/parser@^7.14.0", "@babel/parser@^7.14.5", "@babel/parser@^7.14.8", "@babel/parser@^7.4.3", "@babel/parser@^7.4.5", "@babel/parser@^7.6.0", "@babel/parser@^7.7.0", "@babel/parser@^7.8.3", "@babel/parser@^7.9.0", "@babel/parser@^7.9.6": version "7.14.8" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.8.tgz#66fd41666b2d7b840bd5ace7f7416d5ac60208d4" integrity sha512-syoCQFOoo/fzkWDeM0dLEZi5xqurb5vuyzwIMNZRNun+N/9A4cUZeQaE7dTrB8jGaKuJRBtEOajtnmw0I5hvvA== @@ -1534,7 +1534,7 @@ "@babel/helper-create-class-features-plugin" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-proposal-class-properties@^7.1.0", "@babel/plugin-proposal-class-properties@^7.10.4", "@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.13.0", "@babel/plugin-proposal-class-properties@^7.8.3": +"@babel/plugin-proposal-class-properties@^7.10.4", "@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.13.0", "@babel/plugin-proposal-class-properties@^7.8.3": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz#146376000b94efd001e57a40a88a525afaab9f37" integrity sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg== @@ -1657,7 +1657,7 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" -"@babel/plugin-proposal-object-rest-spread@^7.0.0", "@babel/plugin-proposal-object-rest-spread@^7.11.0", "@babel/plugin-proposal-object-rest-spread@^7.12.1", "@babel/plugin-proposal-object-rest-spread@^7.13.0", "@babel/plugin-proposal-object-rest-spread@^7.4.4", "@babel/plugin-proposal-object-rest-spread@^7.9.0", "@babel/plugin-proposal-object-rest-spread@^7.9.5": +"@babel/plugin-proposal-object-rest-spread@^7.11.0", "@babel/plugin-proposal-object-rest-spread@^7.12.1", "@babel/plugin-proposal-object-rest-spread@^7.13.0", "@babel/plugin-proposal-object-rest-spread@^7.4.4", "@babel/plugin-proposal-object-rest-spread@^7.9.0", "@babel/plugin-proposal-object-rest-spread@^7.9.5": version "7.13.8" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz#5d210a4d727d6ce3b18f9de82cc99a3964eed60a" integrity sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g== @@ -2311,7 +2311,7 @@ core-js-compat "^3.8.0" semver "^5.5.0" -"@babel/preset-env@7.13.5", "@babel/preset-env@^7.0.0", "@babel/preset-env@^7.1.6", "@babel/preset-env@^7.11.0", "@babel/preset-env@^7.12.1", "@babel/preset-env@^7.12.11", "@babel/preset-env@^7.4.5": +"@babel/preset-env@7.13.5", "@babel/preset-env@^7.0.0", "@babel/preset-env@^7.11.0", "@babel/preset-env@^7.12.1", "@babel/preset-env@^7.12.11", "@babel/preset-env@^7.4.5": version "7.13.5" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.13.5.tgz#68b3bbc821a97fcdbf4bd0f6895b83d07f84f33e" integrity sha512-xUeKBIIcbwxGevyWMSWZOW98W1lp7toITvVsMxSddCEQy932yYiF4fCB+CG3E/MXzFX3KbefgvCqEQ7TDoE6UQ== @@ -2571,7 +2571,7 @@ levenary "^1.1.1" semver "^5.5.0" -"@babel/preset-flow@^7.0.0", "@babel/preset-flow@^7.12.1": +"@babel/preset-flow@^7.12.1": version "7.13.13" resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.13.13.tgz#a61a1c149b3f77589d795287744393444d5cdd9e" integrity sha512-MDtwtamMifqq3R2mC7l3A3uFalUb3NH5TIBQWjN/epEPlZktcLq4se3J+ivckKrLMGsR7H9LW8+pYuIUN9tsKg== @@ -2662,7 +2662,7 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-transform-typescript" "^7.9.0" -"@babel/preset-typescript@^7.1.0", "@babel/preset-typescript@^7.12.7", "@babel/preset-typescript@^7.3.3", "@babel/preset-typescript@^7.8.3": +"@babel/preset-typescript@^7.12.7", "@babel/preset-typescript@^7.3.3", "@babel/preset-typescript@^7.8.3": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.13.0.tgz#ab107e5f050609d806fbb039bec553b33462c60a" integrity sha512-LXJwxrHy0N3f6gIJlYbLta1D9BDtHpQeqwzM0LIfjDlr6UE/D5Mc7W4iDiQzaE+ks0sTjT26ArcHWnJVt0QiHw== @@ -2682,7 +2682,7 @@ pirates "^4.0.0" source-map-support "^0.5.16" -"@babel/register@^7.0.0", "@babel/register@^7.12.1": +"@babel/register@^7.12.1": version "7.13.14" resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.13.14.tgz#bbfa8f4f027c2ebc432e8e69e078b632605f2d9b" integrity sha512-iyw0hUwjh/fzN8qklVqZodbyWjEBOG0KdDnBOpv3zzIgK3NmuRXBmIXH39ZBdspkn8LTHvSboN+oYb4MT43+9Q== @@ -2865,11 +2865,6 @@ resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-9.0.1.tgz#c27b391d8457d1e893f1eddeaf5e5412d12ffbb5" integrity sha512-6It2EVfGskxZCQhuykrfnALg7oVeiI6KclWSmGDqB0AiInVrTGB9Jp9i4/Ad21u9Jde/voVQz6eFX/eSg/UsPA== -"@cypress/bower-kendo-ui@0.0.2": - version "0.0.2" - resolved "https://registry.yarnpkg.com/@cypress/bower-kendo-ui/-/bower-kendo-ui-0.0.2.tgz#62ea93d7f0653c0b91a7a4e5e9ede9d26d5990ea" - integrity sha1-YuqT1/BlPAuRp6Tl6e3p0m1ZkOo= - "@cypress/browserify-preprocessor@3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@cypress/browserify-preprocessor/-/browserify-preprocessor-3.0.0.tgz#2d1fa6a96ed7130a1b172c540448a5955cbc1264" @@ -2994,15 +2989,6 @@ http-proxy "^1.17.0" self-signed-cert "^1.0.1" -"@cypress/env-or-json-file@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@cypress/env-or-json-file/-/env-or-json-file-2.0.0.tgz#fb6479b8b379e05a5cd216d9ae89c049a7b3c444" - integrity sha1-+2R5uLN54Fpc0hbZronASaezxEQ= - dependencies: - check-more-types "2.24.0" - debug "3.1.0" - lazy-ass "1.6.0" - "@cypress/get-windows-proxy@1.6.2": version "1.6.2" resolved "https://registry.yarnpkg.com/@cypress/get-windows-proxy/-/get-windows-proxy-1.6.2.tgz#c2f14c465fce7cf3bb3da4835fb191d80a79c2e3" @@ -6957,18 +6943,6 @@ is-module "^1.0.0" resolve "^1.19.0" -"@rollup/plugin-node-resolve@^13.0.4": - version "13.0.4" - resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.4.tgz#b10222f4145a019740acb7738402130d848660c0" - integrity sha512-eYq4TFy40O8hjeDs+sIxEH/jc9lyuI2k9DM557WN6rO5OpnC2qXMBNj4IKH1oHrnAazL49C5p0tgP0/VpqJ+/w== - dependencies: - "@rollup/pluginutils" "^3.1.0" - "@types/resolve" "1.17.1" - builtin-modules "^3.1.0" - deepmerge "^4.2.2" - is-module "^1.0.0" - resolve "^1.19.0" - "@rollup/plugin-typescript@^8.2.1": version "8.2.1" resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-8.2.1.tgz#f1a32d4030cc83432ce36a80a922280f0f0b5d44" @@ -8895,13 +8869,6 @@ resolved "https://registry.yarnpkg.com/@types/parsimmon/-/parsimmon-1.10.6.tgz#8fcf95990514d2a7624aa5f630c13bf2427f9cdd" integrity sha512-FwAQwMRbkhx0J6YELkwIpciVzCcgEqXEbIrIn3a2P5d3kGEHQ3wVhlN3YdVepYP+bZzCYO6OjmD4o9TGOZ40rA== -"@types/pixelmatch@^5.2.4": - version "5.2.4" - resolved "https://registry.yarnpkg.com/@types/pixelmatch/-/pixelmatch-5.2.4.tgz#ca145cc5ede1388c71c68edf2d1f5190e5ddd0f6" - integrity sha512-HDaSHIAv9kwpMN7zlmwfTv6gax0PiporJOipcrGsVNF3Ba+kryOZc0Pio5pn6NhisgWr7TaajlPEKTbTAypIBQ== - dependencies: - "@types/node" "*" - "@types/plist@^3.0.1": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/plist/-/plist-3.0.2.tgz#61b3727bba0f5c462fe333542534a0c3e19ccb01" @@ -10511,11 +10478,6 @@ abbrev@1, abbrev@~1.1.1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abbrev@1.0.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" - integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= - abstract-leveldown@~0.12.0, abstract-leveldown@~0.12.1: version "0.12.4" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-0.12.4.tgz#29e18e632e60e4e221d5810247852a63d7b2e410" @@ -10803,13 +10765,6 @@ alphanum-sort@^1.0.0, alphanum-sort@^1.0.2: resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= -alter@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" - integrity sha1-x1iICGF1cgNKrmJICvJrHU0cs80= - dependencies: - stable "~0.1.3" - amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -11228,13 +11183,6 @@ arr-diff@^1.0.1: arr-flatten "^1.0.1" array-slice "^0.2.3" -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= - dependencies: - arr-flatten "^1.0.1" - arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -11381,11 +11329,6 @@ array-uniq@1.0.2, array-uniq@^1.0.1: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.2.tgz#5fcc373920775723cfd64d65c64bef53bf9eba6d" integrity sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0= -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= - array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -11468,11 +11411,6 @@ asar@^3.0.3, asar@^3.1.0: optionalDependencies: "@types/glob" "^7.1.1" -ascii-table@0.0.9: - version "0.0.9" - resolved "https://registry.yarnpkg.com/ascii-table/-/ascii-table-0.0.9.tgz#06a6604d6a55d4bf41a9a47d9872d7a78da31e73" - integrity sha1-BqZgTWpV1L9BqaR9mHLXp42jHnM= - asn1.js@^5.2.0: version "5.4.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" @@ -11542,21 +11480,11 @@ ast-module-types@^3.0.0: resolved "https://registry.npmjs.org/ast-module-types/-/ast-module-types-3.0.0.tgz#9a6d8a80f438b6b8fe4995699d700297f398bf81" integrity sha512-CMxMCOCS+4D+DkOQfuZf+vLrSEmY/7xtORwdxs4wtcC1wVgvk2MqFFTwQCFhvWsI4KPU9lcWXPI8DgRiz+xetQ== -ast-traverse@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" - integrity sha1-ac8rg4bxnc2hux4F1o/jWdiJfeY= - ast-types-flow@0.0.7, ast-types-flow@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= -ast-types@0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.10.1.tgz#f52fca9715579a14f841d67d7f8d25432ab6a3dd" - integrity sha512-UY7+9DPzlJ9VM8eY0b2TUZcZvF+1pO0hzMtAyjBYKhOmnvRlqYNYnWdtsMj0V16CGaMlpL0G1jnLbLo4AyotuQ== - ast-types@0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48" @@ -11574,16 +11502,6 @@ ast-types@0.14.2, ast-types@^0.14.2: dependencies: tslib "^2.0.1" -ast-types@0.8.12: - version "0.8.12" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" - integrity sha1-oNkOQ1G7iHcWyD/WN+v4GK9K38w= - -ast-types@0.9.6: - version "0.9.6" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" - integrity sha1-ECyenpAF0+fjgpvwxPok7oYu6bk= - ast-types@^0.13.2: version "0.13.4" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" @@ -11643,11 +11561,6 @@ async@0.9.x, async@^0.9.0: resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= -async@1.x, async@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= - async@>=0.2.9, async@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" @@ -11760,20 +11673,6 @@ available-typed-arrays@^1.0.2: dependencies: array-filter "^1.0.0" -awesome-typescript-loader@5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/awesome-typescript-loader/-/awesome-typescript-loader-5.2.1.tgz#a41daf7847515f4925cdbaa3075d61f289e913fc" - integrity sha512-slv66OAJB8orL+UUaTI3pKlLorwIvS4ARZzYR9iJJyGsEgOqueMfOMdKySWzZ73vIkEe3fcwFgsKMg4d8zyb1g== - dependencies: - chalk "^2.4.1" - enhanced-resolve "^4.0.0" - loader-utils "^1.1.0" - lodash "^4.17.5" - micromatch "^3.1.9" - mkdirp "^0.5.1" - source-map-support "^0.5.3" - webpack-log "^1.2.0" - aws-sdk@2.814.0, aws-sdk@^2.389.0: version "2.814.0" resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.814.0.tgz#7a1c36006e0b5826f14bd2511b1d229ef6814bb0" @@ -11827,88 +11726,6 @@ babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@5.8.38, babel-core@^5, babel-core@^5.8.21: - version "5.8.38" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" - integrity sha1-H8ruedfmG3ULALjlT238nQr4ZVg= - dependencies: - babel-plugin-constant-folding "^1.0.1" - babel-plugin-dead-code-elimination "^1.0.2" - babel-plugin-eval "^1.0.1" - babel-plugin-inline-environment-variables "^1.0.1" - babel-plugin-jscript "^1.0.4" - babel-plugin-member-expression-literals "^1.0.1" - babel-plugin-property-literals "^1.0.1" - babel-plugin-proto-to-assign "^1.0.3" - babel-plugin-react-constant-elements "^1.0.3" - babel-plugin-react-display-name "^1.0.3" - babel-plugin-remove-console "^1.0.1" - babel-plugin-remove-debugger "^1.0.1" - babel-plugin-runtime "^1.0.7" - babel-plugin-undeclared-variables-check "^1.0.2" - babel-plugin-undefined-to-void "^1.1.6" - babylon "^5.8.38" - bluebird "^2.9.33" - chalk "^1.0.0" - convert-source-map "^1.1.0" - core-js "^1.0.0" - debug "^2.1.1" - detect-indent "^3.0.0" - esutils "^2.0.0" - fs-readdir-recursive "^0.1.0" - globals "^6.4.0" - home-or-tmp "^1.0.0" - is-integer "^1.0.4" - js-tokens "1.0.1" - json5 "^0.4.0" - lodash "^3.10.0" - minimatch "^2.0.3" - output-file-sync "^1.1.0" - path-exists "^1.0.0" - path-is-absolute "^1.0.0" - private "^0.1.6" - regenerator "0.8.40" - regexpu "^1.3.0" - repeating "^1.1.2" - resolve "^1.1.6" - shebang-regex "^1.0.0" - slash "^1.0.0" - source-map "^0.5.0" - source-map-support "^0.2.10" - to-fast-properties "^1.0.0" - trim-right "^1.0.0" - try-resolve "^1.0.0" - -babel-core@^6.26.0: - version "6.26.3" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" - integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== - dependencies: - babel-code-frame "^6.26.0" - babel-generator "^6.26.0" - babel-helpers "^6.24.1" - babel-messages "^6.23.0" - babel-register "^6.26.0" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - convert-source-map "^1.5.1" - debug "^2.6.9" - json5 "^0.5.1" - lodash "^4.17.4" - minimatch "^3.0.4" - path-is-absolute "^1.0.1" - private "^0.1.8" - slash "^1.0.0" - source-map "^0.5.7" - -babel-core@^7.0.0-bridge.0: - version "7.0.0-bridge.0" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" - integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg== - babel-eslint@10.0.3: version "10.0.3" resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a" @@ -11950,7 +11767,7 @@ babel-extract-comments@^1.0.0: dependencies: babylon "^6.18.0" -babel-generator@^6.18.0, babel-generator@^6.26.0: +babel-generator@^6.18.0: version "6.26.1" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== @@ -11964,138 +11781,6 @@ babel-generator@^6.18.0, babel-generator@^6.26.0: source-map "^0.5.7" trim-right "^1.0.1" -babel-helper-bindify-decorators@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" - integrity sha1-FMGeXxQte0fxmlJDHlKxzLxAozA= - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" - integrity sha1-zORReto1b0IgvK6KAsKzRvmlZmQ= - dependencies: - babel-helper-explode-assignable-expression "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-call-delegate@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" - integrity sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340= - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-define-map@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" - integrity sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8= - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-explode-assignable-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" - integrity sha1-8luCz33BBDPFX3BZLVdGQArCLKo= - dependencies: - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-explode-class@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" - integrity sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes= - dependencies: - babel-helper-bindify-decorators "^6.24.1" - babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" - integrity sha1-00dbjAPtmCQqJbSDUasYOZ01gKk= - dependencies: - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-get-function-arity@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" - integrity sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-hoist-variables@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" - integrity sha1-HssnaJydJVE+rbyZFKc/VAi+enY= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-optimise-call-expression@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" - integrity sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-helper-regex@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" - integrity sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI= - dependencies: - babel-runtime "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-helper-remap-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" - integrity sha1-XsWBgnrXI/7N04HxySg5BnbkVRs= - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helper-replace-supers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" - integrity sha1-v22/5Dk40XNpohPKiov3S2qQqxo= - dependencies: - babel-helper-optimise-call-expression "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-helpers@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" - integrity sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI= - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-jest@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54" @@ -12167,23 +11852,6 @@ babel-plugin-apply-mdx-type-prop@1.6.22: "@babel/helper-plugin-utils" "7.10.4" "@mdx-js/util" "1.6.22" -babel-plugin-check-es2015-constants@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" - integrity sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-constant-folding@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" - integrity sha1-g2HTZMmORJw2kr26Ue/whEKQqo4= - -babel-plugin-dead-code-elimination@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" - integrity sha1-X3xFEnTc18zNv7s+C4XdKBIfD2U= - babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" @@ -12207,11 +11875,6 @@ babel-plugin-emotion@^10.0.27: find-root "^1.1.0" source-map "^0.5.7" -babel-plugin-eval@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" - integrity sha1-ovrtJc5r5preS/7CY/cBaRlZUNo= - babel-plugin-extract-import-names@1.6.22: version "1.6.22" resolved "https://registry.yarnpkg.com/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz#de5f9a28eb12f3eb2578bf74472204e66d1a13dc" @@ -12219,11 +11882,6 @@ babel-plugin-extract-import-names@1.6.22: dependencies: "@babel/helper-plugin-utils" "7.10.4" -babel-plugin-inline-environment-variables@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" - integrity sha1-H1jOkSB61qgmqL9kX6/mj/X+P/4= - babel-plugin-istanbul@6.0.0, babel-plugin-istanbul@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" @@ -12252,11 +11910,6 @@ babel-plugin-jest-hoist@^24.9.0: dependencies: "@types/babel__traverse" "^7.0.6" -babel-plugin-jscript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" - integrity sha1-jzQsOCduh6R9X6CovT1etsytj8w= - babel-plugin-macros@2.8.0, babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" @@ -12275,11 +11928,6 @@ babel-plugin-macros@^3.0.1: cosmiconfig "^7.0.0" resolve "^1.19.0" -babel-plugin-member-expression-literals@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" - integrity sha1-zF7bD6qNyScXDnTW0cAkQAIWJNM= - babel-plugin-module-resolver@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-4.0.0.tgz#8f3a3d9d48287dc1d3b0d5595113adabd36a847f" @@ -12325,28 +11973,6 @@ babel-plugin-prismjs@1.0.2: resolved "https://registry.yarnpkg.com/babel-plugin-prismjs/-/babel-plugin-prismjs-1.0.2.tgz#837bf6b32168b3ba624c054fc755946deb1b63fa" integrity sha512-WbUE86Aih6h6daLpyavuikEXECrkon21oWh4MOHa5stMfY/IK1e/Sr79qEGhl7KrL16fMChB3tdbVR82ubnzOg== -babel-plugin-property-literals@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" - integrity sha1-AlIwGQAZKYCxwRjv6kjOk6q4MzY= - -babel-plugin-proto-to-assign@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" - integrity sha1-xJ56/QL1d7xNoF6i3wAiUM980SM= - dependencies: - lodash "^3.9.3" - -babel-plugin-react-constant-elements@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" - integrity sha1-lGc26DeEKcvDSdz/YvUcFDs041o= - -babel-plugin-react-display-name@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" - integrity sha1-dU/jiSboQkpOexWrbqYTne4FFPw= - babel-plugin-react-docgen@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz#7cc8e2f94e8dc057a06e953162f0810e4e72257b" @@ -12356,21 +11982,6 @@ babel-plugin-react-docgen@^4.2.1: lodash "^4.17.15" react-docgen "^5.0.0" -babel-plugin-remove-console@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" - integrity sha1-2PJFVsOgUAXUKqqv0neH9T/wE6c= - -babel-plugin-remove-debugger@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" - integrity sha1-/S6jzWGkKK0fO5yJiC/0KT6MFMc= - -babel-plugin-runtime@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" - integrity sha1-v3x9lm3Vbs1cF/ocslPJrLflSq8= - "babel-plugin-styled-components@>= 1": version "1.12.0" resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.12.0.tgz#1dec1676512177de6b827211e9eda5a30db4f9b9" @@ -12381,51 +11992,6 @@ babel-plugin-runtime@^1.0.7: babel-plugin-syntax-jsx "^6.18.0" lodash "^4.17.11" -babel-plugin-syntax-async-functions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" - integrity sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU= - -babel-plugin-syntax-async-generators@^6.5.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" - integrity sha1-a8lj67FuzLrmuStZbrfzXDQqi5o= - -babel-plugin-syntax-class-constructor-call@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz#9cb9d39fe43c8600bec8146456ddcbd4e1a76416" - integrity sha1-nLnTn+Q8hgC+yBRkVt3L1OGnZBY= - -babel-plugin-syntax-class-properties@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" - integrity sha1-1+sjt5oxf4VDlixQW4J8fWysJ94= - -babel-plugin-syntax-decorators@^6.13.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" - integrity sha1-MSVjtNvePMgGzuPkFszurd0RrAs= - -babel-plugin-syntax-dynamic-import@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" - integrity sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo= - -babel-plugin-syntax-exponentiation-operator@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" - integrity sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4= - -babel-plugin-syntax-export-extensions@^6.8.0: - version "6.13.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz#70a1484f0f9089a4e84ad44bac353c95b9b12721" - integrity sha1-cKFITw+QiaToStRLrDU8lbmxJyE= - -babel-plugin-syntax-flow@^6.18.0: - version "6.18.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" - integrity sha1-TDqyCiryaqIM0lmVw5jE63AxDI0= - babel-plugin-syntax-jsx@6.18.0, babel-plugin-syntax-jsx@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" @@ -12436,275 +12002,7 @@ babel-plugin-syntax-object-rest-spread@^6.8.0: resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= -babel-plugin-syntax-trailing-function-commas@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" - integrity sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM= - -babel-plugin-transform-async-generator-functions@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" - integrity sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds= - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-generators "^6.5.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-async-to-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" - integrity sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E= - dependencies: - babel-helper-remap-async-to-generator "^6.24.1" - babel-plugin-syntax-async-functions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-class-constructor-call@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz#80dc285505ac067dcb8d6c65e2f6f11ab7765ef9" - integrity sha1-gNwoVQWsBn3LjWxl4vbxGrd2Xvk= - dependencies: - babel-plugin-syntax-class-constructor-call "^6.18.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-class-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" - integrity sha1-anl2PqYdM9NvN7YRqp3vgagbRqw= - dependencies: - babel-helper-function-name "^6.24.1" - babel-plugin-syntax-class-properties "^6.8.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-decorators@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" - integrity sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0= - dependencies: - babel-helper-explode-class "^6.24.1" - babel-plugin-syntax-decorators "^6.13.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-arrow-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" - integrity sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" - integrity sha1-u8UbSflk1wy42OC5ToICRs46YUE= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-block-scoping@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" - integrity sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8= - dependencies: - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-traverse "^6.26.0" - babel-types "^6.26.0" - lodash "^4.17.4" - -babel-plugin-transform-es2015-classes@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" - integrity sha1-WkxYpQyclGHlZLSyo7+ryXolhNs= - dependencies: - babel-helper-define-map "^6.24.1" - babel-helper-function-name "^6.24.1" - babel-helper-optimise-call-expression "^6.24.1" - babel-helper-replace-supers "^6.24.1" - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-computed-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" - integrity sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM= - dependencies: - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-destructuring@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" - integrity sha1-mXux8auWf2gtKwh2/jWNYOdlxW0= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-duplicate-keys@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" - integrity sha1-c+s9MQypaePvnskcU3QabxV2Qj4= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-for-of@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" - integrity sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-function-name@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" - integrity sha1-g0yJhTvDaxrw86TF26qU/Y6sqos= - dependencies: - babel-helper-function-name "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" - integrity sha1-T1SgLWzWbPkVKAAZox0xklN3yi4= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-modules-amd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" - integrity sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ= - dependencies: - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-commonjs@^6.24.1: - version "6.26.2" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" - integrity sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q== - dependencies: - babel-plugin-transform-strict-mode "^6.24.1" - babel-runtime "^6.26.0" - babel-template "^6.26.0" - babel-types "^6.26.0" - -babel-plugin-transform-es2015-modules-systemjs@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" - integrity sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM= - dependencies: - babel-helper-hoist-variables "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-modules-umd@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" - integrity sha1-rJl+YoXNGO1hdq22B9YCNErThGg= - dependencies: - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - -babel-plugin-transform-es2015-object-super@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" - integrity sha1-JM72muIcuDp/hgPa0CH1cusnj40= - dependencies: - babel-helper-replace-supers "^6.24.1" - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-parameters@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" - integrity sha1-V6w1GrScrxSpfNE7CfZv3wpiXys= - dependencies: - babel-helper-call-delegate "^6.24.1" - babel-helper-get-function-arity "^6.24.1" - babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-shorthand-properties@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" - integrity sha1-JPh11nIch2YbvZmkYi5R8U3jiqA= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-spread@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" - integrity sha1-1taKmfia7cRTbIGlQujdnxdG+NE= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-sticky-regex@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" - integrity sha1-AMHNsaynERLN8M9hJsLta0V8zbw= - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-transform-es2015-template-literals@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" - integrity sha1-qEs0UPfp+PH2g51taH2oS7EjbY0= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-typeof-symbol@^6.22.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" - integrity sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I= - dependencies: - babel-runtime "^6.22.0" - -babel-plugin-transform-es2015-unicode-regex@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" - integrity sha1-04sS9C6nMj9yk4fxinxa4frrNek= - dependencies: - babel-helper-regex "^6.24.1" - babel-runtime "^6.22.0" - regexpu-core "^2.0.0" - -babel-plugin-transform-exponentiation-operator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" - integrity sha1-KrDJx/MJj6SJB3cruBP+QejeOg4= - dependencies: - babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" - babel-plugin-syntax-exponentiation-operator "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-export-extensions@^6.22.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz#53738b47e75e8218589eea946cbbd39109bbe653" - integrity sha1-U3OLR+deghhYnuqUbLvTkQm75lM= - dependencies: - babel-plugin-syntax-export-extensions "^6.8.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-flow-strip-types@^6.8.0: - version "6.22.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz#84cb672935d43714fdc32bce84568d87441cf7cf" - integrity sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988= - dependencies: - babel-plugin-syntax-flow "^6.18.0" - babel-runtime "^6.22.0" - -babel-plugin-transform-object-rest-spread@^6.22.0, babel-plugin-transform-object-rest-spread@^6.26.0: +babel-plugin-transform-object-rest-spread@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz#0f36692d50fef6b7e2d4b3ac1478137a963b7b06" integrity sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY= @@ -12717,63 +12015,6 @@ babel-plugin-transform-react-remove-prop-types@0.4.24: resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== -babel-plugin-transform-regenerator@^6.24.1: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" - integrity sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8= - dependencies: - regenerator-transform "^0.10.0" - -babel-plugin-transform-strict-mode@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" - integrity sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g= - dependencies: - babel-runtime "^6.22.0" - babel-types "^6.24.1" - -babel-plugin-undeclared-variables-check@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" - integrity sha1-XPGqU52BP/ZOmWQSkK9iCWX2Xe4= - dependencies: - leven "^1.0.2" - -babel-plugin-undefined-to-void@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" - integrity sha1-f1eO+LeN+uYAM4XYQXph7aBuL4E= - -babel-preset-es2015@^6.9.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" - integrity sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk= - dependencies: - babel-plugin-check-es2015-constants "^6.22.0" - babel-plugin-transform-es2015-arrow-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" - babel-plugin-transform-es2015-block-scoping "^6.24.1" - babel-plugin-transform-es2015-classes "^6.24.1" - babel-plugin-transform-es2015-computed-properties "^6.24.1" - babel-plugin-transform-es2015-destructuring "^6.22.0" - babel-plugin-transform-es2015-duplicate-keys "^6.24.1" - babel-plugin-transform-es2015-for-of "^6.22.0" - babel-plugin-transform-es2015-function-name "^6.24.1" - babel-plugin-transform-es2015-literals "^6.22.0" - babel-plugin-transform-es2015-modules-amd "^6.24.1" - babel-plugin-transform-es2015-modules-commonjs "^6.24.1" - babel-plugin-transform-es2015-modules-systemjs "^6.24.1" - babel-plugin-transform-es2015-modules-umd "^6.24.1" - babel-plugin-transform-es2015-object-super "^6.24.1" - babel-plugin-transform-es2015-parameters "^6.24.1" - babel-plugin-transform-es2015-shorthand-properties "^6.24.1" - babel-plugin-transform-es2015-spread "^6.22.0" - babel-plugin-transform-es2015-sticky-regex "^6.24.1" - babel-plugin-transform-es2015-template-literals "^6.22.0" - babel-plugin-transform-es2015-typeof-symbol "^6.22.0" - babel-plugin-transform-es2015-unicode-regex "^6.24.1" - babel-plugin-transform-regenerator "^6.24.1" - babel-preset-jest@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz#192b521e2217fb1d1f67cf73f70c336650ad3cdc" @@ -12803,36 +12044,6 @@ babel-preset-react-app@^9.0.2, babel-preset-react-app@^9.1.2: babel-plugin-macros "2.8.0" babel-plugin-transform-react-remove-prop-types "0.4.24" -babel-preset-stage-1@^6.5.0: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz#7692cd7dcd6849907e6ae4a0a85589cfb9e2bfb0" - integrity sha1-dpLNfc1oSZB+auSgqFWJz7niv7A= - dependencies: - babel-plugin-transform-class-constructor-call "^6.24.1" - babel-plugin-transform-export-extensions "^6.22.0" - babel-preset-stage-2 "^6.24.1" - -babel-preset-stage-2@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" - integrity sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE= - dependencies: - babel-plugin-syntax-dynamic-import "^6.18.0" - babel-plugin-transform-class-properties "^6.24.1" - babel-plugin-transform-decorators "^6.24.1" - babel-preset-stage-3 "^6.24.1" - -babel-preset-stage-3@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" - integrity sha1-g2raCp56f6N8sTj7kyb4eTSkg5U= - dependencies: - babel-plugin-syntax-trailing-function-commas "^6.22.0" - babel-plugin-transform-async-generator-functions "^6.24.1" - babel-plugin-transform-async-to-generator "^6.24.1" - babel-plugin-transform-exponentiation-operator "^6.24.1" - babel-plugin-transform-object-rest-spread "^6.22.0" - babel-preset-typescript-vue3@^2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/babel-preset-typescript-vue3/-/babel-preset-typescript-vue3-2.0.14.tgz#d60dd7a53d8e1fb60ff755aaaaa5f05c2f871f0f" @@ -12853,27 +12064,7 @@ babel-preset-typescript-vue@^1.0.3: "@babel/preset-typescript" "^7.3.3" vue-template-compiler "^2.6.11" -babel-register@^6.26.0, babel-register@^6.9.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" - integrity sha1-btAhFz4vy0htestFxgCahW9kcHE= - dependencies: - babel-core "^6.26.0" - babel-runtime "^6.26.0" - core-js "^2.5.0" - home-or-tmp "^2.0.0" - lodash "^4.17.4" - mkdirp "^0.5.1" - source-map-support "^0.4.15" - -babel-runtime@^5.6.18: - version "5.8.38" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-5.8.38.tgz#1c0b02eb63312f5f087ff20450827b425c9d4c19" - integrity sha1-HAsC62MxL18If/IEUIJ7QlydTBk= - dependencies: - core-js "^1.0.0" - -babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: +babel-runtime@^6.11.6, babel-runtime@^6.20.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= @@ -12881,7 +12072,7 @@ babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runti core-js "^2.4.0" regenerator-runtime "^0.11.0" -babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0: +babel-template@^6.16.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= @@ -12892,7 +12083,7 @@ babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0: babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.18.0, babel-traverse@^6.23.1, babel-traverse@^6.24.1, babel-traverse@^6.26.0: +babel-traverse@^6.18.0, babel-traverse@^6.23.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= @@ -12907,7 +12098,7 @@ babel-traverse@^6.18.0, babel-traverse@^6.23.1, babel-traverse@^6.24.1, babel-tr invariant "^2.2.2" lodash "^4.17.4" -babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24.1, babel-types@^6.26.0: +babel-types@^6.18.0, babel-types@^6.23.0, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= @@ -12929,12 +12120,7 @@ babelify@10.0.0: resolved "https://registry.yarnpkg.com/babelify/-/babelify-10.0.0.tgz#fe73b1a22583f06680d8d072e25a1e0d1d1d7fb5" integrity sha512-X40FaxyH7t3X+JFAKvb1H9wooWKLRCi8pg3m8poqtdZaIng+bjzp9RvKQCvRjF9isHiPkXspbbXT/zwXLtwgwg== -babylon@^5.8.38: - version "5.8.38" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" - integrity sha1-7JsSCxG/bM1Bc6GL8hfmC3mFn/0= - -babylon@^6.17.0, babylon@^6.17.3, babylon@^6.18.0: +babylon@^6.17.0, babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== @@ -13075,13 +12261,6 @@ bin-links@^1.1.2, bin-links@^1.1.8: npm-normalize-package-bin "^1.0.0" write-file-atomic "^2.3.0" -bin-up@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/bin-up/-/bin-up-1.2.0.tgz#57976407e82b9c39e92d9e22eee0c3e298a95c4c" - integrity sha512-OOv0fU6dcy/2C4QsY0MlkA8c5ro/cqC7xNJ15mDbA35Oynn5vPt8rCiR3kxitQuOGe6vkJH6le6Pg1tQqySLkA== - dependencies: - execa "0.8.0" - binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" @@ -13149,11 +12328,6 @@ bluebird-lst@^1.0.9: dependencies: bluebird "^3.5.5" -bluebird-retry@0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/bluebird-retry/-/bluebird-retry-0.11.0.tgz#1289ab22cbbc3a02587baad35595351dd0c1c047" - integrity sha1-EomrIsu8OgJYe6rTVZU1HdDBwEc= - bluebird@3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" @@ -13179,11 +12353,6 @@ bluebird@3.7.2, bluebird@^3.1.1, bluebird@^3.3.5, bluebird@^3.4.1, bluebird@^3.5 resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -bluebird@^2.9.33: - version "2.11.0" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" - integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE= - blueimp-md5@^2.3.0: version "2.18.0" resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.18.0.tgz#1152be1335f0c6b3911ed9e36db54f3e6ac52935" @@ -13325,7 +12494,7 @@ boxen@^5.0.0: widest-line "^3.1.0" wrap-ansi "^7.0.0" -brace-expansion@^1.0.0, brace-expansion@^1.1.7: +brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== @@ -13333,15 +12502,6 @@ brace-expansion@^1.0.0, brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - braces@^2.3.1, braces@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" @@ -13365,11 +12525,6 @@ braces@^3.0.1, braces@~3.0.2: dependencies: fill-range "^7.0.1" -breakable@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" - integrity sha1-eEp5eRWjjq0nutRWtVcstLuqeME= - brorand@^1.0.1, brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" @@ -14072,7 +13227,7 @@ camelcase@5.3.1, camelcase@^5.0.0, camelcase@^5.2.0, camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^1.0.2, camelcase@^1.2.1: +camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk= @@ -15167,7 +14322,7 @@ commander@2.9.0: dependencies: graceful-readlink ">= 1.0.0" -commander@2.x.x, commander@^2.11.0, commander@^2.12.1, commander@^2.16.0, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@^2.20.3, commander@^2.5.0, commander@^2.8.1: +commander@2.x.x, commander@^2.11.0, commander@^2.12.1, commander@^2.16.0, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@^2.20.3, commander@^2.8.1: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -15230,21 +14385,6 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -commoner@~0.10.3: - version "0.10.8" - resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" - integrity sha1-NPw2cs0kOT6LtH5wyqApOBH08sU= - dependencies: - commander "^2.5.0" - detective "^4.3.1" - glob "^5.0.15" - graceful-fs "^4.1.2" - iconv-lite "^0.4.5" - mkdirp "^0.5.0" - private "^0.1.6" - q "^1.1.2" - recast "^0.11.17" - compare-func@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" @@ -15767,7 +14907,7 @@ core-js@^1.0.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" integrity sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= -core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0: +core-js@^2.4.0: version "2.6.12" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== @@ -16852,7 +15992,7 @@ debug@*, debug@4, debug@4.3.3, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^ dependencies: ms "2.1.2" -debug@2, debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9: +debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -17134,22 +16274,6 @@ defined@^1.0.0: resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= -defs@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" - integrity sha1-siYJ8sehG6ej2xFoBcE5scr/qdI= - dependencies: - alter "~0.2.0" - ast-traverse "~0.1.1" - breakable "~1.0.0" - esprima-fb "~15001.1001.0-dev-harmony-fb" - simple-fmt "~0.1.0" - simple-is "~0.2.0" - stringmap "~0.2.2" - stringset "~0.2.1" - tryor "~0.1.2" - yargs "~3.27.0" - degenerator@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-3.0.1.tgz#7ef78ec0c8577a544477308ddf1d2d6e88d51f5b" @@ -17338,15 +16462,6 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-indent@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" - integrity sha1-ncXl3bzu+DJXZLlFGwK8bVQIT3U= - dependencies: - get-stdin "^4.0.1" - minimist "^1.1.0" - repeating "^1.1.0" - detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" @@ -17482,7 +16597,7 @@ detective-typescript@^7.0.0: node-source-walk "^4.2.0" typescript "^3.9.10" -detective@^4.0.0, detective@^4.3.1: +detective@^4.0.0: version "4.7.1" resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e" integrity sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig== @@ -18628,11 +17743,6 @@ es6-object-assign@^1.1.0: resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw= -es6-promise@^3.0.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" - integrity sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM= - es6-promise@^4.0.3: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" @@ -18725,18 +17835,6 @@ escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escodegen@1.8.x: - version "1.8.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" - integrity sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg= - dependencies: - esprima "^2.7.1" - estraverse "^1.9.1" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.2.0" - escodegen@^1.11.0, escodegen@^1.8.1, escodegen@^1.9.1: version "1.14.3" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" @@ -19122,16 +18220,6 @@ espree@^6.1.2, espree@^6.2.1: acorn-jsx "^5.2.0" eslint-visitor-keys "^1.1.0" -esprima-fb@~15001.1001.0-dev-harmony-fb: - version "15001.1001.0-dev-harmony-fb" - resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" - integrity sha1-Q761fsJujPI3092LM+QlM1d/Jlk= - -esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1: - version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= - esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -19142,11 +18230,6 @@ esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.0.0.tgz#609ac5c2667eae5433b41eb9ecece2331b41498f" integrity sha1-YJrFwmZ+rlQztB657OziMxtBSY8= -esprima@~3.1.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= - esquery@^1.0.1, esquery@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" @@ -19161,11 +18244,6 @@ esrecurse@^4.1.0, esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" - integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q= - estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" @@ -19191,7 +18269,7 @@ estree-walker@^2.0.1: resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== -esutils@^2.0.0, esutils@^2.0.2: +esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== @@ -19325,19 +18403,6 @@ execa@0.11.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@0.8.0, execa@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" - integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - execa@1.0.0, execa@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -19433,6 +18498,19 @@ execa@^0.7.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +execa@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" + integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + execa@^3.3.0: version "3.4.0" resolved "https://registry.yarnpkg.com/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" @@ -19486,13 +18564,6 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= - dependencies: - is-posix-bracket "^0.1.0" - expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -19506,13 +18577,6 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= - dependencies: - fill-range "^2.1.0" - expand-template@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" @@ -19671,13 +18735,6 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= - dependencies: - is-extglob "^1.0.0" - extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" @@ -20043,11 +19100,6 @@ filelist@^1.0.1: dependencies: minimatch "^3.0.4" -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= - filename-reserved-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" @@ -20108,17 +19160,6 @@ fill-keys@^1.0.2: is-object "~1.0.1" merge-descriptors "~1.0.0" -fill-range@^2.1.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" - integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^3.0.0" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -20457,11 +19498,6 @@ flora-colossus@^1.0.0: debug "^4.1.1" fs-extra "^7.0.0" -flow-parser@0.*, flow-parser@^0.*: - version "0.146.0" - resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.146.0.tgz#e389013c4c2bee1ca09a59957223685f8bbefb02" - integrity sha512-lMaDIdcEsdtKL0B+VFp8et/AjnB+cU1HJ6KDrp4Lw3Gsq0Ck0cmWRDgWfUQxxDvY99ntQyA/IdyFxFK4izKo4g== - fluent-ffmpeg@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74" @@ -20844,11 +19880,6 @@ fs-monkey@1.0.3: resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3" integrity sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q== -fs-readdir-recursive@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" - integrity sha1-MVtPuMHKW4xH3v7zGdBz2tNWgFk= - fs-readdir-recursive@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" @@ -21462,17 +20493,6 @@ glob@7.2.0, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.0, glo once "^1.3.0" path-is-absolute "^1.0.0" -glob@^5.0.15: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - global-agent@^2.0.2: version "2.1.12" resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-2.1.12.tgz#e4ae3812b731a9e81cbf825f9377ef450a8e4195" @@ -21591,11 +20611,6 @@ globals@^13.6.0: dependencies: type-fest "^0.20.2" -globals@^6.4.0: - version "6.4.1" - resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" - integrity sha1-hJgDKzttHMge68X3lpDY/in6v08= - globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -22029,7 +21044,7 @@ handlebars@^3.0.3: optionalDependencies: uglify-js "^2.6" -handlebars@^4.0.1, handlebars@^4.7.6: +handlebars@^4.7.6: version "4.7.7" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== @@ -22382,22 +21397,6 @@ hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react- dependencies: react-is "^16.7.0" -home-or-tmp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" - integrity sha1-S58eQIAMPlDGwn94FnavzOcfOYU= - dependencies: - os-tmpdir "^1.0.1" - user-home "^1.1.1" - -home-or-tmp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" - integrity sha1-42w/LSyufXRqhX440Y1fMqeILbg= - dependencies: - os-homedir "^1.0.0" - os-tmpdir "^1.0.1" - homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" @@ -22897,7 +21896,7 @@ iconv-corefoundation@^1.1.6: cli-truncate "^1.1.0" node-addon-api "^1.6.3" -iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@^0.4.5: +iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -23021,11 +22020,6 @@ immer@8.0.1: resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA== -immutable@3.7.6: - version "3.7.6" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" - integrity sha1-E7TTyxK++hVIKib+Gy665kAHHks= - import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -23677,18 +22671,6 @@ is-dom@^1.0.0, is-dom@^1.1.0: is-object "^1.0.1" is-window "^1.0.2" -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= - dependencies: - is-primitive "^2.0.0" - is-expression@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-expression/-/is-expression-4.0.0.tgz#c33155962abf21d0afd2552514d67d2ec16fd2ab" @@ -23815,13 +22797,6 @@ is-installed-globally@^0.4.0, is-installed-globally@~0.4.0: global-dirs "^3.0.0" is-path-inside "^3.0.2" -is-integer@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-integer/-/is-integer-1.0.7.tgz#6bde81aacddf78b659b6629d629cadc51a886d5c" - integrity sha1-a96Bqs3feLZZtmKdYpytxRqIbVw= - dependencies: - is-finite "^1.0.0" - is-interactive@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" @@ -23894,13 +22869,6 @@ is-number-object@^1.0.4: resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= - dependencies: - kind-of "^3.0.2" - is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -24013,16 +22981,6 @@ is-plain-object@^5.0.0: resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= - is-promise@^2.0.0: version "2.2.2" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" @@ -24495,26 +23453,6 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -istanbul@0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" - integrity sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs= - dependencies: - abbrev "1.0.x" - async "1.x" - escodegen "1.8.x" - esprima "2.7.x" - glob "^5.0.15" - handlebars "^4.0.1" - js-yaml "3.x" - mkdirp "0.5.x" - nopt "3.x" - once "1.x" - resolve "1.1.x" - supports-color "^3.1.0" - which "^1.1.1" - wordwrap "^1.0.0" - istextorbinary@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-6.0.0.tgz#bc6e7541006bc203feffe16628d0a72893b2ad54" @@ -25163,13 +24101,6 @@ js-beautify@^1.6.12: mkdirp "^1.0.4" nopt "^5.0.0" -js-codemod@cpojer/js-codemod: - version "8.0.0" - resolved "https://codeload.github.com/cpojer/js-codemod/tar.gz/f08370ce77b5246a481772f138eaa0a92aa6e450" - dependencies: - jscodeshift "^0.3.30" - nuclide-format-js "0.0.36" - js-cookie@2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" @@ -25202,11 +24133,6 @@ js-stringify@^1.0.2: resolved "https://registry.yarnpkg.com/js-stringify/-/js-stringify-1.0.2.tgz#1736fddfd9724f28a3682adc6230ae7e4e9679db" integrity sha1-Fzb939lyTyijaCrcYjCufk6Weds= -js-tokens@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" - integrity sha1-zENaXIuUrRWst5gxQPyAGCyJrq4= - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -25233,7 +24159,7 @@ js-yaml@3.14.0: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@3.14.1, js-yaml@3.x, js-yaml@^3.13.1, js-yaml@^3.7.0: +js-yaml@3.14.1, js-yaml@^3.13.1, js-yaml@^3.7.0: version "3.14.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== @@ -25268,73 +24194,6 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= -jscodemods@cypress-io/jscodemods#01b546e: - version "0.0.0" - resolved "https://codeload.github.com/cypress-io/jscodemods/tar.gz/01b546e627b7a6ffccd10579081d023d67394df8" - -jscodeshift@0.3.20: - version "0.3.20" - resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.3.20.tgz#1e8e7f1c7207d3ab91ae21f160281561156f7caa" - integrity sha1-Ho5/HHIH06uRriHxYCgVYRVvfKo= - dependencies: - async "^1.5.0" - babel-core "^5.8.21" - babel-runtime "^5.6.18" - colors "^1.1.2" - es6-promise "^3.0.0" - lodash "^3.5.0" - micromatch "^2.3.7" - node-dir "0.1.8" - nomnom "^1.8.1" - recast "^0.11.0" - temp "^0.8.1" - -jscodeshift@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.7.0.tgz#4eee7506fd4fdacbd80340287d61575af991fdab" - integrity sha512-Kt6rpTa1HVhAWagD6J0y6qxxqRmDgkFvczerLgOsDNSGoUZSmq2CO1vFRcda9OV1BaZKSHCIh+VREPts5tB/Ig== - dependencies: - "@babel/core" "^7.1.6" - "@babel/parser" "^7.1.6" - "@babel/plugin-proposal-class-properties" "^7.1.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/preset-env" "^7.1.6" - "@babel/preset-flow" "^7.0.0" - "@babel/preset-typescript" "^7.1.0" - "@babel/register" "^7.0.0" - babel-core "^7.0.0-bridge.0" - colors "^1.1.2" - flow-parser "0.*" - graceful-fs "^4.1.11" - micromatch "^3.1.10" - neo-async "^2.5.0" - node-dir "^0.1.17" - recast "^0.18.1" - temp "^0.8.1" - write-file-atomic "^2.3.0" - -jscodeshift@^0.3.30: - version "0.3.32" - resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.3.32.tgz#dece5eb602f16340d8d954c7f96ac907c502eabb" - integrity sha1-3s5etgLxY0DY2VTH+WrJB8UC6rs= - dependencies: - async "^1.5.0" - babel-core "^5" - babel-plugin-transform-flow-strip-types "^6.8.0" - babel-preset-es2015 "^6.9.0" - babel-preset-stage-1 "^6.5.0" - babel-register "^6.9.0" - babylon "^6.17.3" - colors "^1.1.2" - flow-parser "^0.*" - lodash "^4.13.1" - micromatch "^2.3.7" - node-dir "0.1.8" - nomnom "^1.8.1" - recast "^0.12.5" - temp "^0.8.1" - write-file-atomic "^1.2.0" - jsdom@13.2.0: version "13.2.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-13.2.0.tgz#b1a0dbdadc255435262be8ea3723d2dba0d7eb3a" @@ -25367,38 +24226,6 @@ jsdom@13.2.0: ws "^6.1.2" xml-name-validator "^3.0.0" -jsdom@14.1.0, jsdom@^14.0.0, jsdom@^14.1.0: - version "14.1.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-14.1.0.tgz#916463b6094956b0a6c1782c94e380cd30e1981b" - integrity sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng== - dependencies: - abab "^2.0.0" - acorn "^6.0.4" - acorn-globals "^4.3.0" - array-equal "^1.0.0" - cssom "^0.3.4" - cssstyle "^1.1.1" - data-urls "^1.1.0" - domexception "^1.0.1" - escodegen "^1.11.0" - html-encoding-sniffer "^1.0.2" - nwsapi "^2.1.3" - parse5 "5.1.0" - pn "^1.1.0" - request "^2.88.0" - request-promise-native "^1.0.5" - saxes "^3.1.9" - symbol-tree "^3.2.2" - tough-cookie "^2.5.0" - w3c-hr-time "^1.0.1" - w3c-xmlserializer "^1.1.2" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^7.0.0" - ws "^6.1.2" - xml-name-validator "^3.0.0" - jsdom@^11.5.1: version "11.12.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" @@ -25431,6 +24258,38 @@ jsdom@^11.5.1: ws "^5.2.0" xml-name-validator "^3.0.0" +jsdom@^14.0.0, jsdom@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-14.1.0.tgz#916463b6094956b0a6c1782c94e380cd30e1981b" + integrity sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng== + dependencies: + abab "^2.0.0" + acorn "^6.0.4" + acorn-globals "^4.3.0" + array-equal "^1.0.0" + cssom "^0.3.4" + cssstyle "^1.1.1" + data-urls "^1.1.0" + domexception "^1.0.1" + escodegen "^1.11.0" + html-encoding-sniffer "^1.0.2" + nwsapi "^2.1.3" + parse5 "5.1.0" + pn "^1.1.0" + request "^2.88.0" + request-promise-native "^1.0.5" + saxes "^3.1.9" + symbol-tree "^3.2.2" + tough-cookie "^2.5.0" + w3c-hr-time "^1.0.1" + w3c-xmlserializer "^1.1.2" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^7.0.0" + ws "^6.1.2" + xml-name-validator "^3.0.0" + jsesc@2.5.2, jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -25546,11 +24405,6 @@ json3@^3.3.2, json3@^3.3.3: resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== -json5@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" - integrity sha1-BUNS5MTIDIbAkjh31EneF2pzLI0= - json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" @@ -26221,11 +25075,6 @@ levelup@^0.18.2: semver "~2.3.1" xtend "~3.0.0" -leven@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" - integrity sha1-kUS27ryl8dBoAWnxpncNzqYLdcM= - leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -26952,12 +25801,12 @@ lodash@4.17.4: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" integrity sha1-eCA6TRwyiuHYbcpkYONptX9AVa4= -"lodash@>=3.5 <5", lodash@^4.13.1, lodash@^4.14.0, lodash@^4.16.2, lodash@^4.16.4, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0, lodash@~4.17.2: +"lodash@>=3.5 <5", lodash@^4.14.0, lodash@^4.16.2, lodash@^4.16.4, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0, lodash@~4.17.2: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -lodash@^3.1.0, lodash@^3.10.0, lodash@^3.5.0, lodash@^3.9.3: +lodash@^3.1.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y= @@ -26970,7 +25819,7 @@ log-ok@^0.1.1: ansi-green "^0.1.1" success-symbol "^0.1.0" -log-symbols@2.2.0, log-symbols@^2.1.0, log-symbols@^2.2.0: +log-symbols@2.2.0, log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== @@ -27014,14 +25863,6 @@ loglevel@^1.4.1, loglevel@^1.6.6, loglevel@^1.6.8: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== -loglevelnext@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-1.0.5.tgz#36fc4f5996d6640f539ff203ba819641680d75a2" - integrity sha512-V/73qkPuJmx4BcBF19xPBr+0ZRVBhc4POxvZTZdMeXpJ4NItXSJ/MSwuFT0kQJlCbXvdlZoQQ/418bS1y9Jh6A== - dependencies: - es6-symbol "^3.1.1" - object.assign "^4.1.0" - lolex@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.3.2.tgz#7c3da62ffcb30f0f5a80a2566ca24e45d8a01f31" @@ -27420,11 +26261,6 @@ matcher@^3.0.0: dependencies: escape-string-regexp "^4.0.0" -math-random@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" - integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== - md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -27674,26 +26510,7 @@ microevent.ts@~0.1.1: resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== -micromatch@^2.3.7: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - -micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8, micromatch@^3.1.9: +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -27882,20 +26699,13 @@ minimatch@0.3: lru-cache "2" sigmund "~1.0.0" -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4: +minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" -minimatch@^2.0.3: - version "2.0.10" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" - integrity sha1-jQh8OcazjAAbl/ynzm0OHoCvusc= - dependencies: - brace-expansion "^1.0.0" - minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -28088,7 +26898,7 @@ mkdirp@0.5.3: dependencies: minimist "^1.2.5" -mkdirp@0.5.5, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@^0.5.5, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5.5, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@^0.5.5, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -28992,16 +27802,6 @@ nock@12.0.2: lodash "^4.17.13" propagate "^2.0.0" -nock@12.0.3: - version "12.0.3" - resolved "https://registry.yarnpkg.com/nock/-/nock-12.0.3.tgz#83f25076dbc4c9aa82b5cdf54c9604c7a778d1c9" - integrity sha512-QNb/j8kbFnKCiyqi9C5DD0jH/FubFGj5rt9NQFONXwQm3IPB0CULECg/eS3AU1KgZb/6SwUa4/DTRKhVxkGABw== - dependencies: - debug "^4.1.0" - json-stringify-safe "^5.0.1" - lodash "^4.17.13" - propagate "^2.0.0" - nock@13.0.7: version "13.0.7" resolved "https://registry.yarnpkg.com/nock/-/nock-13.0.7.tgz#9bc718c66bd0862dfa14601a9ba678a406127910" @@ -29029,12 +27829,7 @@ node-addon-api@^3.1.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239" integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw== -node-dir@0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.8.tgz#55fb8deb699070707fb67f91a460f0448294c77d" - integrity sha1-VfuN62mQcHB/tn+RpGDwRIKUx30= - -node-dir@^0.1.10, node-dir@^0.1.17: +node-dir@^0.1.10: version "0.1.17" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" integrity sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU= @@ -29244,7 +28039,7 @@ node-uuid@^1.4.1: resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" integrity sha1-sEDrCSOWivq/jTL7HxfxFn/auQc= -nomnom@^1.5.x, nomnom@^1.8.1: +nomnom@^1.5.x: version "1.8.1" resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" integrity sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc= @@ -29264,13 +28059,6 @@ nopt@1.0.10: dependencies: abbrev "1" -nopt@3.x: - version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= - dependencies: - abbrev "1" - nopt@^4.0.1, nopt@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" @@ -29306,7 +28094,7 @@ normalize-package-data@^3.0.0: semver "^7.3.2" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.1, normalize-path@^2.1.1: +normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= @@ -29763,15 +28551,6 @@ nth-check@^2.0.0: dependencies: boolbase "^1.0.0" -nuclide-format-js@0.0.36: - version "0.0.36" - resolved "https://registry.yarnpkg.com/nuclide-format-js/-/nuclide-format-js-0.0.36.tgz#e6934066b4d817c09545c5cddb6c911a421ac69a" - integrity sha1-5pNAZrTYF8CVRcXN22yRGkIaxpo= - dependencies: - babel-core "5.8.38" - immutable "3.7.6" - jscodeshift "0.3.20" - num2fraction@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" @@ -29965,7 +28744,7 @@ object.map@^1.0.0: for-own "^1.0.0" make-iterator "^1.0.0" -object.omit@^2.0.0, object.omit@~2.0.0: +object.omit@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= @@ -30035,7 +28814,7 @@ on-headers@~1.0.1, on-headers@~1.0.2: resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== -once@1.x, once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.3.3, once@^1.4.0, once@~1.4.0: +once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.3.3, once@^1.4.0, once@~1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -30255,7 +29034,7 @@ os-name@^3.0.0, os-name@^3.1.0: macos-release "^2.2.0" windows-release "^3.1.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= @@ -30280,15 +29059,6 @@ outpipe@^1.1.0: dependencies: shell-quote "^1.4.2" -output-file-sync@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" - integrity sha1-0KM+7+YaIF+suQCS6CZZjVJFznY= - dependencies: - graceful-fs "^4.1.4" - mkdirp "^0.5.1" - object-assign "^4.1.0" - overlayscrollbars@^1.13.1: version "1.13.1" resolved "https://registry.yarnpkg.com/overlayscrollbars/-/overlayscrollbars-1.13.1.tgz#0b840a88737f43a946b9d87875a2f9e421d0338a" @@ -30786,16 +29556,6 @@ parse-github-repo-url@^1.3.0: resolved "https://registry.yarnpkg.com/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz#9e7d8bb252a6cb6ba42595060b7bf6df3dbc1f50" integrity sha1-nn2LslKmy2ukJZUGC3v23z28H1A= -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - parse-headers@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.3.tgz#5e8e7512383d140ba02f0c7aa9f49b4399c92515" @@ -30826,11 +29586,6 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -parse-ms@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" - integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA== - parse-node-version@^1.0.0, parse-node-version@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" @@ -31000,11 +29755,6 @@ path-dirname@^1.0.0: resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= -path-exists@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" - integrity sha1-1aiZjrce83p0w06w2eum6HjuoIE= - path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" @@ -32573,15 +31323,6 @@ precinct@^8.0.0: module-definition "^3.3.1" node-source-walk "^4.2.0" -prefixed-list@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prefixed-list/-/prefixed-list-1.0.1.tgz#929da401f225e6c088c6f4fedd8ec45085e511ca" - integrity sha1-kp2kAfIl5sCIxvT+3Y7EUIXlEco= - dependencies: - check-more-types "2.24.0" - lazy-ass "1.6.0" - ramda "0.24.1" - prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -32602,11 +31343,6 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= - prettier@^1.16.4, prettier@^1.18.2: version "1.19.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" @@ -32645,13 +31381,6 @@ pretty-hrtime@^1.0.0, pretty-hrtime@^1.0.3: resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= -pretty-ms@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-7.0.0.tgz#45781273110caf35f55cab21a8a9bd403a233dc0" - integrity sha512-J3aPWiC5e9ZeZFuSeBraGxSkGMOvulSWsxDByOcbD1Pr75YL3LSNIKIb52WXbCLE1sS5s4inBBbryjF4Y05Ceg== - dependencies: - parse-ms "^2.1.0" - pretty@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pretty/-/pretty-2.0.0.tgz#adbc7960b7bbfe289a557dc5f737619a220d06a5" @@ -32692,11 +31421,6 @@ prismjs@^1.21.0, prismjs@~1.23.0: optionalDependencies: clipboard "^2.0.0" -private@^0.1.6, private@^0.1.8, private@~0.1.5: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - process-es6@^0.11.2: version "0.11.6" resolved "https://registry.yarnpkg.com/process-es6/-/process-es6-0.11.6.tgz#c6bb389f9a951f82bd4eb169600105bd2ff9c778" @@ -33231,11 +31955,6 @@ railroad-diagrams@^1.0.0: resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" integrity sha1-635iZ1SN3t+4mcG5Dlc3RVnN234= -ramda@0.24.1: - version "0.24.1" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.24.1.tgz#c3b7755197f35b8dc3502228262c4c91ddb6b857" - integrity sha1-w7d1UZfzW43DUCIoJixMkd22uFc= - ramda@0.25.0, ramda@^0.25.0: version "0.25.0" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" @@ -33274,15 +31993,6 @@ random-bytes@~1.0.0: resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" integrity sha1-T2ih3Arli9P7lYSMMDJNt11kNgs= -randomatic@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" - integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== - dependencies: - is-number "^4.0.0" - kind-of "^6.0.0" - math-random "^1.0.1" - randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -34486,16 +33196,6 @@ realpath-native@^1.1.0: dependencies: util.promisify "^1.0.0" -recast@0.10.33, recast@^0.10.10: - version "0.10.33" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" - integrity sha1-lCgI96oBbx+nFCxGHX5XBKqo1pc= - dependencies: - ast-types "0.8.12" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - source-map "~0.5.0" - recast@0.20.4: version "0.20.4" resolved "https://registry.yarnpkg.com/recast/-/recast-0.20.4.tgz#db55983eac70c46b3fff96c8e467d65ffb4a7abc" @@ -34506,37 +33206,6 @@ recast@0.20.4: source-map "~0.6.1" tslib "^2.0.1" -recast@^0.11.0, recast@^0.11.17: - version "0.11.23" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" - integrity sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM= - dependencies: - ast-types "0.9.6" - esprima "~3.1.0" - private "~0.1.5" - source-map "~0.5.0" - -recast@^0.12.5: - version "0.12.9" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.12.9.tgz#e8e52bdb9691af462ccbd7c15d5a5113647a15f1" - integrity sha512-y7ANxCWmMW8xLOaiopiRDlyjQ9ajKRENBH+2wjntIbk3A6ZR1+BLQttkmSHMY7Arl+AAZFwJ10grg2T6f1WI8A== - dependencies: - ast-types "0.10.1" - core-js "^2.4.1" - esprima "~4.0.0" - private "~0.1.5" - source-map "~0.6.1" - -recast@^0.18.1: - version "0.18.10" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.18.10.tgz#605ebbe621511eb89b6356a7e224bff66ed91478" - integrity sha512-XNvYvkfdAN9QewbrxeTOjgINkdY/odTgTS56ZNEWL9Ml0weT4T3sFtvnTuF+Gxyu46ANcRm1ntrF6F5LAJPAaQ== - dependencies: - ast-types "0.13.3" - esprima "~4.0.0" - private "^0.1.8" - source-map "~0.6.1" - rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -34626,7 +33295,7 @@ regenerate-unicode-properties@^8.2.0: dependencies: regenerate "^1.4.0" -regenerate@^1.2.1, regenerate@^1.4.0: +regenerate@^1.4.0: version "1.4.2" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== @@ -34651,15 +33320,6 @@ regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0 resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== -regenerator-transform@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" - integrity sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q== - dependencies: - babel-runtime "^6.18.0" - babel-types "^6.19.0" - private "^0.1.6" - regenerator-transform@^0.14.2: version "0.14.5" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" @@ -34667,25 +33327,6 @@ regenerator-transform@^0.14.2: dependencies: "@babel/runtime" "^7.8.4" -regenerator@0.8.40: - version "0.8.40" - resolved "https://registry.yarnpkg.com/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" - integrity sha1-oORXxY69uuV1yfjNdRJ+k3VkNdg= - dependencies: - commoner "~0.10.3" - defs "~1.1.0" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - recast "0.10.33" - through "~2.3.8" - -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== - dependencies: - is-equal-shallow "^0.1.3" - regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -34722,15 +33363,6 @@ regexpp@^3.0.0, regexpp@^3.1.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== -regexpu-core@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" - integrity sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA= - dependencies: - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - regexpu-core@^4.7.1: version "4.7.1" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" @@ -34743,17 +33375,6 @@ regexpu-core@^4.7.1: unicode-match-property-ecmascript "^1.0.4" unicode-match-property-value-ecmascript "^1.2.0" -regexpu@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" - integrity sha1-5TTcmRqeWEYFDJjebX3UpVyeoW0= - dependencies: - esprima "^2.6.0" - recast "^0.10.10" - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - registry-auth-token@3.3.2, registry-auth-token@^3.0.1: version "3.3.2" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" @@ -34799,23 +33420,11 @@ registry-url@^5.0.0: dependencies: rc "^1.2.8" -regjsgen@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" - integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= - regjsgen@^0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== -regjsparser@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" - integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw= - dependencies: - jsesc "~0.5.0" - regjsparser@^0.6.4: version "0.6.7" resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.7.tgz#c00164e1e6713c2e3ee641f1701c4b7aa0a7f86c" @@ -34946,13 +33555,6 @@ repeat-string@^1.5.2, repeat-string@^1.5.4, repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -repeating@^1.1.0, repeating@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" - integrity sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw= - dependencies: - is-finite "^1.0.0" - repeating@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" @@ -34960,11 +33562,6 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -repl.history@0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/repl.history/-/repl.history-0.1.4.tgz#80367171f3781d6e4299c71758c253097f5d5832" - integrity sha1-gDZxcfN4HW5CmccXWMJTCX9dWDI= - replace-ext@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" @@ -35213,7 +33810,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.1.7, resolve@1.1.x: +resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= @@ -35387,7 +33984,7 @@ rimraf@2.6.2: dependencies: glob "^7.0.5" -rimraf@2.6.3, rimraf@~2.6.2: +rimraf@2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -36375,11 +34972,6 @@ simple-concat@^1.0.0: resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== -simple-fmt@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" - integrity sha1-GRv1ZqWeZTBILLJatTtKjchcOms= - simple-get@^3.0.3: version "3.1.0" resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.1.0.tgz#b45be062435e50d159540b576202ceec40b9c6b3" @@ -36389,11 +34981,6 @@ simple-get@^3.0.3: once "^1.3.1" simple-concat "^1.0.0" -simple-is@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" - integrity sha1-Krt1qt453rXMgVzhDmGRFkhQuvA= - simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" @@ -36591,7 +35178,7 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -slide@^1.1.3, slide@^1.1.5, slide@^1.1.6, slide@~1.1.3, slide@~1.1.6: +slide@^1.1.3, slide@^1.1.6, slide@~1.1.3, slide@~1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= @@ -37037,32 +35624,11 @@ source-map-support@0.5.19, source-map-support@^0.5.10, source-map-support@^0.5.1 buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.2.10: - version "0.2.10" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" - integrity sha1-6lo5AKHByyUJagrozFwrSxDe09w= - dependencies: - source-map "0.1.32" - -source-map-support@^0.4.15: - 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.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== -source-map@0.1.32: - version "0.1.32" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" - integrity sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY= - dependencies: - amdefine ">=0.0.4" - source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -37088,18 +35654,11 @@ source-map@^0.1.40: dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3: +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1, source-map@~0.5.3: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" - integrity sha1-2rc/vPwrqBm03gO9b26qSBZLP50= - dependencies: - amdefine ">=0.0.4" - sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8: version "1.4.8" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" @@ -37339,7 +35898,7 @@ ssri@^8.0.0, ssri@^8.0.1: dependencies: minipass "^3.1.1" -stable@^0.1.8, stable@~0.1.3: +stable@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== @@ -37696,16 +36255,6 @@ stringify-package@^1.0.0, stringify-package@^1.0.1: resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85" integrity sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg== -stringmap@~0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" - integrity sha1-VWwTeyWPlCuHdvWy71gqoGnX0bE= - -stringset@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" - integrity sha1-7yWcTjSTRDd/zRyRPdLoSMnAQrU= - strip-ansi@*, strip-ansi@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" @@ -38114,7 +36663,7 @@ supports-color@^2.0.0: resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= -supports-color@^3.1.0, supports-color@^3.2.3: +supports-color@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= @@ -38435,13 +36984,6 @@ temp-write@^3.4.0: temp-dir "^1.0.0" uuid "^3.0.1" -temp@^0.8.1: - version "0.8.4" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2" - integrity sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg== - dependencies: - rimraf "~2.6.2" - tempy@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/tempy/-/tempy-1.0.0.tgz#4f192b3ee3328a2684d0e3fc5c491425395aab65" @@ -38709,14 +37251,6 @@ through2-filter@^3.0.0: through2 "~2.0.0" xtend "~4.0.0" -through2@2.0.5, through2@^2.0.0, through2@^2.0.1, through2@^2.0.2, through2@^2.0.3, through2@~2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - through2@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.0.tgz#468b461df9cd9fcc170f22ebf6852e467e578ff2" @@ -38725,6 +37259,14 @@ through2@3.0.0: readable-stream "2 || 3" xtend "~4.0.1" +through2@^2.0.0, through2@^2.0.1, through2@^2.0.2, through2@^2.0.3, through2@~2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + through2@^3.0.0, through2@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" @@ -38740,7 +37282,7 @@ through2@^4.0.0: dependencies: readable-stream "3" -through@2, through@2.3.8, "through@>=2.2.7 <3", through@X.X.X, through@^2.3.4, through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1, through@~2.3.8: +through@2, through@2.3.8, "through@>=2.2.7 <3", through@X.X.X, through@^2.3.4, through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -38875,7 +37417,7 @@ to-arraybuffer@^1.0.0: resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= -to-fast-properties@^1.0.0, to-fast-properties@^1.0.3: +to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= @@ -39057,7 +37599,7 @@ trim-repeated@^1.0.0: dependencies: escape-string-regexp "^1.0.2" -trim-right@^1.0.0, trim-right@^1.0.1: +trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= @@ -39084,21 +37626,11 @@ truncate-utf8-bytes@^1.0.0: dependencies: utf8-byte-length "^1.0.1" -try-resolve@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" - integrity sha1-z95vq9ctY+V5fPqrhzq76OcA6RI= - tryer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== -tryor@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" - integrity sha1-gUXkynyv9ArN48z5Rui4u3W0Fys= - ts-dedent@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.1.1.tgz#6dd56870bb5493895171334fa5d7e929107e5bbc" @@ -39109,17 +37641,6 @@ ts-essentials@^2.0.3: resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-2.0.12.tgz#c9303f3d74f75fa7528c3d49b80e089ab09d8745" integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w== -ts-loader@7.0.4: - version "7.0.4" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-7.0.4.tgz#5d9b95227de5afb91fdd9668f8920eb193cfe0cc" - integrity sha512-5du6OQHl+4ZjO4crEyoYUyWSrmmo7bAO+inkaILZ68mvahqrfoa4nn0DRmpQ4ruT4l+cuJCgF0xD7SBIyLeeow== - dependencies: - chalk "^2.3.0" - enhanced-resolve "^4.0.0" - loader-utils "^1.0.2" - micromatch "^4.0.0" - semver "^6.0.0" - ts-loader@8.0.13: version "8.0.13" resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.0.13.tgz#2bebeb833570ca46bb9338322a9a29900e988535" @@ -39262,11 +37783,6 @@ tslib@2.1.0, tslib@~2.1.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== -tslib@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" - integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== - tslib@^1.0.0, tslib@^1.10.0, tslib@^1.11.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -40132,11 +38648,6 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -user-home@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" - integrity sha1-K1viOjK2Onyd640PKNSFcko98ZA= - user-home@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" @@ -40239,7 +38750,7 @@ uuid@8.3.2, uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0, uuid@^3.3.2, uuid@^3.3.3, uuid@^3.4.0: +uuid@^3.0.0, uuid@^3.0.1, uuid@^3.3.2, uuid@^3.3.3, uuid@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -41426,16 +39937,6 @@ webpack-livereload-plugin@2.3.0: portfinder "^1.0.17" tiny-lr "^1.1.1" -webpack-log@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-1.2.0.tgz#a4b34cda6b22b518dbb0ab32e567962d5c72a43d" - integrity sha512-U9AnICnu50HXtiqiDxuli5gLB5PGBo7VvcHx36jRZHwK4vzOYLbImqT4lwWwoMHdQWwEKw736fCHEekokTEKHA== - dependencies: - chalk "^2.1.0" - log-symbols "^2.1.0" - loglevelnext "^1.0.1" - uuid "^3.1.0" - webpack-log@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" @@ -41938,11 +40439,6 @@ window-size@0.1.0: resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0= -window-size@^0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" - integrity sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY= - windows-release@^3.1.0: version "3.3.3" resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.3.tgz#1c10027c7225743eec6b89df160d64c2e0293999" @@ -42216,15 +40712,6 @@ write-file-atomic@2.4.1: imurmurhash "^0.1.4" signal-exit "^3.0.2" -write-file-atomic@^1.2.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" - integrity sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8= - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - slide "^1.1.5" - write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.2, write-file-atomic@^2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" @@ -42465,11 +40952,7 @@ xvfb-maybe@0.2.1, xvfb-maybe@^0.2.1: debug "^2.2.0" which "^1.2.4" -xvfb@cypress-io/node-xvfb#22e3783c31d81ebe64d8c0df491ea00cdc74726a: - version "0.3.0" - resolved "https://codeload.github.com/cypress-io/node-xvfb/tar.gz/22e3783c31d81ebe64d8c0df491ea00cdc74726a" - -y18n@^3.2.0, y18n@^3.2.1: +y18n@^3.2.1: version "3.2.2" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696" integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ== @@ -42856,18 +41339,6 @@ yargs@~3.10.0: decamelize "^1.0.0" window-size "0.1.0" -yargs@~3.27.0: - version "3.27.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" - integrity sha1-ISBUaTFuk5Ex1Z8toMbX+YIh6kA= - dependencies: - camelcase "^1.2.1" - cliui "^2.1.0" - decamelize "^1.0.0" - os-locale "^1.4.0" - window-size "^0.1.2" - y18n "^3.2.0" - yarn-deduplicate@3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/yarn-deduplicate/-/yarn-deduplicate-3.1.0.tgz#3018d93e95f855f236a215b591fe8bc4bcabba3e" From 86f5b49d2cdfbf133d3020ea62e8eda70c8ee508 Mon Sep 17 00:00:00 2001 From: Emily Rohrbough Date: Tue, 19 Apr 2022 11:00:16 -0500 Subject: [PATCH 08/16] chore(sessions): break out session utils and write some unit tests (#21048) Co-authored-by: Matt Schile Co-authored-by: Bill Glesias --- .../commands/sessions/utils_spec.js | 244 ++++++++++++++++++ .../{sessions.ts => sessions/index.ts} | 209 +-------------- .../driver/src/cy/commands/sessions/utils.ts | 208 +++++++++++++++ 3 files changed, 463 insertions(+), 198 deletions(-) create mode 100644 packages/driver/cypress/integration/commands/sessions/utils_spec.js rename packages/driver/src/cy/commands/{sessions.ts => sessions/index.ts} (76%) create mode 100644 packages/driver/src/cy/commands/sessions/utils.ts diff --git a/packages/driver/cypress/integration/commands/sessions/utils_spec.js b/packages/driver/cypress/integration/commands/sessions/utils_spec.js new file mode 100644 index 000000000000..dcf0705a1144 --- /dev/null +++ b/packages/driver/cypress/integration/commands/sessions/utils_spec.js @@ -0,0 +1,244 @@ +const { + getSessionDetails, + getConsoleProps, + navigateAboutBlank, +} = require('@packages/driver/src/cy/commands/sessions/utils') + +describe('src/cy/commands/sessions/utils.ts', () => { + describe('.getSessionDetails', () => { + it('for one domain with neither cookies or local storage set', () => { + const sessionState = { + id: 'session1', + } + + const details = getSessionDetails(sessionState) + + expect(details.id).to.eq('session1') + expect(Object.keys(details.data)).to.have.length(0) + }) + + it('for one domain with only cookies set', () => { + const sessionState = { + id: 'session1', + cookies: [ + { name: 'foo', value: 'f', path: '/', domain: 'localhost', secure: true, httpOnly: true, expiry: 123 }, + ], + } + + const details = getSessionDetails(sessionState) + + expect(details.id).to.eq('session1') + expect(Object.keys(details.data)).to.have.length(1) + expect(details.data).to.have.property('localhost') + expect(details.data.localhost).to.deep.eq({ + cookies: 1, + }) + }) + + it('for one domain with only local storage set', () => { + const sessionState = { + id: 'session1', + localStorage: [ + { origin: 'localhost', value: { 'stor-foo': 's-f' } }, + ], + } + + const details = getSessionDetails(sessionState) + + expect(details.id).to.eq('session1') + expect(Object.keys(details.data)).to.have.length(1) + expect(details.data).to.have.property('localhost') + expect(details.data.localhost).to.deep.eq({ + localStorage: 1, + }) + }) + + it('for one domain with both cookies and localStorage', () => { + const sessionState = { + id: 'session1', + cookies: [ + { name: 'foo', value: 'f', path: '/', domain: 'localhost', secure: true, httpOnly: true, expiry: 123 }, + ], + localStorage: [ + { origin: 'localhost', value: { 'stor-foo': 's-f' } }, + ], + } + + const details = getSessionDetails(sessionState) + + expect(details.id).to.eq('session1') + expect(Object.keys(details.data)).to.have.length(1) + expect(details.data).to.have.property('localhost') + expect(details.data.localhost).to.deep.eq({ + cookies: 1, + localStorage: 1, + }) + }) + + it('for multiple domains', () => { + const sessionState = { + id: 'session1', + cookies: [ + { name: 'foo', value: 'f', path: '/', domain: 'localhost', secure: true, httpOnly: true, expiry: 123 }, + { name: 'bar', value: 'b', path: '/', domain: 'localhost', secure: false, httpOnly: false, expiry: 456 }, + ], + localStorage: [ + { origin: 'localhost', value: { 'stor-foo': 's-f' } }, + { origin: 'http://example.com', value: { 'random': 'hi' } }, + ], + } + + const details = getSessionDetails(sessionState) + + expect(details.id).to.eq('session1') + expect(Object.keys(details.data)).to.have.length(2) + expect(details.data).to.have.property('localhost') + expect(details.data.localhost).to.deep.eq({ + cookies: 2, + localStorage: 1, + }) + + expect(details.data).to.have.property('example.com') + expect(details.data['example.com']).to.deep.eq({ + localStorage: 1, + }) + }) + }) + + describe('.getConsoleProps', () => { + it('for one domain with neither cookies or localStorage set', () => { + const sessionState = { + id: 'session1', + } + + const consoleProps = getConsoleProps(sessionState) + + expect(consoleProps.id).to.eq('session1') + expect(consoleProps.table).to.have.length(0) + }) + + it('for one domain with only cookies set', () => { + const sessionState = { + id: 'session1', + cookies: [ + { name: 'foo', value: 'f', path: '/', domain: 'localhost', secure: true, httpOnly: true, expiry: 123 }, + ], + } + + const consoleProps = getConsoleProps(sessionState) + + expect(consoleProps.id).to.eq('session1') + expect(consoleProps.table).to.have.length(1) + const cookiesTable = consoleProps.table[0]() + + expect(cookiesTable.name).to.contain('Cookies - localhost (1)') + expect(cookiesTable.data).to.deep.eq(sessionState.cookies) + }) + + it('for one domain with only localStorage set', () => { + const sessionState = { + id: 'session1', + localStorage: [ + { origin: 'localhost', value: { 'stor-foo': 's-f' } }, + ], + } + const consoleProps = getConsoleProps(sessionState) + + expect(consoleProps.id).to.eq('session1') + expect(consoleProps.table).to.have.length(1) + const localStorageTable = consoleProps.table[0]() + + expect(localStorageTable.name).to.contain('Storage - localhost (1)') + expect(localStorageTable.data).to.have.length(1) + expect(localStorageTable.data).to.deep.eq([{ key: 'stor-foo', value: 's-f' }]) + }) + + it('for one domain with both cookies and localStorage set', () => { + const sessionState = { + id: 'session1', + cookies: [ + { name: 'foo', value: 'f', path: '/', domain: 'localhost', secure: true, httpOnly: true, expiry: 123 }, + ], + localStorage: [ + { origin: 'localhost', value: { 'stor-foo': 's-f' } }, + ], + } + + const consoleProps = getConsoleProps(sessionState) + + expect(consoleProps.id).to.eq('session1') + expect(consoleProps.table).to.have.length(2) + let table = consoleProps.table[0]() + + expect(table.name).to.contain('Cookies - localhost (1)') + expect(table.data).to.have.length(1) + expect(table.data).to.deep.eq(sessionState.cookies) + + table = consoleProps.table[1]() + expect(table.name).to.contain('Storage - localhost (1)') + expect(table.data).to.have.length(1) + expect(table.data).to.deep.eq([{ key: 'stor-foo', value: 's-f' }]) + }) + + it('for multiple domains', () => { + const sessionState = { + id: 'session1', + cookies: [ + { name: 'foo', value: 'f', path: '/', domain: 'localhost', secure: true, httpOnly: true, expiry: 123 }, + { name: 'bar', value: 'b', path: '/', domain: 'localhost', secure: false, httpOnly: false, expiry: 456 }, + ], + localStorage: [ + { origin: 'localhost', value: { 'stor-foo': 's-f' } }, + { origin: 'http://example.com', value: { 'random': 'hi' } }, + ], + } + + const consoleProps = getConsoleProps(sessionState) + + expect(consoleProps.id).to.eq('session1') + expect(consoleProps.table).to.have.length(3) + let table = consoleProps.table[0]() + + expect(table.name).to.contain('Cookies - localhost (2)') + expect(table.data).to.have.length(2) + expect(table.data).to.deep.eq(sessionState.cookies) + + table = consoleProps.table[1]() + expect(table.name).to.contain('Storage - localhost (1)') + expect(table.data).to.have.length(1) + expect(table.data).to.deep.eq([{ key: 'stor-foo', value: 's-f' }]) + + table = consoleProps.table[2]() + expect(table.name).to.contain('Storage - example.com (1)') + expect(table.data).to.have.length(1) + expect(table.data).to.deep.eq([{ key: 'random', value: 'hi' }]) + }) + }) + + describe('.navigateAboutBlank', () => { + it('triggers session blank page visit', () => { + const stub = cy.stub(Cypress, 'action').log(false) + .callThrough() + .withArgs('cy:visit:blank') + + cy.then(() => { + navigateAboutBlank() + navigateAboutBlank(true) + expect(stub).to.have.been.calledTwice + expect(stub.args[0]).to.deep.eq(['cy:visit:blank', { type: 'session' }]) + expect(stub.args[1]).to.deep.eq(['cy:visit:blank', { type: 'session' }]) + }) + }) + + it('triggers session-lifecycle blank page visit', () => { + const stub = cy.stub(Cypress, 'action').log(false) + .callThrough() + .withArgs('cy:visit:blank') + + cy.then(() => { + navigateAboutBlank(false) + expect(stub).to.have.been.calledWith('cy:visit:blank', { type: 'session-lifecycle' }) + }) + }) + }) +}) diff --git a/packages/driver/src/cy/commands/sessions.ts b/packages/driver/src/cy/commands/sessions/index.ts similarity index 76% rename from packages/driver/src/cy/commands/sessions.ts rename to packages/driver/src/cy/commands/sessions/index.ts index 0f526910b602..4aaedbc4cd17 100644 --- a/packages/driver/src/cy/commands/sessions.ts +++ b/packages/driver/src/cy/commands/sessions/index.ts @@ -1,10 +1,16 @@ import _ from 'lodash' -import $ from 'jquery' -import { $Location } from '../../cypress/location' -import $errUtils from '../../cypress/error_utils' +import { $Location } from '../../../cypress/location' +import $errUtils from '../../../cypress/error_utils' import stringifyStable from 'json-stable-stringify' -import $stackUtils from '../../cypress/stack_utils' -import Bluebird from 'bluebird' +import $stackUtils from '../../../cypress/stack_utils' +import { + getSessionDetails, + getCurrentOriginStorage, + setPostMessageLocalStorage, + getConsoleProps, + getPostMessageLocalStorage, + navigateAboutBlank, +} from './utils' const currentTestRegisteredSessions = new Map() type ActiveSessions = Cypress.Commands.Session.ActiveSessions @@ -18,193 +24,6 @@ type SessionData = Cypress.Commands.Session.SessionData * therefore session data should be cleared with spec browser launch */ -const getSessionDetails = (sessState: SessionData) => { - return { - id: sessState.id, - data: _.merge( - _.mapValues(_.groupBy(sessState.cookies, 'domain'), (v) => ({ cookies: v.length })), - ..._.map(sessState.localStorage, (v) => ({ [$Location.create(v.origin).hostname]: { localStorage: Object.keys(v.value).length } })), - ) } -} - -const getSessionDetailsForTable = (sessState: SessionData) => { - return _.merge( - _.mapValues(_.groupBy(sessState.cookies, 'domain'), (v) => ({ cookies: v })), - ..._.map(sessState.localStorage, (v) => ({ [$Location.create(v.origin).hostname]: { localStorage: v } })), - ) -} - -const isSecureContext = (url: string) => url.startsWith('https:') - -const getCurrentOriginStorage = () => { - // localStorage.length property is not always accurate, we must stringify to check for entries - // for ex) try setting localStorage.key = 'val' and reading localStorage.length, may be 0. - const _localStorageStr = JSON.stringify(window.localStorage) - const _localStorage = _localStorageStr.length > 2 && JSON.parse(_localStorageStr) - const _sessionStorageStr = JSON.stringify(window.sessionStorage) - const _sessionStorage = _sessionStorageStr.length > 2 && JSON.parse(JSON.stringify(window.sessionStorage)) - - const value = {} as any - - if (_localStorage) { - value.localStorage = _localStorage - } - - if (_sessionStorage) { - value.sessionStorage = _sessionStorage - } - - return value -} - -const setPostMessageLocalStorage = async (specWindow, originOptions) => { - const origins = originOptions.map((v) => v.origin) as string[] - - const iframes: JQuery[] = [] - - const $iframeContainer = $(`
`).appendTo($('body', specWindow.document)) - - // if we're on an https domain, there is no way for the secure context to access insecure origins from iframes - // since there is no way for the app to access localStorage on insecure contexts, we don't have to clear any localStorage on http domains. - if (isSecureContext(specWindow.location.href)) { - _.remove(origins, (v) => !isSecureContext(v)) - } - - if (!origins.length) return [] - - _.each(origins, (u) => { - const $iframe = $(``) - - $iframe.appendTo($iframeContainer) - iframes.push($iframe) - }) - - let onPostMessage - - const successOrigins = [] as string[] - - return new Bluebird((resolve) => { - onPostMessage = (event) => { - const data = event.data - - if (data.type === 'set:storage:load') { - if (!event.source) { - throw new Error('failed to get localStorage') - } - - const opts = _.find(originOptions, { origin: event.origin })! - - event.source.postMessage({ type: 'set:storage:data', data: opts }, '*') - } else if (data.type === 'set:storage:complete') { - successOrigins.push(event.origin) - if (successOrigins.length === origins.length) { - resolve() - } - } - } - - specWindow.addEventListener('message', onPostMessage) - }) - // timeout just in case something goes wrong and the iframe never loads in - .timeout(2000) - .finally(() => { - specWindow.removeEventListener('message', onPostMessage) - $iframeContainer.remove() - }) - .catch(() => { - Cypress.log({ - name: 'warning', - message: `failed to access session localStorage data on origin(s): ${_.xor(origins, successOrigins).join(', ')}`, - }) - }) -} - -const getConsoleProps = (sessState: SessionData) => { - const sessionDetails = getSessionDetailsForTable(sessState) - - const tables = _.flatMap(sessionDetails, (val, domain) => { - const cookiesTable = () => { - return { - name: `🍪 Cookies - ${domain} (${val.cookies.length})`, - data: val.cookies, - } - } - - const localStorageTable = () => { - return { - name: `📁 Storage - ${domain} (${_.keys(val.localStorage.value).length})`, - data: _.map(val.localStorage.value, (value, key) => { - return { - key, - value, - } - }), - } - } - - return [ - val.cookies && cookiesTable, - val.localStorage && localStorageTable, - ] - }) - - return { - id: sessState.id, - table: _.compact(tables), - } -} - -const getPostMessageLocalStorage = (specWindow, origins): Promise => { - const results = [] as any[] - const iframes: JQuery[] = [] - let onPostMessage - const successOrigins = [] as string[] - - const $iframeContainer = $(`
`).appendTo($('body', specWindow.document)) - - _.each(origins, (u) => { - const $iframe = $(``) - - $iframe.appendTo($iframeContainer) - iframes.push($iframe) - }) - - return new Bluebird((resolve) => { - // when the cross-domain iframe for each domain is loaded - // we can only communicate through postmessage - onPostMessage = ((event) => { - const data = event.data - - if (data.type !== 'localStorage') return - - const value = data.value - - results.push([event.origin, value]) - - successOrigins.push(event.origin) - if (successOrigins.length === origins.length) { - resolve(results) - } - }) - - specWindow.addEventListener('message', onPostMessage) - }) - // timeout just in case something goes wrong and the iframe never loads in - .timeout(2000) - .finally(() => { - specWindow.removeEventListener('message', onPostMessage) - $iframeContainer.remove() - }) - .catch((err) => { - Cypress.log({ - name: 'warning', - message: `failed to access session localStorage data on origin(s): ${_.xor(origins, successOrigins).join(', ')}`, - }) - - return [] - }) -} - export default function (Commands, Cypress, cy) { const { Promise } = Cypress @@ -867,9 +686,3 @@ export default function (Commands, Cypress, cy) { Cypress.session = sessions } - -function navigateAboutBlank (session = true) { - Cypress.action('cy:url:changed', '') - - return Cypress.action('cy:visit:blank', { type: session ? 'session' : 'session-lifecycle' }) as unknown as Promise -} diff --git a/packages/driver/src/cy/commands/sessions/utils.ts b/packages/driver/src/cy/commands/sessions/utils.ts new file mode 100644 index 000000000000..9f20ebea5021 --- /dev/null +++ b/packages/driver/src/cy/commands/sessions/utils.ts @@ -0,0 +1,208 @@ +import _ from 'lodash' +import $ from 'jquery' +import { $Location } from '../../../cypress/location' +import Bluebird from 'bluebird' + +type SessionData = Cypress.Commands.Session.SessionData + +const getSessionDetails = (sessState: SessionData) => { + return { + id: sessState.id, + data: _.merge( + _.mapValues(_.groupBy(sessState.cookies, 'domain'), (v) => ({ cookies: v.length })), + ..._.map(sessState.localStorage, (v) => ({ [$Location.create(v.origin).hostname]: { localStorage: Object.keys(v.value).length } })), + ) } +} + +const getSessionDetailsForTable = (sessState: SessionData) => { + return _.merge( + _.mapValues(_.groupBy(sessState.cookies, 'domain'), (v) => ({ cookies: v })), + ..._.map(sessState.localStorage, (v) => ({ [$Location.create(v.origin).hostname]: { localStorage: v } })), + ) +} + +const isSecureContext = (url: string) => url.startsWith('https:') + +const getCurrentOriginStorage = () => { + // localStorage.length property is not always accurate, we must stringify to check for entries + // for ex) try setting localStorage.key = 'val' and reading localStorage.length, may be 0. + const _localStorageStr = JSON.stringify(window.localStorage) + const _localStorage = _localStorageStr.length > 2 && JSON.parse(_localStorageStr) + const _sessionStorageStr = JSON.stringify(window.sessionStorage) + const _sessionStorage = _sessionStorageStr.length > 2 && JSON.parse(JSON.stringify(window.sessionStorage)) + + const value = {} as any + + if (_localStorage) { + value.localStorage = _localStorage + } + + if (_sessionStorage) { + value.sessionStorage = _sessionStorage + } + + return value +} + +const setPostMessageLocalStorage = async (specWindow, originOptions) => { + const origins = originOptions.map((v) => v.origin) as string[] + + const iframes: JQuery[] = [] + + const $iframeContainer = $(`
`).appendTo($('body', specWindow.document)) + + // if we're on an https domain, there is no way for the secure context to access insecure origins from iframes + // since there is no way for the app to access localStorage on insecure contexts, we don't have to clear any localStorage on http domains. + if (isSecureContext(specWindow.location.href)) { + _.remove(origins, (v) => !isSecureContext(v)) + } + + if (!origins.length) return [] + + _.each(origins, (u) => { + const $iframe = $(``) + + $iframe.appendTo($iframeContainer) + iframes.push($iframe) + }) + + let onPostMessage + + const successOrigins = [] as string[] + + return new Bluebird((resolve) => { + onPostMessage = (event) => { + const data = event.data + + if (data.type === 'set:storage:load') { + if (!event.source) { + throw new Error('failed to get localStorage') + } + + const opts = _.find(originOptions, { origin: event.origin })! + + event.source.postMessage({ type: 'set:storage:data', data: opts }, '*') + } else if (data.type === 'set:storage:complete') { + successOrigins.push(event.origin) + if (successOrigins.length === origins.length) { + resolve() + } + } + } + + specWindow.addEventListener('message', onPostMessage) + }) + // timeout just in case something goes wrong and the iframe never loads in + .timeout(2000) + .finally(() => { + specWindow.removeEventListener('message', onPostMessage) + $iframeContainer.remove() + }) + .catch(() => { + Cypress.log({ + name: 'warning', + message: `failed to access session localStorage data on origin(s): ${_.xor(origins, successOrigins).join(', ')}`, + }) + }) +} + +const getConsoleProps = (sessState: SessionData) => { + const sessionDetails = getSessionDetailsForTable(sessState) + + const tables = _.flatMap(sessionDetails, (val, domain) => { + const cookiesTable = () => { + return { + name: `🍪 Cookies - ${domain} (${val.cookies.length})`, + data: val.cookies, + } + } + + const localStorageTable = () => { + return { + name: `📁 Storage - ${domain} (${_.keys(val.localStorage.value).length})`, + data: _.map(val.localStorage.value, (value, key) => { + return { + key, + value, + } + }), + } + } + + return [ + val.cookies && cookiesTable, + val.localStorage && localStorageTable, + ] + }) + + return { + id: sessState.id, + table: _.compact(tables), + } +} + +const getPostMessageLocalStorage = (specWindow, origins): Promise => { + const results = [] as any[] + const iframes: JQuery[] = [] + let onPostMessage + const successOrigins = [] as string[] + + const $iframeContainer = $(`
`).appendTo($('body', specWindow.document)) + + _.each(origins, (u) => { + const $iframe = $(``) + + $iframe.appendTo($iframeContainer) + iframes.push($iframe) + }) + + return new Bluebird((resolve) => { + // when the cross-domain iframe for each domain is loaded + // we can only communicate through postmessage + onPostMessage = ((event) => { + const data = event.data + + if (data.type !== 'localStorage') return + + const value = data.value + + results.push([event.origin, value]) + + successOrigins.push(event.origin) + if (successOrigins.length === origins.length) { + resolve(results) + } + }) + + specWindow.addEventListener('message', onPostMessage) + }) + // timeout just in case something goes wrong and the iframe never loads in + .timeout(2000) + .finally(() => { + specWindow.removeEventListener('message', onPostMessage) + $iframeContainer.remove() + }) + .catch((err) => { + Cypress.log({ + name: 'warning', + message: `failed to access session localStorage data on origin(s): ${_.xor(origins, successOrigins).join(', ')}`, + }) + + return [] + }) +} + +function navigateAboutBlank (session: boolean = true) { + Cypress.action('cy:url:changed', '') + + return Cypress.action('cy:visit:blank', { type: session ? 'session' : 'session-lifecycle' }) as unknown as Promise +} + +export { + getSessionDetails, + getCurrentOriginStorage, + setPostMessageLocalStorage, + getConsoleProps, + getPostMessageLocalStorage, + navigateAboutBlank, +} From 68173be4aa3a9d6c64cc447aa68d8f374bc3c066 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Apr 2022 12:39:48 +1000 Subject: [PATCH 09/16] chore: bump minimist from 1.2.5 to 1.2.6 (#21134) Co-authored-by: Lachlan Miller --- .../visual-testing-with-applitools/yarn.lock | 161 ++++++++---------- 1 file changed, 74 insertions(+), 87 deletions(-) diff --git a/npm/react/examples/visual-testing-with-applitools/yarn.lock b/npm/react/examples/visual-testing-with-applitools/yarn.lock index 118dc77203bf..806deba572e6 100644 --- a/npm/react/examples/visual-testing-with-applitools/yarn.lock +++ b/npm/react/examples/visual-testing-with-applitools/yarn.lock @@ -175,40 +175,6 @@ "@cypress/react@file:../../dist": version "0.0.0" -"@oozcitak/dom@1.15.8": - version "1.15.8" - resolved "https://registry.yarnpkg.com/@oozcitak/dom/-/dom-1.15.8.tgz#0c0c7bb54cfdaadc07fd637913e706101721d15d" - integrity sha512-MoOnLBNsF+ok0HjpAvxYxR4piUhRDCEWK0ot3upwOOHYudJd30j6M+LNcE8RKpwfnclAX9T66nXXzkytd29XSw== - dependencies: - "@oozcitak/infra" "1.0.8" - "@oozcitak/url" "1.0.4" - "@oozcitak/util" "8.3.8" - -"@oozcitak/infra@1.0.8": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@oozcitak/infra/-/infra-1.0.8.tgz#b0b089421f7d0f6878687608301fbaba837a7d17" - integrity sha512-JRAUc9VR6IGHOL7OGF+yrvs0LO8SlqGnPAMqyzOuFZPSZSXI7Xf2O9+awQPSMXgIWGtgUf/dA6Hs6X6ySEaWTg== - dependencies: - "@oozcitak/util" "8.3.8" - -"@oozcitak/url@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@oozcitak/url/-/url-1.0.4.tgz#ca8b1c876319cf5a648dfa1123600a6aa5cda6ba" - integrity sha512-kDcD8y+y3FCSOvnBI6HJgl00viO/nGbQoCINmQ0h98OhnGITrWR3bOGfwYCthgcrV8AnTJz8MzslTQbC3SOAmw== - dependencies: - "@oozcitak/infra" "1.0.8" - "@oozcitak/util" "8.3.8" - -"@oozcitak/util@8.3.8": - version "8.3.8" - resolved "https://registry.yarnpkg.com/@oozcitak/util/-/util-8.3.8.tgz#10f65fe1891fd8cde4957360835e78fd1936bfdd" - integrity sha512-T8TbSnGsxo6TDBJx/Sgv/BlVJL3tshxZP7Aq5R1mSnM5OcHY2dQaxLMu2+E8u3gN0MLOzdjurqN4ZRVuzQycOQ== - -"@types/node@14.6.2": - version "14.6.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.6.2.tgz#264b44c5a28dfa80198fc2f7b6d3c8a054b9491f" - integrity sha512-onlIwbaeqvZyniGPfdw/TEhKIh79pz66L1q06WUQqJLnAb6wbjvOtepLYTGHTqzdXgBYIE3ZdmqHDGsRsbBz7A== - "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -269,10 +235,10 @@ ajv@^6.12.3: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-styles@^3.2.1: version "3.2.1" @@ -288,13 +254,6 @@ ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - array-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" @@ -399,6 +358,11 @@ chalk@^2.0.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -476,6 +440,11 @@ cosmiconfig@^6.0.0: path-type "^4.0.0" yaml "^1.7.2" +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= + css-tree@^1.0.0-alpha.39: version "1.0.0-alpha.39" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.39.tgz#2bff3ffe1bb3f776cf7eefd91ee5cba77a149eeb" @@ -501,14 +470,6 @@ cssstyle@^2.0.0: dependencies: cssom "~0.3.6" -cypress-circleci-reporter@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/cypress-circleci-reporter/-/cypress-circleci-reporter-0.2.0.tgz#a3e1571694f4e21649a6af4d508e68948d23622d" - integrity sha512-uhqcJwvtKJ7Bw3RHVBTqUH9GP2L6jq+qLp/+/Jh3/OSe5Af6H7RxIARhvawsvbPrg9lMWdW/jCezjeUcXrl9uA== - dependencies: - strip-ansi "^6.0.0" - xmlbuilder2 "^2.1.1" - dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -530,7 +491,7 @@ dateformat@^3.0.3: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debug@2.6.9: +debug@2.6.9, debug@^2.2.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -630,7 +591,7 @@ escodegen@^1.11.1: optionalDependencies: source-map "~0.6.1" -esprima@^4.0.0, esprima@^4.0.1: +esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -880,6 +841,11 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-buffer@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -895,14 +861,6 @@ js-tokens@^4.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@3.14.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -971,11 +929,25 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= +lodash@^4.17.15: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + lodash@^4.17.19: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== +md5@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + mdn-data@2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.6.tgz#852dc60fcaa5daa2e8cf6c9189c440ed3e042978" @@ -1013,10 +985,10 @@ mime@1.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@^1.2.5, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mkdirp@^0.5.1: version "0.5.5" @@ -1025,6 +997,32 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.5" +mkdirp@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mocha-junit-reporter@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-2.0.2.tgz#d521689b651dc52f52044739f8ffb368be415731" + integrity sha512-vYwWq5hh3v1lG0gdQCBxwNipBfvDiAM1PHroQRNp96+2l72e9wEUTw+mzoK+O0SudgfQ7WvTQZ9Nh3qkAYAjfg== + dependencies: + debug "^2.2.0" + md5 "^2.1.0" + mkdirp "~0.5.1" + strip-ansi "^6.0.1" + xml "^1.0.0" + +mocha-multi-reporters@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/mocha-multi-reporters/-/mocha-multi-reporters-1.5.1.tgz#c73486bed5519e1d59c9ce39ac7a9792600e5676" + integrity sha512-Yb4QJOaGLIcmB0VY7Wif5AjvLMUFAdV57D2TWEva1Y0kU/3LjKpeRVmlMIfuO1SVbauve459kgtIizADqxMWPg== + dependencies: + debug "^4.1.1" + lodash "^4.17.15" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -1297,11 +1295,6 @@ source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - sshpk@^1.7.0: version "1.16.1" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" @@ -1332,12 +1325,12 @@ stealthy-require@^1.1.1: resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^5.0.0" + ansi-regex "^5.0.1" supports-color@^5.3.0: version "5.5.0" @@ -1522,16 +1515,10 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== -xmlbuilder2@^2.1.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/xmlbuilder2/-/xmlbuilder2-2.4.0.tgz#fb6c5171bef1bcb984c88cfef5210e17b7b841cd" - integrity sha512-KrOVUGD65xTQ7ZA+GMQGdBSpe1Ufu5ylCQSYVk6QostySDkxPmAQ0WWIu7dR3JjLfVbF22RFQX7KyrZ6VTLcQg== - dependencies: - "@oozcitak/dom" "1.15.8" - "@oozcitak/infra" "1.0.8" - "@oozcitak/util" "8.3.8" - "@types/node" "14.6.2" - js-yaml "3.14.0" +xml@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= xmlchars@^2.1.1: version "2.2.0" From d7ce86541db67561a51bc20d165144e27b5b1423 Mon Sep 17 00:00:00 2001 From: Matt Schile Date: Wed, 20 Apr 2022 23:03:08 -0600 Subject: [PATCH 10/16] chore: (cross-origin) add support for redirecting back to primary (#21144) --- .../integration/commands/navigation_spec.js | 57 ++---- .../commands/multi_domain_navigation.spec.ts | 83 +++++++- packages/driver/src/cy/commands/navigation.ts | 61 +++--- packages/driver/src/cy/multi-domain/index.ts | 16 +- packages/driver/src/cypress/error_messages.ts | 24 ++- packages/driver/types/internal-types.d.ts | 3 +- .../proxy/lib/http/response-middleware.ts | 6 +- .../unit/http/response-middleware.spec.ts | 44 +---- packages/server/lib/experiments.ts | 2 +- packages/server/lib/remote_states.ts | 10 +- packages/server/lib/server-base.ts | 4 +- packages/server/lib/server-e2e.ts | 13 +- packages/server/lib/socket-base.ts | 6 +- .../test/integration/http_requests_spec.js | 2 +- .../server/test/integration/server_spec.js | 181 +++++++++++++----- .../server/test/unit/remote_states.spec.ts | 49 ++--- packages/server/test/unit/socket_spec.js | 21 +- .../runnable_execution_spec.ts.js | 8 +- 18 files changed, 371 insertions(+), 219 deletions(-) diff --git a/packages/driver/cypress/integration/commands/navigation_spec.js b/packages/driver/cypress/integration/commands/navigation_spec.js index b4bda839fbc1..b6b4f0155e3b 100644 --- a/packages/driver/cypress/integration/commands/navigation_spec.js +++ b/packages/driver/cypress/integration/commands/navigation_spec.js @@ -1414,10 +1414,10 @@ describe('src/cy/commands/navigation', () => { \`cy.visit()\` failed because you are attempting to visit a URL that is of a different origin.\n You likely forgot to use \`cy.origin()\`:\n \`cy.visit('http://localhost:3500/fixtures/generic.html')\` - \`\`\n + \`\`\n \`cy.origin('http://localhost:3501', () => {\` \` cy.visit('http://localhost:3501/fixtures/generic.html')\` - \` \` + \` \` \`})\`\n The new URL is considered a different origin because the following parts of the URL are different:\n > port\n @@ -1446,18 +1446,18 @@ describe('src/cy/commands/navigation', () => { \`cy.visit()\` failed because you are attempting to visit a URL that is of a different origin.\n You likely forgot to use \`cy.origin()\`:\n \`cy.visit('http://localhost:3500/fixtures/generic.html')\` - \`\`\n - \`cy.origin('https://localhost:3500', () => {\` - \` cy.visit('https://localhost:3500/fixtures/generic.html')\` - \` \` + \`\`\n + \`cy.origin('https://localhost:3502', () => {\` + \` cy.visit('https://localhost:3502/fixtures/generic.html')\` + \` \` \`})\`\n The new URL is considered a different origin because the following parts of the URL are different:\n - > protocol\n + > protocol, port\n You may only \`cy.visit()\` same-origin URLs within a single test.\n The previous URL you visited was:\n > 'http://localhost:3500'\n You're attempting to visit this URL:\n - > 'https://localhost:3500'`) + > 'https://localhost:3502'`) expect(err.docsUrl).to.eq('https://on.cypress.io/cannot-visit-different-origin-domain') assertLogLength(this.logs, 2) @@ -1467,7 +1467,7 @@ describe('src/cy/commands/navigation', () => { }) cy.visit('http://localhost:3500/fixtures/generic.html') - cy.visit('https://localhost:3500/fixtures/generic.html') + cy.visit('https://localhost:3502/fixtures/generic.html') }) it('throws when attempting to visit a 2nd domain on different superdomain', function (done) { @@ -1478,10 +1478,10 @@ describe('src/cy/commands/navigation', () => { \`cy.visit()\` failed because you are attempting to visit a URL that is of a different origin.\n You likely forgot to use \`cy.origin()\`:\n \`cy.visit('http://localhost:3500/fixtures/generic.html')\` - \`\`\n - \`cy.origin('http://google.com:3500', () => {\` - \` cy.visit('http://google.com:3500/fixtures/generic.html')\` - \` \` + \`\`\n + \`cy.origin('http://foobar.com:3500', () => {\` + \` cy.visit('http://www.foobar.com:3500/fixtures/generic.html')\` + \` \` \`})\`\n The new URL is considered a different origin because the following parts of the URL are different:\n > superdomain\n @@ -1489,7 +1489,7 @@ describe('src/cy/commands/navigation', () => { The previous URL you visited was:\n > 'http://localhost:3500'\n You're attempting to visit this URL:\n - > 'http://google.com:3500'`) + > 'http://www.foobar.com:3500'`) expect(err.docsUrl).to.eq('https://on.cypress.io/cannot-visit-different-origin-domain') assertLogLength(this.logs, 2) @@ -1499,7 +1499,7 @@ describe('src/cy/commands/navigation', () => { }) cy.visit('http://localhost:3500/fixtures/generic.html') - cy.visit('http://google.com:3500/fixtures/generic.html') + cy.visit('http://www.foobar.com:3500/fixtures/generic.html') }) it('throws attempting to visit 2 unique ip addresses', function (done) { @@ -1510,10 +1510,10 @@ describe('src/cy/commands/navigation', () => { \`cy.visit()\` failed because you are attempting to visit a URL that is of a different origin.\n You likely forgot to use \`cy.origin()\`:\n \`cy.visit('http://127.0.0.1:3500/fixtures/generic.html')\` - \`\`\n - \`cy.origin('http://126.0.0.1:3500', () => {\` - \` cy.visit('http://126.0.0.1:3500/fixtures/generic.html')\` - \` \` + \`\`\n + \`cy.origin('http://0.0.0.0:3500', () => {\` + \` cy.visit('http://0.0.0.0:3500/fixtures/generic.html')\` + \` \` \`})\`\n The new URL is considered a different origin because the following parts of the URL are different:\n > superdomain\n @@ -1521,7 +1521,7 @@ describe('src/cy/commands/navigation', () => { The previous URL you visited was:\n > 'http://127.0.0.1:3500'\n You're attempting to visit this URL:\n - > 'http://126.0.0.1:3500'`) + > 'http://0.0.0.0:3500'`) expect(err.docsUrl).to.eq('https://on.cypress.io/cannot-visit-different-origin-domain') assertLogLength(this.logs, 2) @@ -1532,22 +1532,7 @@ describe('src/cy/commands/navigation', () => { cy .visit('http://127.0.0.1:3500/fixtures/generic.html') - .visit('http://126.0.0.1:3500/fixtures/generic.html') - }) - - it('does not call resolve:url when throws attempting to visit a 2nd domain', (done) => { - const backend = cy.spy(Cypress, 'backend') - - cy.on('fail', (err) => { - expect(backend).to.be.calledWithMatch('resolve:url', 'http://localhost:3500/fixtures/generic.html') - expect(backend).not.to.be.calledWithMatch('resolve:url', 'http://google.com:3500/fixtures/generic.html') - - done() - }) - - cy - .visit('http://localhost:3500/fixtures/generic.html') - .visit('http://google.com:3500/fixtures/generic.html') + .visit('http://0.0.0.0:3500/fixtures/generic.html') }) it('displays loading_network_failed when _resolveUrl throws', function (done) { diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_navigation.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_navigation.spec.ts index febb6e19e1af..e6bc322cdb45 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_navigation.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_navigation.spec.ts @@ -178,11 +178,11 @@ context('cy.origin navigation', () => { You likely forgot to use \`cy.origin()\`:\n \`cy.origin('http://foobar.com:3500', () => {\` \` cy.visit('http://www.foobar.com:3500/fixtures/multi-domain-secondary.html')\` - \` \` + \` \` \`})\`\n \`cy.origin('http://idp.com:3500', () => {\` \` cy.visit('http://www.idp.com:3500/fixtures/dom.html')\` - \` \` + \` \` \`})\`\n The new URL is considered a different origin because the following parts of the URL are different:\n > superdomain\n @@ -211,10 +211,10 @@ context('cy.origin navigation', () => { \`cy.visit()\` failed because you are attempting to visit a URL that is of a different origin.\n In order to visit a different origin, you can enable the \`experimentalSessionAndOrigin\` flag and use \`cy.origin()\`:\n \`cy.visit('http://localhost:3500/fixtures/multi-domain.html')\` - \`\`\n + \`\`\n \`cy.origin('http://foobar.com:3500', () => {\` \` cy.visit('http://www.foobar.com:3500/fixtures/dom.html')\` - \` \` + \` \` \`})\`\n The new URL is considered a different origin because the following parts of the URL are different:\n > superdomain\n @@ -312,7 +312,7 @@ context('cy.origin navigation', () => { }) }) - it('supports visit redirects', () => { + it('supports redirecting from primary to secondary in cy.origin', () => { cy.visit('/fixtures/multi-domain.html') cy.origin('http://www.foobar.com:3500', () => { @@ -321,6 +321,79 @@ context('cy.origin navigation', () => { }) }) + it('supports redirecting from secondary to primary outside of cy.origin', () => { + cy.visit('/fixtures/multi-domain.html') + cy.visit('http://www.foobar.com:3500/redirect?href=http://localhost:3500/fixtures/generic.html') + }) + + it('errors when trying to redirect from secondary to primary in cy.origin', (done) => { + cy.on('fail', (e) => { + expect(e.message).to.equal(stripIndent` + \`cy.visit()\` failed because you are attempting to visit a URL from a previous origin inside of \`cy.origin()\`.\n + Instead of placing the \`cy.visit()\` inside of \`cy.origin()\`, the \`cy.visit()\` should be placed outside of the \`cy.origin()\` block.\n + \`\`\n + \`cy.origin('http://foobar.com:3500', () => {\` + \` \` + \`})\`\n + \`cy.visit('http://www.foobar.com:3500/redirect?href=http://localhost:3500/fixtures/generic.html')\``) + + done() + }) + + cy.visit('http://localhost:3500/fixtures/multi-domain.html') + + cy.origin('http://www.foobar.com:3500', () => { + cy.visit('/redirect?href=http://localhost:3500/fixtures/generic.html') + }) + }) + + it('errors when trying to visit primary in cy.origin', (done) => { + cy.on('fail', (e) => { + expect(e.message).to.equal(stripIndent` + \`cy.visit()\` failed because you are attempting to visit a URL from a previous origin inside of \`cy.origin()\`.\n + Instead of placing the \`cy.visit()\` inside of \`cy.origin()\`, the \`cy.visit()\` should be placed outside of the \`cy.origin()\` block.\n + \`\`\n + \`cy.origin('http://foobar.com:3500', () => {\` + \` \` + \`})\`\n + \`cy.visit('http://localhost:3500/fixtures/generic.html')\``) + + done() + }) + + cy.visit('http://localhost:3500/fixtures/multi-domain.html') + + cy.origin('http://www.foobar.com:3500', () => { + cy.visit('http://localhost:3500/fixtures/generic.html') + }) + }) + + it('errors when trying to redirect from primary to secondary outside of cy.origin', (done) => { + cy.on('fail', (e) => { + expect(e.message).to.equal(stripIndent`\ + \`cy.visit()\` failed because you are attempting to visit a URL that is of a different origin.\n + You likely forgot to use \`cy.origin()\`:\n + \`cy.visit('http://localhost:3500/fixtures/multi-domain.html')\` + \`\`\n + \`cy.origin('http://foobar.com:3500', () => {\` + \` cy.visit('http://localhost:3500/redirect?href=http://www.foobar.com:3500/fixtures/generic.html')\` + \` \` + \`})\`\n + The new URL is considered a different origin because the following parts of the URL are different:\n + > superdomain\n + You may only \`cy.visit()\` same-origin URLs within a single test.\n + The previous URL you visited was:\n + > 'http://localhost:3500'\n + You're attempting to visit this URL:\n + > 'http://www.foobar.com:3500'`) + + done() + }) + + cy.visit('/fixtures/multi-domain.html') + cy.visit('http://localhost:3500/redirect?href=http://www.foobar.com:3500/fixtures/generic.html') + }) + it('supports auth options and adding auth to subsequent requests', () => { cy.origin('http://foobar.com:3500', () => { cy.visit('http://www.foobar.com:3500/basic_auth', { diff --git a/packages/driver/src/cy/commands/navigation.ts b/packages/driver/src/cy/commands/navigation.ts index 8e6f2d4a64ef..99c64ea9f369 100644 --- a/packages/driver/src/cy/commands/navigation.ts +++ b/packages/driver/src/cy/commands/navigation.ts @@ -90,7 +90,7 @@ const timedOutWaitingForPageLoad = (ms, log) => { } } -const cannotVisitDifferentOrigin = ({ remote, existing, previousUrlVisited, log, isCrossOriginSpecBridge = false }) => { +const cannotVisitDifferentOrigin = ({ remote, existing, originalUrl, previousUrlVisited, log, isCrossOriginSpecBridge = false }) => { const differences: string[] = [] if (remote.protocol !== existing.protocol) { @@ -111,6 +111,7 @@ const cannotVisitDifferentOrigin = ({ remote, existing, previousUrlVisited, log, differences: differences.join(', '), previousUrl: previousUrlVisited, attemptedUrl: remote, + originalUrl, isCrossOriginSpecBridge, experimentalSessionAndOrigin: Cypress.config('experimentalSessionAndOrigin'), }, @@ -122,6 +123,22 @@ const cannotVisitDifferentOrigin = ({ remote, existing, previousUrlVisited, log, $errUtils.throwErrByPath('visit.cannot_visit_different_origin', errOpts) } +const cannotVisitPreviousOrigin = ({ remote, originalUrl, previousUrlVisited, log }) => { + const errOpts = { + onFail: log, + args: { + attemptedUrl: remote, + previousUrl: previousUrlVisited, + originalUrl, + }, + errProps: { + isCrossOrigin: true, + }, + } + + $errUtils.throwErrByPath('origin.cannot_visit_previous_origin', errOpts) +} + const specifyFileByRelativePath = (url, log) => { $errUtils.throwErrByPath('visit.specify_file_by_relative_path', { onFail: log, @@ -494,6 +511,7 @@ const normalizeOptions = (options) => { .extend({ timeout: options.responseTimeout, isCrossOrigin: Cypress.isCrossOriginSpecBridge, + hasAlreadyVisitedUrl: options.hasAlreadyVisitedUrl, }) .value() } @@ -833,6 +851,8 @@ export default (Commands, Cypress, cy, state, config) => { onLoad () {}, }) + options.hasAlreadyVisitedUrl = !!previousUrlVisited + if (!_.isUndefined(options.qs) && !_.isObject(options.qs)) { $errUtils.throwErrByPath('visit.invalid_qs', { args: { qs: String(options.qs) } }) } @@ -1026,17 +1046,6 @@ export default (Commands, Cypress, cy, state, config) => { const existingHash = remote.hash || '' const existingAuth = remote.auth || '' - if (previousUrlVisited && (remote.originPolicy !== existing.originPolicy)) { - // if we've already visited a new superDomain - // then die else we'd be in a terrible endless loop - // we also need to disable retries to prevent the endless loop - $utils.getTestFromRunnable(state('runnable'))._retries = 0 - - const params = { remote, existing, previousUrlVisited, log: options._log } - - return cannotVisitDifferentOrigin(params) - } - // in a cross origin spec bridge, the window may not have been set yet if nothing has been loaded in the secondary origin, // it's also possible for a new test to start and for a cross-origin failure to occur if the win is set but // the AUT hasn't yet navigated to the secondary origin @@ -1082,7 +1091,7 @@ export default (Commands, Cypress, cy, state, config) => { return requestUrl(url, options) .then((resp: any = {}) => { - let { url, originalUrl, cookies, redirects, filePath } = resp + let { url, originalUrl, cookies, redirects, filePath, isPrimaryOrigin } = resp // reapply the existing hash url += existingHash @@ -1114,7 +1123,6 @@ export default (Commands, Cypress, cy, state, config) => { // if the origin currently matches // then go ahead and change the iframe's src - // and we're good to go if (remote.originPolicy === existing.originPolicy) { previousUrlVisited = remote @@ -1126,22 +1134,25 @@ export default (Commands, Cypress, cy, state, config) => { }) } - // if we are in a cross origin spec bridge and the origin policies weren't the same, - // we need to throw an error since the user tried to visit a new - // origin which isn't allowed within a cy.origin block - if (Cypress.isCrossOriginSpecBridge && win) { - const existingAutOrigin = $Location.create(win.location.href) - const params = { remote, existing, previousUrlVisited: existingAutOrigin, log: options._log, isCrossOriginSpecBridge: true } + // if we've already cy.visit'ed in the test and we are visiting a new origin, + // throw an error, else we'd be in a endless loop, + // we also need to disable retries to prevent the endless loop + if (previousUrlVisited) { + $utils.getTestFromRunnable(state('runnable'))._retries = 0 + + const params = { remote, existing, originalUrl, previousUrlVisited, log: options._log } return cannotVisitDifferentOrigin(params) } - // if we've already visited a new origin - // then die else we'd be in a terrible endless loop - if (previousUrlVisited) { - const params = { remote, existing, previousUrlVisited, log: options._log } + // if we are in a cross origin spec bridge and the origin policies weren't the same, + // we need to throw an error since the user tried to visit a new + // origin which isn't allowed within a cy.origin block + if (Cypress.isCrossOriginSpecBridge) { + const existingAutOrigin = win ? $Location.create(win.location.href) : $Location.create(Cypress.state('currentActiveOriginPolicy')) + const params = { remote, existing, originalUrl, previousUrlVisited: existingAutOrigin, log: options._log, isCrossOriginSpecBridge: true, isPrimaryOrigin } - return cannotVisitDifferentOrigin(params) + return isPrimaryOrigin ? cannotVisitPreviousOrigin(params) : cannotVisitDifferentOrigin(params) } // tell our backend we're changing origins diff --git a/packages/driver/src/cy/multi-domain/index.ts b/packages/driver/src/cy/multi-domain/index.ts index 44299336918b..70ce6fd5df35 100644 --- a/packages/driver/src/cy/multi-domain/index.ts +++ b/packages/driver/src/cy/multi-domain/index.ts @@ -43,11 +43,11 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, } // If we haven't seen a cy.origin and cleared the timeout within 300ms, - // go ahead and inform the server 'ready:for:origin' failed and to release the - // response. This typically happens during a redirect where the user does + // go ahead and inform the server to release the response. + // This typically happens during a redirect where the user does // not have a cy.origin for the intermediary origin. timeoutId = setTimeout(() => { - Cypress.backend('ready:for:origin', { failed: true }) + Cypress.backend('cross:origin:release:html') }, 300) }) @@ -94,7 +94,7 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, const validator = new Validator({ log, onFailure: () => { - Cypress.backend('ready:for:origin', { failed: true }) + Cypress.backend('cross:origin:release:html') }, }) @@ -163,7 +163,7 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, // lets the proxy know to allow the response for the secondary // origin html through, so the page will finish loading - Cypress.backend('ready:for:origin', { originPolicy: location.originPolicy }) + Cypress.backend('cross:origin:release:html') if (err) { if (err?.name === 'ReferenceError') { @@ -202,7 +202,7 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, } // fired once the spec bridge is set up and ready to receive messages - communicator.once('bridge:ready', (_data, specBridgeOriginPolicy) => { + communicator.once('bridge:ready', async (_data, specBridgeOriginPolicy) => { if (specBridgeOriginPolicy === originPolicy) { // now that the spec bridge is ready, instantiate Cypress with the current app config and environment variables for initial sync when creating the instance communicator.toSpecBridge(originPolicy, 'initialize:cypress', { @@ -210,6 +210,8 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, env: preprocessEnv(Cypress.env()), }) + await Cypress.backend('cross:origin:bridge:ready', { originPolicy }) + // once the secondary origin page loads, send along the // user-specified callback to run in that origin try { @@ -237,7 +239,7 @@ export function addCommands (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, }) } catch (err: any) { // Release the request if 'run:origin:fn' fails - Cypress.backend('ready:for:origin', { failed: true }) + Cypress.backend('cross:origin:release:html') const wrappedErr = $errUtils.errByPath('origin.run_origin_fn_errored', { error: err.message, diff --git a/packages/driver/src/cypress/error_messages.ts b/packages/driver/src/cypress/error_messages.ts index f7f41d972415..937a349e2a17 100644 --- a/packages/driver/src/cypress/error_messages.ts +++ b/packages/driver/src/cypress/error_messages.ts @@ -1237,6 +1237,22 @@ export default { docsUrl: 'https://on.cypress.io/session-api', }, }, + cannot_visit_previous_origin (args) { + return { + message: stripIndent`\ + ${cmd('visit')} failed because you are attempting to visit a URL from a previous origin inside of ${cmd('origin')}. + + Instead of placing the ${cmd('visit')} inside of ${cmd('origin')}, the ${cmd('visit')} should be placed outside of the ${cmd('origin')} block. + + \`\` + + \`cy.origin('${args.previousUrl.originPolicy}', () => {\` + \` \` + \`})\` + + \`cy.visit('${args.originalUrl}')\``, + } + }, }, proxy: { @@ -2105,15 +2121,15 @@ export default { ${args.isCrossOriginSpecBridge ? `\`cy.origin('${args.previousUrl.originPolicy}', () => {\` \` cy.visit('${args.previousUrl}')\` - \` \` + \` \` \`})\`` : `\`cy.visit('${args.previousUrl}')\` - \`\`` + \`\`` } \`cy.origin('${args.attemptedUrl.originPolicy}', () => {\` - \` cy.visit('${args.attemptedUrl}')\` - \` \` + \` cy.visit('${args.originalUrl}')\` + \` \` \`})\` The new URL is considered a different origin because the following parts of the URL are different: diff --git a/packages/driver/types/internal-types.d.ts b/packages/driver/types/internal-types.d.ts index 6f4697214b9d..82a0754ded3e 100644 --- a/packages/driver/types/internal-types.d.ts +++ b/packages/driver/types/internal-types.d.ts @@ -23,7 +23,8 @@ declare namespace Cypress { } interface Backend { - (task: 'ready:for:origin', args: { originPolicy?: string , failed?: boolean}): boolean + (task: 'cross:origin:release:html'): boolean + (task: 'cross:origin:bridge:ready', args: { originPolicy?: string }): boolean (task: 'cross:origin:finished', originPolicy: string): boolean } diff --git a/packages/proxy/lib/http/response-middleware.ts b/packages/proxy/lib/http/response-middleware.ts index 5768bc4dc3df..82697b51c37c 100644 --- a/packages/proxy/lib/http/response-middleware.ts +++ b/packages/proxy/lib/http/response-middleware.ts @@ -238,10 +238,10 @@ const MaybeDelayForCrossOrigin: ResponseMiddleware = function () { // delay the response if this is a cross-origin (and not returning to a previous origin) html request from the AUT iframe if (this.config.experimentalSessionAndOrigin && isCrossOrigin && !isPreviousOrigin && isAUTFrame && (isHTML || isRenderedHTML)) { - this.debug('is cross-origin, delay until ready:for:origin event') + this.debug('is cross-origin, delay until cross:origin:release:html event') - this.serverBus.once('ready:for:origin', ({ failed }) => { - this.debug(`received ready:for:origin${failed ? ' failed' : ''}, let the response proceed`) + this.serverBus.once('cross:origin:release:html', () => { + this.debug(`received cross:origin:release:html, let the response proceed`) this.next() }) diff --git a/packages/proxy/test/unit/http/response-middleware.spec.ts b/packages/proxy/test/unit/http/response-middleware.spec.ts index 5c9f215cb956..a3faa680f77c 100644 --- a/packages/proxy/test/unit/http/response-middleware.spec.ts +++ b/packages/proxy/test/unit/http/response-middleware.spec.ts @@ -196,7 +196,7 @@ describe('http/response-middleware', function () { }) }) - it('waits for server signal if req is not of a previous origin, letting it continue after receiving ready:for:origin', function () { + it('waits for server signal if req is not of a previous origin, letting it continue after receiving cross:origin:release:html', function () { prepareContext({ req: { isAUTFrame: true, @@ -217,12 +217,12 @@ describe('http/response-middleware', function () { expect(ctx.serverBus.emit).to.be.calledWith('cross:origin:delaying:html', { href: 'http://www.idp.com/test' }) - ctx.serverBus.once.withArgs('ready:for:origin').args[0][1]({ originPolicy: 'http://idp.com' }) + ctx.serverBus.once.withArgs('cross:origin:release:html').args[0][1]() return promise }) - it('waits for server signal if res is html, letting it continue after receiving ready:for:origin', function () { + it('waits for server signal if res is html, letting it continue after receiving cross:origin:release:html', function () { prepareContext({ incomingRes: { headers: { @@ -242,12 +242,12 @@ describe('http/response-middleware', function () { expect(ctx.serverBus.emit).to.be.calledWith('cross:origin:delaying:html', { href: 'http://www.foobar.com/test' }) - ctx.serverBus.once.withArgs('ready:for:origin').args[0][1]({ originPolicy: 'http://foobar.com' }) + ctx.serverBus.once.withArgs('cross:origin:release:html').args[0][1]() return promise }) - it('waits for server signal if incomingRes is rendered html, letting it continue after receiving ready:for:origin', function () { + it('waits for server signal if incomingRes is rendered html, letting it continue after receiving cross:origin:release:html', function () { prepareContext({ req: { headers: { @@ -268,33 +268,7 @@ describe('http/response-middleware', function () { expect(ctx.serverBus.emit).to.be.calledWith('cross:origin:delaying:html', { href: 'http://www.foobar.com/test' }) - ctx.serverBus.once.withArgs('ready:for:origin').args[0][1]({ originPolicy: 'http://foobar.com' }) - - return promise - }) - - it('waits for server signal, letting it continue after receiving ready:for:origin failed', function () { - prepareContext({ - req: { - isAUTFrame: true, - proxiedUrl: 'http://www.idp.com/test', - }, - incomingRes: { - headers: { - 'content-type': 'text/html', - }, - }, - secondaryOrigins: ['http://foobar.com', 'http://example.com'], - config: { - experimentalSessionAndOrigin: true, - }, - }) - - const promise = testMiddleware([MaybeDelayForCrossOrigin], ctx) - - expect(ctx.serverBus.emit).to.be.calledWith('cross:origin:delaying:html', { href: 'http://www.idp.com/test' }) - - ctx.serverBus.once.withArgs('ready:for:origin').args[0][1]({ failed: true }) + ctx.serverBus.once.withArgs('cross:origin:release:html').args[0][1]() return promise }) @@ -309,7 +283,7 @@ describe('http/response-middleware', function () { // set the secondary remote states remoteStates.addEventListeners(eventEmitter) props.secondaryOrigins?.forEach((originPolicy) => { - eventEmitter.emit('ready:for:origin', { originPolicy }) + eventEmitter.emit('cross:origin:bridge:ready', { originPolicy }) }) ctx = { @@ -592,7 +566,7 @@ describe('http/response-middleware', function () { // set the secondary remote states remoteStates.addEventListeners(eventEmitter) props.secondaryOrigins?.forEach((originPolicy) => { - eventEmitter.emit('ready:for:origin', { originPolicy }) + eventEmitter.emit('cross:origin:bridge:ready', { originPolicy }) }) ctx = { @@ -914,7 +888,7 @@ describe('http/response-middleware', function () { // set the secondary remote states remoteStates.addEventListeners(eventEmitter) props.secondaryOrigins?.forEach((originPolicy) => { - eventEmitter.emit('ready:for:origin', { originPolicy }) + eventEmitter.emit('cross:origin:bridge:ready', { originPolicy }) }) return { diff --git a/packages/server/lib/experiments.ts b/packages/server/lib/experiments.ts index b962cbdb8b2e..0a0e876c76f0 100644 --- a/packages/server/lib/experiments.ts +++ b/packages/server/lib/experiments.ts @@ -71,7 +71,7 @@ const _summaries: StringValues = { const _names: StringValues = { experimentalFetchPolyfill: 'Fetch Polyfill', experimentalInteractiveRunEvents: 'Interactive Mode Run Events', - experimentalSessionAndOrigin: 'Login Flows', + experimentalSessionAndOrigin: 'Cross-origin and Session', experimentalSourceRewriting: 'Improved Source Rewriting', experimentalStudio: 'Studio', } diff --git a/packages/server/lib/remote_states.ts b/packages/server/lib/remote_states.ts index 7049e78067c1..f9ceb3e6a056 100644 --- a/packages/server/lib/remote_states.ts +++ b/packages/server/lib/remote_states.ts @@ -139,14 +139,8 @@ export class RemoteStates { } addEventListeners (eventEmitter: EventEmitter) { - eventEmitter.on('ready:for:origin', ({ originPolicy, failed }) => { - if (failed) { - debug('received ready:for:origin failed, don\'t add origin to remote states') - - return - } - - debug(`received ready:for:origin, add origin ${originPolicy} to remote states`) + eventEmitter.on('cross:origin:bridge:ready', ({ originPolicy }) => { + debug(`received cross:origin:bridge:ready, add origin ${originPolicy} to remote states`) const existingOrigin = this.remoteStates.get(originPolicy) diff --git a/packages/server/lib/server-base.ts b/packages/server/lib/server-base.ts index cf87e986f852..edad746878e2 100644 --- a/packages/server/lib/server-base.ts +++ b/packages/server/lib/server-base.ts @@ -166,8 +166,8 @@ export abstract class ServerBase { setupCrossOriginRequestHandling () { this._eventBus.on('cross:origin:delaying:html', (request) => { - this.socket.localBus.once('ready:for:origin', (args) => { - this._eventBus.emit('ready:for:origin', args) + this.socket.localBus.once('cross:origin:release:html', () => { + this._eventBus.emit('cross:origin:release:html') }) this.socket.toDriver('cross:origin:delaying:html', request) diff --git a/packages/server/lib/server-e2e.ts b/packages/server/lib/server-e2e.ts index a87a8cc37210..8dadffa18768 100644 --- a/packages/server/lib/server-e2e.ts +++ b/packages/server/lib/server-e2e.ts @@ -291,11 +291,12 @@ export class ServerE2E extends ServerBase { details.totalTime = Date.now() - startTime - // TODO: think about moving this logic back into the - // frontend so that the driver can be in control of - // when the server should cache the request buffer - // and set the domain vs not - if (isOk && details.isHtml) { + // buffer the response and set the remote state if this is a successful html response that is for the same + // origin if the user has already visited an origin or if this is a request from within cy.origin + // TODO: think about moving this logic back into the frontend so that the driver can be in control + // of when to buffer and set the remote state + if (isOk && details.isHtml && + !((options.hasAlreadyVisitedUrl || options.isCrossOrigin) && !cors.urlOriginsMatch(previousRemoteState.origin, newUrl))) { // if we're not handling a local file set the remote state if (!handlingLocalFile) { this.remoteStates.set(newUrl as string, options) @@ -321,6 +322,8 @@ export class ServerE2E extends ServerBase { restorePreviousRemoteState(previousRemoteState, previousRemoteStateIsPrimary) } + details.isPrimaryOrigin = this.remoteStates.isPrimaryOrigin(newUrl!) + return resolve(details) }) diff --git a/packages/server/lib/socket-base.ts b/packages/server/lib/socket-base.ts index 5e5c563d2395..96a14a6b3a98 100644 --- a/packages/server/lib/socket-base.ts +++ b/packages/server/lib/socket-base.ts @@ -414,8 +414,10 @@ export class SocketBase { return } - case 'ready:for:origin': - return this.localBus.emit('ready:for:origin', args[0]) + case 'cross:origin:bridge:ready': + return this.localBus.emit('cross:origin:bridge:ready', args[0]) + case 'cross:origin:release:html': + return this.localBus.emit('cross:origin:release:html') case 'cross:origin:finished': return this.localBus.emit('cross:origin:finished', args[0]) default: diff --git a/packages/server/test/integration/http_requests_spec.js b/packages/server/test/integration/http_requests_spec.js index 047656c7f88e..d1ef6e02e7e3 100644 --- a/packages/server/test/integration/http_requests_spec.js +++ b/packages/server/test/integration/http_requests_spec.js @@ -3028,7 +3028,7 @@ describe('Routes', () => { }) this.server._eventBus.on('cross:origin:delaying:html', () => { - this.server._eventBus.emit('ready:for:origin', { originPolicy: 'http://foobar.com' }) + this.server._eventBus.emit('cross:origin:release:html') }) return this.rp({ diff --git a/packages/server/test/integration/server_spec.js b/packages/server/test/integration/server_spec.js index d51fc8537bf6..b6f9196349fc 100644 --- a/packages/server/test/integration/server_spec.js +++ b/packages/server/test/integration/server_spec.js @@ -145,6 +145,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://localhost:2000/index.html', @@ -176,6 +177,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: false, contentType: 'application/json', url: 'http://localhost:2000/assets/foo.json', @@ -196,6 +198,7 @@ describe('Server', () => { .then((obj = {}) => { expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://localhost:2000/index.html', @@ -213,6 +216,7 @@ describe('Server', () => { .then((obj = {}) => { expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://localhost:2000/index.html', @@ -244,6 +248,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://localhost:2000/sub/', @@ -276,6 +281,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: false, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://localhost:2000/does-not-exist', @@ -303,6 +309,7 @@ describe('Server', () => { .then((obj = {}) => { expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://localhost:2000/index.html', @@ -384,6 +391,7 @@ describe('Server', () => { }).then((obj) => { expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: `http://localhost:${this.httpPort}/${path}/100`, @@ -430,6 +438,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://getbootstrap.com/', @@ -464,6 +473,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: false, isHtml: false, contentType: 'application/json', url: 'http://getbootstrap.com/user.json', @@ -508,6 +518,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: undefined, url: 'http://example.com/', @@ -529,6 +540,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: false, isHtml: false, contentType: undefined, url: 'http://example.com/', @@ -562,6 +574,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://espn.go.com/', @@ -625,6 +638,7 @@ describe('Server', () => { .then((obj = {}) => { expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://espn.go.com/', @@ -644,6 +658,7 @@ describe('Server', () => { .then((obj = {}) => { expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://espn.go.com/', @@ -698,6 +713,7 @@ describe('Server', () => { .then((obj = {}) => { expectToEqDetails(obj, { isOkStatusCode: false, + isPrimaryOrigin: false, isHtml: false, contentType: undefined, url: 'http://espn.com/', @@ -712,6 +728,7 @@ describe('Server', () => { .then((obj = {}) => { expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://espn.go.com/', @@ -747,6 +764,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: false, + isPrimaryOrigin: false, isHtml: true, contentType: 'text/html', url: 'http://mlb.mlb.com/', @@ -780,6 +798,7 @@ describe('Server', () => { .then((obj = {}) => { expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://getbootstrap.com/', @@ -820,6 +839,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://google.com/foo', @@ -876,6 +896,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://google.com/index', @@ -907,7 +928,7 @@ describe('Server', () => { }) context('cross-origin', () => { - it('adds a secondary remote state', function () { + it('adds a remote state and buffers the response when the request is from within cy.origin and the origins match', function () { nock('http://www.cypress.io/') .get('/') .reply(200, 'content', { @@ -923,7 +944,7 @@ describe('Server', () => { fileServer: this.fileServer, }) - this.server.socket.localBus.emit('ready:for:origin', { originPolicy: 'http://cypress.io' }) + this.server.socket.localBus.emit('cross:origin:bridge:ready', { originPolicy: 'http://cypress.io' }) expect(this.server.remoteStates.current()).to.deep.eq({ auth: undefined, @@ -944,6 +965,7 @@ describe('Server', () => { .then((obj = {}) => { expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: false, isHtml: true, contentType: 'text/html', url: 'http://www.cypress.io/', @@ -990,34 +1012,54 @@ describe('Server', () => { }) }) - it('doesn\'t override existing remote state on ready:for:origin', function () { - nock('http://www.cypress.io/') + it('adds a remote state and buffers the response when a url has already been visited and the origins match', function () { + nock('http://localhost:3500/') .get('/') .reply(200, 'content', { 'Content-Type': 'text/html', }) - this.server.socket.localBus.emit('ready:for:origin', { originPolicy: 'http://cypress.io' }) + // this will be the current origin + this.server.remoteStates.set('http://localhost:3500/') + + return this.server._onResolveUrl('http://localhost:3500/', {}, this.automationRequest, { hasAlreadyVisitedUrl: true }) + .then((obj = {}) => { + // Verify the cross origin request was buffered + const buffer = this.buffers.take('http://localhost:3500/') + + expect(buffer).to.not.be.empty - return this.server._onResolveUrl('http://www.cypress.io/', {}, this.automationRequest, { isCrossOrigin: true }) - .then(() => { // Verify the secondary remote state is returned expect(this.server.remoteStates.current()).to.deep.eq({ auth: undefined, props: { - domain: 'cypress', - port: '80', - tld: 'io', + domain: '', + port: '3500', + tld: 'localhost', }, - origin: 'http://www.cypress.io', + origin: 'http://localhost:3500', strategy: 'http', - domainName: 'cypress.io', + domainName: 'localhost', fileServer: null, }) + }) + }) + + it('doesn\'t set a remote state or buffer the response when a url has already been visited and the origins don\'t match', function () { + nock('http://localhost:3500/') + .get('/') + .reply(200, 'content', { + 'Content-Type': 'text/html', + }) - this.server.socket.localBus.emit('ready:for:origin', { originPolicy: 'http://cypress.io' }) + this.server.remoteStates.set('http://localhost:3500/') - // Verify the existing secondary remote state is not overridden + // this will be the current origin + this.server.socket.localBus.emit('cross:origin:bridge:ready', { originPolicy: 'http://cypress.io' }) + + return this.server._onResolveUrl('http://localhost:3500/', {}, this.automationRequest, { hasAlreadyVisitedUrl: true }) + .then(() => { + // Verify the remote state was not updated expect(this.server.remoteStates.current()).to.deep.eq({ auth: undefined, props: { @@ -1025,65 +1067,100 @@ describe('Server', () => { port: '80', tld: 'io', }, - origin: 'http://www.cypress.io', + origin: 'http://cypress.io', strategy: 'http', domainName: 'cypress.io', fileServer: null, }) - }) - }) - context('#get()', () => { - it('returns undefined for not found remote state', function () { - this.server.remoteStates.set('http://www.cypress.io/') + // Verify the cross origin request was not buffered + const buffer = this.buffers.take('http://localhost:3500/') - expect(this.server.remoteStates.get('http://notfound.com/')).to.be.undefined + expect(buffer).to.be.empty }) + }) - it('returns primary remote state', function () { - this.server.remoteStates.set('http://www.cypress.io/', { isCrossOrigin: true }) - - expect(this.server.remoteStates.get('http://localhost:2000')).to.deep.eq({ - auth: undefined, - props: null, - origin: 'http://localhost:2000', - strategy: 'file', - domainName: 'localhost', - fileServer: this.fileServer, - }) + it('doesn\'t set a remote state or buffer the response when the request is from within cy.origin and the origins don\'t match', function () { + nock('http://localhost:3500/') + .get('/') + .reply(200, 'content', { + 'Content-Type': 'text/html', }) - it('returns secondary remote state', function () { - this.server.remoteStates.set('http://www.cypress.io/', { isCrossOrigin: true }) + this.server.remoteStates.set('http://localhost:3500/') - expect(this.server.remoteStates.get('http://cypress.io')).to.deep.eq({ + // this will be the current origin + this.server.socket.localBus.emit('cross:origin:bridge:ready', { originPolicy: 'http://cypress.io' }) + + return this.server._onResolveUrl('http://localhost:3500/', {}, this.automationRequest, { isCrossOrigin: true }) + .then(() => { + // Verify the remote state was not updated + expect(this.server.remoteStates.current()).to.deep.eq({ auth: undefined, props: { domain: 'cypress', port: '80', tld: 'io', }, - origin: 'http://www.cypress.io', + origin: 'http://cypress.io', strategy: 'http', domainName: 'cypress.io', fileServer: null, }) + + // Verify the cross origin request was not buffered + const buffer = this.buffers.take('http://localhost:3500/') + + expect(buffer).to.be.empty }) }) - context('#reset()', () => { - it('returns undefined for not found remote state', function () { - this.server.socket.localBus.emit('ready:for:origin', { originPolicy: 'http://cypress.io' }) + it('doesn\'t override existing remote state on cross:origin:bridge:ready', function () { + nock('http://www.cypress.io/') + .get('/') + .reply(200, 'content', { + 'Content-Type': 'text/html', + }) + + this.server.socket.localBus.emit('cross:origin:bridge:ready', { originPolicy: 'http://cypress.io' }) - expect(this.server.remoteStates.isSecondaryOrigin('http://cypress.io')).to.be.true - expect(this.server.remoteStates.get('http://cypress.io')).to.not.be.undefined + return this.server._onResolveUrl('http://www.cypress.io/', {}, this.automationRequest, { isCrossOrigin: true, auth: { username: 'u', password: 'p' } }) + .then(() => { + // Verify the secondary remote state is returned + expect(this.server.remoteStates.current()).to.deep.eq({ + auth: { + username: 'u', + password: 'p', + }, + props: { + domain: 'cypress', + port: '80', + tld: 'io', + }, + origin: 'http://www.cypress.io', + strategy: 'http', + domainName: 'cypress.io', + fileServer: null, + }) - this.server.remoteStates.reset() + this.server.socket.localBus.emit('cross:origin:bridge:ready', { originPolicy: 'http://cypress.io' }) - expect(this.server.remoteStates.isSecondaryOrigin('http://cypress.io')).to.be.false - expect(this.server.remoteStates.get('http://cypress.io')).to.be.undefined - expect(this.server.remoteStates.isPrimaryOrigin('http://localhost:2000')).to.be.true - expect(this.server.remoteStates.get('http://localhost:2000')).to.not.be.undefined + // Verify the existing secondary remote state is not overridden + expect(this.server.remoteStates.current()).to.deep.eq({ + auth: { + username: 'u', + password: 'p', + }, + props: { + domain: 'cypress', + port: '80', + tld: 'io', + }, + origin: 'http://www.cypress.io', + strategy: 'http', + domainName: 'cypress.io', + fileServer: null, + }) }) }) }) @@ -1113,6 +1190,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://localhost:2000/index.html', @@ -1133,6 +1211,7 @@ describe('Server', () => { }).then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://www.google.com/', @@ -1165,6 +1244,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://localhost:2000/index.html', @@ -1208,6 +1288,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://www.google.com/', @@ -1245,6 +1326,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://localhost:2000/index.html', @@ -1279,6 +1361,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://www.google.com/', @@ -1322,6 +1405,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'https://www.foobar.com:8443/', @@ -1359,6 +1443,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://localhost:2000/index.html', @@ -1393,6 +1478,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'https://www.foobar.com:8443/', @@ -1436,6 +1522,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: s3StaticHtmlUrl, @@ -1481,6 +1568,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: 'http://localhost:2000/index.html', @@ -1515,6 +1603,7 @@ describe('Server', () => { .then((obj = {}) => { return expectToEqDetails(obj, { isOkStatusCode: true, + isPrimaryOrigin: true, isHtml: true, contentType: 'text/html', url: s3StaticHtmlUrl, diff --git a/packages/server/test/unit/remote_states.spec.ts b/packages/server/test/unit/remote_states.spec.ts index 021f74c37d7c..6ad429044c4d 100644 --- a/packages/server/test/unit/remote_states.spec.ts +++ b/packages/server/test/unit/remote_states.spec.ts @@ -94,21 +94,21 @@ describe('remote states', () => { context('#isSecondaryOrigin', () => { it('returns true when the requested url is a secondary origin', function () { - this.eventEmitter.emit('ready:for:origin', { originPolicy: 'https://google.com' }) + this.eventEmitter.emit('cross:origin:bridge:ready', { originPolicy: 'https://google.com' }) const isSecondaryOrigin = this.remoteStates.isSecondaryOrigin('https://staging.google.com') expect(isSecondaryOrigin).to.be.true }) it('returns false when the requested url is the primary origin', function () { - this.eventEmitter.emit('ready:for:origin', { originPolicy: 'https://google.com' }) + this.eventEmitter.emit('cross:origin:bridge:ready', { originPolicy: 'https://google.com' }) const isSecondaryOrigin = this.remoteStates.isSecondaryOrigin('http://localhost:3500') expect(isSecondaryOrigin).to.be.false }) it('returns false when the requested url is not in the origin stack', function () { - this.eventEmitter.emit('ready:for:origin', { originPolicy: 'https://google.com' }) + this.eventEmitter.emit('cross:origin:bridge:ready', { originPolicy: 'https://google.com' }) const isSecondaryOrigin = this.remoteStates.isSecondaryOrigin('https://foobar.com') expect(isSecondaryOrigin).to.be.false @@ -123,7 +123,7 @@ describe('remote states', () => { }) it('returns false when the requested url is not the primary origin', function () { - this.eventEmitter.emit('ready:for:origin', { originPolicy: 'https://google.com' }) + this.eventEmitter.emit('cross:origin:bridge:ready', { originPolicy: 'https://google.com' }) const isPrimaryOrigin = this.remoteStates.isPrimaryOrigin('http://google.com') expect(isPrimaryOrigin).to.be.false @@ -132,7 +132,7 @@ describe('remote states', () => { context('#removeCurrentOrigin', () => { it('removes the current origin from the stack', function () { - this.eventEmitter.emit('ready:for:origin', { originPolicy: 'https://google.com' }) + this.eventEmitter.emit('cross:origin:bridge:ready', { originPolicy: 'https://google.com' }) expect(this.remoteStates.isInOriginStack('https://google.com')).to.be.true this.remoteStates.removeCurrentOrigin('https://google.com') @@ -141,7 +141,7 @@ describe('remote states', () => { }) it('throws an error when trying to remove the incorrect origin', function () { - this.eventEmitter.emit('ready:for:origin', { originPolicy: 'https://google.com' }) + this.eventEmitter.emit('cross:origin:bridge:ready', { originPolicy: 'https://google.com' }) expect(this.remoteStates.isInOriginStack('https://google.com')).to.be.true expect(() => this.remoteStates.removeCurrentOrigin('http://notfound.com')) @@ -151,9 +151,10 @@ describe('remote states', () => { context('#reset', () => { it('resets the origin stack and remote states to the primary', function () { - this.eventEmitter.emit('ready:for:origin', { originPolicy: 'https://google.com' }) + this.eventEmitter.emit('cross:origin:bridge:ready', { originPolicy: 'https://google.com' }) expect(this.remoteStates.isInOriginStack('https://google.com')).to.be.true + expect(this.remoteStates.get('https://google.com')).to.not.be.undefined this.remoteStates.reset() @@ -164,7 +165,7 @@ describe('remote states', () => { context('#current', () => { it('returns the remote state for the current origin in the stack', function () { - this.eventEmitter.emit('ready:for:origin', { originPolicy: 'https://google.com' }) + this.eventEmitter.emit('cross:origin:bridge:ready', { originPolicy: 'https://google.com' }) this.remoteStates.set('https://staging.google.com/foo/bar', { isCrossOrigin: true }) const state = this.remoteStates.current() @@ -203,6 +204,8 @@ describe('remote states', () => { }, }) + expect(this.remoteStates.get('https://staging.google.com')).to.deep.equal(state) + expect(this.remoteStates.isPrimaryOrigin('https://staging.google.com')).to.be.true }) @@ -226,6 +229,8 @@ describe('remote states', () => { }, }) + expect(this.remoteStates.get('https://staging.google.com')).to.deep.equal(state) + expect(this.remoteStates.isPrimaryOrigin('http://localhost:3500')).to.be.true expect(this.remoteStates.isPrimaryOrigin('https://staging.google.com')).to.be.false }) @@ -366,36 +371,24 @@ describe('remote states', () => { }) context('events', () => { - it('can add a secondary remote state on ready:for:origin', function () { + it('can add a secondary remote state on cross:origin:bridge:ready', function () { let currentState = this.remoteStates.current() expect(currentState.origin).to.equal('http://localhost:3500') - this.eventEmitter.emit('ready:for:origin', { originPolicy: 'http://cypress.io' }) + this.eventEmitter.emit('cross:origin:bridge:ready', { originPolicy: 'http://cypress.io' }) currentState = this.remoteStates.current() expect(currentState.origin).to.equal('http://cypress.io') expect(this.remoteStates.isSecondaryOrigin(currentState.origin)).to.be.true }) - it('doesn\'t do anything if ready:for:origin failed', function () { - let currentState = this.remoteStates.current() - - expect(currentState.origin).to.equal('http://localhost:3500') - - this.eventEmitter.emit('ready:for:origin', { failed: true }) - - currentState = this.remoteStates.current() - expect(currentState.origin).to.equal('http://localhost:3500') - expect(this.remoteStates.isSecondaryOrigin(currentState.origin)).to.be.false - }) - it('removes the current origin when cross:origin:finished is received', function () { let currentState = this.remoteStates.current() expect(currentState.origin).to.equal('http://localhost:3500') - this.eventEmitter.emit('ready:for:origin', { originPolicy: 'http://cypress.io' }) + this.eventEmitter.emit('cross:origin:bridge:ready', { originPolicy: 'http://cypress.io' }) currentState = this.remoteStates.current() expect(currentState.origin).to.equal('http://cypress.io') @@ -406,22 +399,22 @@ describe('remote states', () => { expect(currentState.origin).to.equal('http://localhost:3500') }) - it('doesn\'t override an existing secondary remote state on ready:for:origin', function () { + it('doesn\'t override an existing secondary remote state on cross:origin:bridge:ready', function () { let currentState = this.remoteStates.current() expect(currentState.origin).to.equal('http://localhost:3500') - // simulate a cy.origin by calling ready:for:origin followed by setting + // simulate a cy.origin by calling cross:origin:bridge:ready followed by setting // the origin with specific auth options and finally calling cross:origin:finished - this.eventEmitter.emit('ready:for:origin', { originPolicy: 'http://cypress.io' }) + this.eventEmitter.emit('cross:origin:bridge:ready', { originPolicy: 'http://cypress.io' }) this.remoteStates.set('http://cypress.io', { auth: { username: 'u', password: 'p' }, isCrossOrigin: true }) currentState = this.remoteStates.current() expect(currentState.origin).to.equal('http://cypress.io') expect(currentState.auth).to.deep.equal({ username: 'u', password: 'p' }) this.eventEmitter.emit('cross:origin:finished', 'http://cypress.io') - // verify calling ready:for:origin doesn't reset the previous state - this.eventEmitter.emit('ready:for:origin', { originPolicy: 'http://cypress.io' }) + // verify calling cross:origin:bridge:ready doesn't reset the previous state + this.eventEmitter.emit('cross:origin:bridge:ready', { originPolicy: 'http://cypress.io' }) currentState = this.remoteStates.current() expect(currentState.origin).to.equal('http://cypress.io') diff --git a/packages/server/test/unit/socket_spec.js b/packages/server/test/unit/socket_spec.js index 8a4d659bfaa0..93e4666beca2 100644 --- a/packages/server/test/unit/socket_spec.js +++ b/packages/server/test/unit/socket_spec.js @@ -563,16 +563,25 @@ describe('lib/socket', () => { }) }) - context('on(ready:for:origin)', () => { - it('emits ready:for:origin on local bus', function (done) { - this.server.socket.localBus.once('ready:for:origin', ({ originPolicy, failed }) => { + context('on(cross:origin:bridge:ready)', () => { + it('emits cross:origin:bridge:ready on local bus', function (done) { + this.server.socket.localBus.once('cross:origin:bridge:ready', ({ originPolicy }) => { expect(originPolicy).to.equal('http://foobar.com') - expect(failed).to.be.false done() }) - this.client.emit('backend:request', 'ready:for:origin', { originPolicy: 'http://foobar.com', failed: false }, () => {}) + this.client.emit('backend:request', 'cross:origin:bridge:ready', { originPolicy: 'http://foobar.com' }, () => {}) + }) + }) + + context('on(cross:origin:release:html)', () => { + it('emits cross:origin:release:html on local bus', function (done) { + this.server.socket.localBus.once('cross:origin:release:html', () => { + done() + }) + + this.client.emit('backend:request', 'cross:origin:release:html', () => {}) }) }) @@ -585,7 +594,7 @@ describe('lib/socket', () => { }) // add the origin before calling cross:origin:finished (otherwise we'll fail trying to remove the origin) - this.client.emit('backend:request', 'ready:for:origin', { originPolicy: 'http://foobar.com' }, () => {}) + this.client.emit('backend:request', 'cross:origin:bridge:ready', { originPolicy: 'http://foobar.com' }, () => {}) this.client.emit('backend:request', 'cross:origin:finished', 'http://foobar.com', () => {}) }) diff --git a/system-tests/__snapshots__/runnable_execution_spec.ts.js b/system-tests/__snapshots__/runnable_execution_spec.ts.js index d8e37324a4fd..0d6074bf3faf 100644 --- a/system-tests/__snapshots__/runnable_execution_spec.ts.js +++ b/system-tests/__snapshots__/runnable_execution_spec.ts.js @@ -38,11 +38,11 @@ exports['e2e runnable execution / cannot navigate in before hook and test'] = ` In order to visit a different origin, you can enable the \`experimentalSessionAndOrigin\` flag and use \`cy.origin()\`: \`cy.visit('http://localhost:4545/')\` -\`\` +\`\` \`cy.origin('http://localhost:5656', () => {\` \` cy.visit('http://localhost:5656/')\` -\` \` +\` \` \`})\` The new URL is considered a different origin because the following parts of the URL are different: @@ -69,11 +69,11 @@ https://on.cypress.io/cannot-visit-different-origin-domain In order to visit a different origin, you can enable the \`experimentalSessionAndOrigin\` flag and use \`cy.origin()\`: \`cy.visit('http://localhost:4545/')\` -\`\` +\`\` \`cy.origin('http://localhost:5656', () => {\` \` cy.visit('http://localhost:5656/')\` -\` \` +\` \` \`})\` The new URL is considered a different origin because the following parts of the URL are different: From 55e7f8a2310eded9ebbdf363b0be6d19c3d3df30 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Apr 2022 03:25:54 -0500 Subject: [PATCH 11/16] chore: Update Chrome (beta) to 101.0.4951.41 (#21161) Co-authored-by: cypress-bot[bot] <2f0651858c6e38e0+cypress-bot[bot]@users.noreply.github.com> --- browser-versions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser-versions.json b/browser-versions.json index 7cda3cd22949..f304171fae27 100644 --- a/browser-versions.json +++ b/browser-versions.json @@ -1,4 +1,4 @@ { - "chrome:beta": "101.0.4951.34", + "chrome:beta": "101.0.4951.41", "chrome:stable": "100.0.4896.127" } From e3161a0b37c5895b060c9a2883906409395f59b5 Mon Sep 17 00:00:00 2001 From: Matt Henkes Date: Thu, 21 Apr 2022 09:32:47 -0500 Subject: [PATCH 12/16] chore: [Multi-domain] Break out separate CI tasks to test the driver with experimentalSessionAndOrigin on (#21148) * Attempt to run tests without the feature flag and the multi-domain folder * do it for real this time dummy * trying circleci changes * valid file??? * moar changes! * i am a master of bash scripting * try another exclude pattern * one more time with feeling * lets do it again * maybe this? * different parallel group * lets try this * updating tests phase 1 * updating tests phase 2 * Apply suggestions from code review Co-authored-by: Matt Schile * Update tests * Run more tests * Re-locate system test * Flex message for firefox Co-authored-by: Matt Schile --- circle.yml | 77 ++++++++++++- packages/driver/cypress.json | 3 +- .../integration/commands/navigation_spec.js | 104 ++++++++++++------ .../e2e/multi-domain/stability_spec.ts | 34 ++++++ .../cypress/integration/e2e/stability_spec.js | 32 ------ packages/driver/package.json | 4 +- .../__snapshots__/navigation_spec.ts.js | 95 ---------------- .../navigation_cross_origin_errors.ts | 10 -- system-tests/test/navigation_spec.ts | 48 -------- 9 files changed, 183 insertions(+), 224 deletions(-) create mode 100644 packages/driver/cypress/integration/e2e/multi-domain/stability_spec.ts delete mode 100644 packages/driver/cypress/integration/e2e/stability_spec.js delete mode 100644 system-tests/__snapshots__/navigation_spec.ts.js delete mode 100644 system-tests/projects/e2e/cypress/integration/navigation_cross_origin_errors.ts delete mode 100644 system-tests/test/navigation_spec.ts diff --git a/circle.yml b/circle.yml index 24c0fb2c3f9b..49a982791e36 100644 --- a/circle.yml +++ b/circle.yml @@ -406,6 +406,10 @@ commands: description: chrome channel to install type: string default: '' + experimentalSessionAndOrigin: + description: experimental flag to apply + type: boolean + default: false steps: - restore_cached_workspace - when: @@ -423,8 +427,13 @@ commands: if [[ -v MAIN_RECORD_KEY ]]; then # internal PR - CYPRESS_RECORD_KEY=$MAIN_RECORD_KEY \ - yarn cypress:run --record --parallel --group 5x-driver-<> --browser <> + if <>; then + CYPRESS_RECORD_KEY=$MAIN_RECORD_KEY \ + yarn cypress:run-experimentalSessionAndOrigin --record --parallel --group 5x-driver-<>-experimentalSessionAndOrigin --browser <> + else + CYPRESS_RECORD_KEY=$MAIN_RECORD_KEY \ + yarn cypress:run --record --parallel --group 5x-driver-<> --browser <> + fi else # external PR TESTFILES=$(circleci tests glob "cypress/integration/**/*spec.*" | circleci tests split --total=$CIRCLE_NODE_TOTAL) @@ -433,7 +442,11 @@ commands: if [[ -z "$TESTFILES" ]]; then echo "Empty list of test files" fi - yarn cypress:run --browser <> --spec $TESTFILES + if <>; then + yarn cypress:run-experimentalSessionAndOrigin --browser <> --spec $TESTFILES + else + yarn cypress:run --browser <> --spec $TESTFILES + fi fi working_directory: packages/driver - verify-mocha-results @@ -1294,6 +1307,44 @@ jobs: - run-driver-integration-tests: browser: electron + driver-integration-tests-chrome-experimentalSessionAndOrigin: + <<: *defaults + resource_class: medium + parallelism: 5 + steps: + - run-driver-integration-tests: + browser: chrome + install-chrome-channel: stable + experimentalSessionAndOrigin: true + + driver-integration-tests-chrome-beta-experimentalSessionAndOrigin: + <<: *defaults + resource_class: medium + parallelism: 5 + steps: + - run-driver-integration-tests: + browser: chrome:beta + install-chrome-channel: beta + experimentalSessionAndOrigin: true + + driver-integration-tests-firefox-experimentalSessionAndOrigin: + <<: *defaults + resource_class: medium + parallelism: 5 + steps: + - run-driver-integration-tests: + browser: firefox + experimentalSessionAndOrigin: true + + driver-integration-tests-electron-experimentalSessionAndOrigin: + <<: *defaults + resource_class: medium + parallelism: 5 + steps: + - run-driver-integration-tests: + browser: electron + experimentalSessionAndOrigin: true + desktop-gui-integration-tests-7x: <<: *defaults parallelism: 7 @@ -2084,6 +2135,22 @@ linux-workflow: &linux-workflow context: test-runner:cypress-record-key requires: - build + - driver-integration-tests-chrome-experimentalSessionAndOrigin: + context: test-runner:cypress-record-key + requires: + - build + - driver-integration-tests-chrome-beta-experimentalSessionAndOrigin: + context: test-runner:cypress-record-key + requires: + - build + - driver-integration-tests-firefox-experimentalSessionAndOrigin: + context: test-runner:cypress-record-key + requires: + - build + - driver-integration-tests-electron-experimentalSessionAndOrigin: + context: test-runner:cypress-record-key + requires: + - build - runner-integration-tests-chrome: context: [test-runner:cypress-record-key, test-runner:percy] requires: @@ -2180,6 +2247,10 @@ linux-workflow: &linux-workflow - driver-integration-tests-chrome - driver-integration-tests-chrome-beta - driver-integration-tests-electron + - driver-integration-tests-firefox-experimentalSessionAndOrigin + - driver-integration-tests-chrome-experimentalSessionAndOrigin + - driver-integration-tests-chrome-beta-experimentalSessionAndOrigin + - driver-integration-tests-electron-experimentalSessionAndOrigin - system-tests-non-root - system-tests-firefox - system-tests-electron diff --git a/packages/driver/cypress.json b/packages/driver/cypress.json index 911238c1181a..f6d381383ca1 100644 --- a/packages/driver/cypress.json +++ b/packages/driver/cypress.json @@ -13,6 +13,5 @@ "retries": { "runMode": 2, "openMode": 0 - }, - "experimentalSessionAndOrigin": true + } } diff --git a/packages/driver/cypress/integration/commands/navigation_spec.js b/packages/driver/cypress/integration/commands/navigation_spec.js index b6b4f0155e3b..cf3a9b5c94ef 100644 --- a/packages/driver/cypress/integration/commands/navigation_spec.js +++ b/packages/driver/cypress/integration/commands/navigation_spec.js @@ -1409,10 +1409,11 @@ describe('src/cy/commands/navigation', () => { it('throws when attempting to visit a 2nd domain on different port', function (done) { cy.on('fail', (err) => { const { lastLog } = this + const experimentalMessage = Cypress.config('experimentalSessionAndOrigin') ? `You likely forgot to use \`cy.origin()\`:\n` : `In order to visit a different origin, you can enable the \`experimentalSessionAndOrigin\` flag and use \`cy.origin()\`:\n` expect(err.message).to.equal(stripIndent`\ \`cy.visit()\` failed because you are attempting to visit a URL that is of a different origin.\n - You likely forgot to use \`cy.origin()\`:\n + ${experimentalMessage} \`cy.visit('http://localhost:3500/fixtures/generic.html')\` \`\`\n \`cy.origin('http://localhost:3501', () => {\` @@ -1441,10 +1442,11 @@ describe('src/cy/commands/navigation', () => { it('throws when attempting to visit a 2nd domain on different protocol', function (done) { cy.on('fail', (err) => { const { lastLog } = this + const experimentalMessage = Cypress.config('experimentalSessionAndOrigin') ? `You likely forgot to use \`cy.origin()\`:\n` : `In order to visit a different origin, you can enable the \`experimentalSessionAndOrigin\` flag and use \`cy.origin()\`:\n` expect(err.message).to.equal(stripIndent`\ \`cy.visit()\` failed because you are attempting to visit a URL that is of a different origin.\n - You likely forgot to use \`cy.origin()\`:\n + ${experimentalMessage} \`cy.visit('http://localhost:3500/fixtures/generic.html')\` \`\`\n \`cy.origin('https://localhost:3502', () => {\` @@ -1473,10 +1475,11 @@ describe('src/cy/commands/navigation', () => { it('throws when attempting to visit a 2nd domain on different superdomain', function (done) { cy.on('fail', (err) => { const { lastLog } = this + const experimentalMessage = Cypress.config('experimentalSessionAndOrigin') ? `You likely forgot to use \`cy.origin()\`:\n` : `In order to visit a different origin, you can enable the \`experimentalSessionAndOrigin\` flag and use \`cy.origin()\`:\n` expect(err.message).to.equal(stripIndent`\ \`cy.visit()\` failed because you are attempting to visit a URL that is of a different origin.\n - You likely forgot to use \`cy.origin()\`:\n + ${experimentalMessage} \`cy.visit('http://localhost:3500/fixtures/generic.html')\` \`\`\n \`cy.origin('http://foobar.com:3500', () => {\` @@ -1505,10 +1508,11 @@ describe('src/cy/commands/navigation', () => { it('throws attempting to visit 2 unique ip addresses', function (done) { cy.on('fail', (err) => { const { lastLog } = this + const experimentalMessage = Cypress.config('experimentalSessionAndOrigin') ? `You likely forgot to use \`cy.origin()\`:\n` : `In order to visit a different origin, you can enable the \`experimentalSessionAndOrigin\` flag and use \`cy.origin()\`:\n` expect(err.message).to.equal(stripIndent`\ \`cy.visit()\` failed because you are attempting to visit a URL that is of a different origin.\n - You likely forgot to use \`cy.origin()\`:\n + ${experimentalMessage} \`cy.visit('http://127.0.0.1:3500/fixtures/generic.html')\` \`\`\n \`cy.origin('http://0.0.0.0:3500', () => {\` @@ -2145,6 +2149,53 @@ describe('src/cy/commands/navigation', () => { .get('#does-not-exist', { timeout: 200 }).should('have.class', 'foo') }) + it('displays cross origin failures when navigating to a cross origin', { pageLoadTimeout: 3000 }, function (done) { + cy.on('fail', (err) => { + const { lastLog } = this + + if (Cypress.config('experimentalSessionAndOrigin')) { + // When the experimentalSessionAndOrigin feature is enabled, we will timeout and display this message. + expect(err.message).to.equal(stripIndent`\ + Timed out after waiting \`3000ms\` for your remote page to load on origin(s):\n + - \`http://localhost:3500\`\n + A cross-origin request for \`http://www.foobar.com:3500/fixtures/multi-domain-secondary.html\` was detected.\n + A command that triggers cross-origin navigation must be immediately followed by a \`cy.origin()\` command:\n + \`cy.origin(\'http://foobar.com:3500\', () => {\` + \` \` + \`})\`\n + If the cross-origin request was an intermediary state, you can try increasing the \`pageLoadTimeout\` value in \`cypress.json\` to wait longer.\n + Browsers will not fire the \`load\` event until all stylesheets and scripts are done downloading.\n + When this \`load\` event occurs, Cypress will continue running commands.`) + + expect(err.docsUrl).to.eq('https://on.cypress.io/origin') + } else { + const error = Cypress.isBrowser('firefox') ? 'Permission denied to access property "document" on cross-origin object' : 'Blocked a frame with origin "http://localhost:3500" from accessing a cross-origin frame.' + + // When the experimentalSessionAndOrigin feature is disabled, we will immediately and display this message. + expect(err.message).to.equal(stripIndent`\ + Cypress detected a cross origin error happened on page load:\n + > ${error}\n + Before the page load, you were bound to the origin policy:\n + > http://localhost:3500\n + A cross origin error happens when your application navigates to a new URL which does not match the origin policy above.\n + A new URL does not match the origin policy if the 'protocol', 'port' (if specified), and/or 'host' (unless of the same superdomain) are different.\n + Cypress does not allow you to navigate to a different origin URL within a single test.\n + You may need to restructure some of your test code to avoid this problem.\n + Alternatively you can also disable Chrome Web Security in Chromium-based browsers which will turn off this restriction by setting { chromeWebSecurity: false } in \`cypress.json\`.`) + + expect(err.docsUrl).to.eq('https://on.cypress.io/cross-origin-violation') + } + + assertLogLength(this.logs, 6) + expect(lastLog.get('error')).to.eq(err) + + done() + }) + + cy.visit('/fixtures/multi-domain.html') + cy.get('a[data-cy="cross-origin-secondary-link"]').click() + }) + return null }) }) @@ -2269,41 +2320,28 @@ describe('src/cy/commands/navigation', () => { }) }) - it('waits for stability at the end of the command queue when not stable', { experimentalSessionAndOrigin: false }, (done) => { + it('tests waiting on stability at the end of the command queue', (done) => { cy .visit('/fixtures/generic.html') .then((win) => { - cy.on('window:load', () => { + // We do not wait if the experimentalSessionAndOrigin feature is enabled + if (Cypress.config('experimentalSessionAndOrigin')) { + const onLoad = cy.spy() + + cy.on('window:load', onLoad) + cy.on('command:queue:end', () => { + expect(onLoad).not.have.been.called done() }) - }) - - cy.on('command:queue:before:end', () => { - // force us to become unstable immediately - // else the beforeunload event fires at the end - // of the tick which is too late - cy.isStable(false, 'testing') - - win.location.href = '/timeout?ms=100' - }) - - return null - }) - }) - - it('does not wait for stability at the end of the command queue when not stable with experimentalSessionAndOrigin', (done) => { - const onLoad = cy.spy() - - cy - .visit('/fixtures/generic.html') - .then((win) => { - cy.on('window:load', onLoad) - - cy.on('command:queue:end', () => { - expect(onLoad).not.have.been.called - done() - }) + } else { + // We do wait if the experimentalSessionAndOrigin feature is not enabled + cy.on('window:load', () => { + cy.on('command:queue:end', () => { + done() + }) + }) + } cy.on('command:queue:before:end', () => { // force us to become unstable immediately diff --git a/packages/driver/cypress/integration/e2e/multi-domain/stability_spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/stability_spec.ts new file mode 100644 index 000000000000..26486e41c651 --- /dev/null +++ b/packages/driver/cypress/integration/e2e/multi-domain/stability_spec.ts @@ -0,0 +1,34 @@ +describe('stability', () => { + describe('before each transitions', () => { + describe('transitioning from a before block to an it block while unstable', () => { + beforeEach(() => { + cy.visit('/fixtures/auth/index.html') + cy.window().then((win) => { + win.location.href = 'http://localhost:3500/timeout?ms=1000' + }) + }) + + it('fails if the page does not load within the page load timeout', { defaultCommandTimeout: 50, pageLoadTimeout: 500 }, (done) => { + cy.on('fail', (err) => { + expect(err.message).to.include(`Timed out after waiting \`500ms\` for your remote page to load.`) + done() + }) + + cy.get('[data-cy="login-idp"]').click() // Takes you to idp.com + }) + + it('waits for the page to load before running the command', { defaultCommandTimeout: 50 }, () => { + cy.get('body').invoke('text').should('equal', 'timeout') + }) + + it('will retry and fail the command after the page loads', { defaultCommandTimeout: 50 }, (done) => { + cy.on('fail', (err) => { + expect(err.message).to.include(`Timed out retrying after 50ms: expected 'timeout' to equal 'not timeout'`) + done() + }) + + cy.get('body').invoke('text').should('equal', 'not timeout') + }) + }) + }) +}) diff --git a/packages/driver/cypress/integration/e2e/stability_spec.js b/packages/driver/cypress/integration/e2e/stability_spec.js deleted file mode 100644 index b6d541845f79..000000000000 --- a/packages/driver/cypress/integration/e2e/stability_spec.js +++ /dev/null @@ -1,32 +0,0 @@ -describe('stability', () => { - describe('transitioning from a before block to an it block while unstable', () => { - beforeEach(() => { - cy.visit('/fixtures/auth/index.html') - cy.window().then((win) => { - win.location.href = 'http://localhost:3500/timeout?ms=1000' - }) - }) - - it('fails if the page does not load within the page load timeout', { defaultCommandTimeout: 50, pageLoadTimeout: 500 }, (done) => { - cy.on('fail', (err) => { - expect(err.message).to.include(`Timed out after waiting \`500ms\` for your remote page to load.`) - done() - }) - - cy.get('[data-cy="login-idp"]').click() // Takes you to idp.com - }) - - it('waits for the page to load before running the command', { defaultCommandTimeout: 50 }, () => { - cy.get('body').invoke('text').should('equal', 'timeout') - }) - - it('will retry and fail the command after the page loads', { defaultCommandTimeout: 50 }, (done) => { - cy.on('fail', (err) => { - expect(err.message).to.include(`Timed out retrying after 50ms: expected 'timeout' to equal 'not timeout'`) - done() - }) - - cy.get('body').invoke('text').should('equal', 'not timeout') - }) - }) -}) diff --git a/packages/driver/package.json b/packages/driver/package.json index aca090231a17..6641bc4c0d00 100644 --- a/packages/driver/package.json +++ b/packages/driver/package.json @@ -5,7 +5,9 @@ "scripts": { "clean-deps": "rm -rf node_modules", "cypress:open": "node ../../scripts/cypress open", - "cypress:run": "node ../../scripts/cypress run", + "cypress:run": "node ../../scripts/cypress run --spec \"cypress/integration/*/*\",\"cypress/integration/*/!(multi-domain)/**/*\"", + "cypress:open-experimentalSessionAndOrigin": "node ../../scripts/cypress open --config experimentalSessionAndOrigin=true", + "cypress:run-experimentalSessionAndOrigin": "node ../../scripts/cypress run --config experimentalSessionAndOrigin=true", "postinstall": "patch-package", "start": "node -e 'console.log(require(`chalk`).red(`\nError:\n\tRunning \\`yarn start\\` is no longer needed for driver/cypress tests.\n\tWe now automatically spawn the server in the pluginsFile.\n\tChanges to the server will be watched and reloaded automatically.`))'" }, diff --git a/system-tests/__snapshots__/navigation_spec.ts.js b/system-tests/__snapshots__/navigation_spec.ts.js deleted file mode 100644 index 38df39d3a9c0..000000000000 --- a/system-tests/__snapshots__/navigation_spec.ts.js +++ /dev/null @@ -1,95 +0,0 @@ -exports['e2e cross origin navigation / captures cross origin failures when "experimentalSessionAndOrigin" config value is falsy'] = ` - -==================================================================================================== - - (Run Starting) - - ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ Cypress: 1.2.3 │ - │ Browser: FooBrowser 88 │ - │ Specs: 1 found (navigation_cross_origin_errors.ts) │ - │ Searched: cypress/integration/navigation_cross_origin_errors.ts │ - │ Experiments: experimentalSessionAndOrigin=false │ - └────────────────────────────────────────────────────────────────────────────────────────────────┘ - - -──────────────────────────────────────────────────────────────────────────────────────────────────── - - Running: navigation_cross_origin_errors.ts (1 of 1) - - - navigation cross origin errors - 1) displays cross origin failures when "experimentalSessionAndOrigin" is turned off - - - 0 passing - 1 failing - - 1) navigation cross origin errors - displays cross origin failures when "experimentalSessionAndOrigin" is turned off: - CypressError: Cypress detected a cross origin error happened on page load: - - > [Cross origin error message] - -Before the page load, you were bound to the origin policy: - - > http://localhost:13370 - -A cross origin error happens when your application navigates to a new URL which does not match the origin policy above. - -A new URL does not match the origin policy if the 'protocol', 'port' (if specified), and/or 'host' (unless of the same superdomain) are different. - -Cypress does not allow you to navigate to a different origin URL within a single test. - -You may need to restructure some of your test code to avoid this problem. - -Alternatively you can also disable Chrome Web Security in Chromium-based browsers which will turn off this restriction by setting { chromeWebSecurity: false } in \`cypress.json\`. - -https://on.cypress.io/cross-origin-violation - [stack trace lines] - - - - - (Results) - - ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ Tests: 1 │ - │ Passing: 0 │ - │ Failing: 1 │ - │ Pending: 0 │ - │ Skipped: 0 │ - │ Screenshots: 1 │ - │ Video: true │ - │ Duration: X seconds │ - │ Spec Ran: navigation_cross_origin_errors.ts │ - └────────────────────────────────────────────────────────────────────────────────────────────────┘ - - - (Screenshots) - - - /XXX/XXX/XXX/cypress/screenshots/navigation_cross_origin_errors.ts/navigation cr (1280x720) - oss origin errors -- displays cross origin failures when experimentalSessionAndO - rigin is turned off (failed).png - - - (Video) - - - Started processing: Compressing to 32 CRF - - Finished processing: /XXX/XXX/XXX/cypress/videos/navigation_cross_origin_errors. (X second) - ts.mp4 - - -==================================================================================================== - - (Run Finished) - - - Spec Tests Passing Failing Pending Skipped - ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ ✖ navigation_cross_origin_errors.ts XX:XX 1 - 1 - - │ - └────────────────────────────────────────────────────────────────────────────────────────────────┘ - ✖ 1 of 1 failed (100%) XX:XX 1 - 1 - - - - -` diff --git a/system-tests/projects/e2e/cypress/integration/navigation_cross_origin_errors.ts b/system-tests/projects/e2e/cypress/integration/navigation_cross_origin_errors.ts deleted file mode 100644 index 7e1654adc89a..000000000000 --- a/system-tests/projects/e2e/cypress/integration/navigation_cross_origin_errors.ts +++ /dev/null @@ -1,10 +0,0 @@ -describe('navigation cross origin errors', () => { - it('displays cross origin failures when "experimentalSessionAndOrigin" is turned off', function () { - // @ts-ignore - cy.visit('/jquery.html').window().then((win) => { - const constructedCrossOriginAnchor = win.$(`cross origin`).appendTo(win.document.body) - - constructedCrossOriginAnchor.get(0).click() - }) - }) -}) diff --git a/system-tests/test/navigation_spec.ts b/system-tests/test/navigation_spec.ts deleted file mode 100644 index b4f83ade06e0..000000000000 --- a/system-tests/test/navigation_spec.ts +++ /dev/null @@ -1,48 +0,0 @@ -import systemTests, { expect } from '../lib/system-tests' - -const PORT = 13370 -const onServer = function (app) { - app.get('/cross_origin.html', (req, res) => { - res.send('

cross origin

') - }) -} - -describe('e2e cross origin navigation', () => { - systemTests.setup({ - servers: [{ - port: 4466, - onServer, - }], - settings: { - hosts: { - '*.foobar.com': '127.0.0.1', - }, - }, - }) - - // TODO: convert to cypress-in-cypress test if possible - // https://github.com/cypress-io/cypress/issues/20973 - systemTests.it('captures cross origin failures when "experimentalSessionAndOrigin" config value is falsy', { - // keep the port the same to prevent issues with the snapshot - port: PORT, - spec: 'navigation_cross_origin_errors.ts', - browser: ['chrome', 'electron'], - snapshot: true, - expectedExitCode: 1, - config: { - experimentalSessionAndOrigin: false, - }, - async onRun (exec) { - const res = await exec() - - expect(res.stdout).to.contain('Cypress detected a cross origin error happened on page load') - expect(res.stdout).to.contain('Before the page load, you were bound to the origin policy:') - expect(res.stdout).to.contain('A cross origin error happens when your application navigates to a new URL which does not match the origin policy above.') - expect(res.stdout).to.contain('A new URL does not match the origin policy if the \'protocol\', \'port\' (if specified), and/or \'host\' (unless of the same superdomain) are different.') - expect(res.stdout).to.contain('Cypress does not allow you to navigate to a different origin URL within a single test.') - expect(res.stdout).to.contain('You may need to restructure some of your test code to avoid this problem.') - expect(res.stdout).to.contain('Alternatively you can also disable Chrome Web Security in Chromium-based browsers which will turn off this restriction by setting { chromeWebSecurity: false } in `cypress.json`.') - expect(res.stdout).to.contain('https://on.cypress.io/cross-origin-violation') - }, - }) -}) From 342bc06ae3f7d2bb3b6eca28183d30391330f16a Mon Sep 17 00:00:00 2001 From: Ahmed Tarek Date: Thu, 21 Apr 2022 22:54:50 +0200 Subject: [PATCH 13/16] fix: prevObject types (#21106) Co-authored-by: Emily Rohrbough Co-authored-by: Rachel Co-authored-by: Tyler Biethman --- cli/types/cypress.d.ts | 11 ++++++++--- cli/types/tests/cypress-tests.ts | 22 +++++++++++----------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index bfb7c84822fd..2e576727860b 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -10,10 +10,13 @@ declare namespace Cypress { type PrevSubject = keyof PrevSubjectMap type TestingType = 'e2e' | 'component' type PluginConfig = (on: PluginEvents, config: PluginConfigOptions) => void | ConfigOptions | Promise + interface JQueryWithSelector extends JQuery { + selector?: string | null + } interface PrevSubjectMap { optional: O - element: JQuery + element: JQueryWithSelector document: Document window: Window } @@ -467,16 +470,18 @@ declare namespace Cypress { Commands: { add(name: T, fn: CommandFn): void add(name: T, options: CommandOptions & {prevSubject: false}, fn: CommandFn): void + add(name: T, options: CommandOptions & {prevSubject: true}, fn: CommandFnWithSubject): void add( - name: T, options: CommandOptions & { prevSubject: true | S | ['optional'] }, fn: CommandFnWithSubject, + name: T, options: CommandOptions & { prevSubject: S | ['optional'] }, fn: CommandFnWithSubject, ): void add( name: T, options: CommandOptions & { prevSubject: S[] }, fn: CommandFnWithSubject[S]>, ): void addAll(fns: CommandFns): void addAll(options: CommandOptions & {prevSubject: false}, fns: CommandFns): void + addAll(options: CommandOptions & { prevSubject: true }, fns: CommandFnsWithSubject): void addAll( - options: CommandOptions & { prevSubject: true | S | ['optional'] }, fns: CommandFnsWithSubject, + options: CommandOptions & { prevSubject: S | ['optional'] }, fns: CommandFnsWithSubject, ): void addAll( options: CommandOptions & { prevSubject: S[] }, fns: CommandFnsWithSubject[S]>, diff --git a/cli/types/tests/cypress-tests.ts b/cli/types/tests/cypress-tests.ts index eecb36f65909..d1992f829f6e 100644 --- a/cli/types/tests/cypress-tests.ts +++ b/cli/types/tests/cypress-tests.ts @@ -83,7 +83,7 @@ namespace CypressCommandsTests { arg // $ExpectType string }) Cypress.Commands.add('newCommand', { prevSubject: true }, (subject, arg) => { - subject // $ExpectType unknown + subject // $ExpectType any arg // $ExpectType string return }) @@ -113,11 +113,11 @@ namespace CypressCommandsTests { arg // $ExpectType string }) Cypress.Commands.add('newCommand', { prevSubject: 'element' }, (subject, arg) => { - subject // $ExpectType JQuery + subject // $ExpectType JQueryWithSelector arg // $ExpectType string }) Cypress.Commands.add('newCommand', { prevSubject: ['element'] }, (subject, arg) => { - subject // $ExpectType JQuery + subject // $ExpectType JQueryWithSelector arg // $ExpectType string }) Cypress.Commands.add('newCommand', { prevSubject: ['element', 'document', 'window'] }, (subject, arg) => { @@ -126,7 +126,7 @@ namespace CypressCommandsTests { } else if (subject instanceof Document) { subject // $ExpectType Document } else { - subject // $ExpectType JQuery + subject // $ExpectType JQueryWithSelector } arg // $ExpectType string }) @@ -136,7 +136,7 @@ namespace CypressCommandsTests { } else if (subject instanceof Document) { subject // $ExpectType Document } else if (subject) { - subject // $ExpectType JQuery + subject // $ExpectType JQueryWithSelector } else { subject // $ExpectType void } @@ -173,7 +173,7 @@ namespace CypressCommandsTests { }) Cypress.Commands.addAll({ prevSubject: true }, { newCommand: (subject, arg) => { - subject // $ExpectType unknown + subject // $ExpectType any arg // $ExpectType any return }, @@ -215,13 +215,13 @@ namespace CypressCommandsTests { }) Cypress.Commands.addAll({ prevSubject: 'element' }, { newCommand: (subject, arg) => { - subject // $ExpectType JQuery + subject // $ExpectType JQueryWithSelector arg // $ExpectType any } }) Cypress.Commands.addAll({ prevSubject: ['element'] }, { newCommand: (subject, arg) => { - subject // $ExpectType JQuery + subject // $ExpectType JQueryWithSelector arg // $ExpectType any } }) @@ -232,7 +232,7 @@ namespace CypressCommandsTests { } else if (subject instanceof Document) { subject // $ExpectType Document } else { - subject // $ExpectType JQuery + subject // $ExpectType JQueryWithSelector } arg // $ExpectType any } @@ -244,7 +244,7 @@ namespace CypressCommandsTests { } else if (subject instanceof Document) { subject // $ExpectType Document } else if (subject) { - subject // $ExpectType JQuery + subject // $ExpectType JQueryWithSelector } else { subject // $ExpectType void } @@ -271,7 +271,7 @@ namespace CypressCommandsTests { originalFn.apply(this, [arg]) // $ExpectType Chainable }) Cypress.Commands.overwrite<'type', 'element'>('type', (originalFn, element, text, options?: Partial) => { - element // $ExpectType JQuery + element // $ExpectType JQueryWithSelector text // $ExpectType string if (options && options.sensitive) { From 885541ea5e736dfd4dac1d3254025b55b367fa3e Mon Sep 17 00:00:00 2001 From: Bill Glesias Date: Fri, 22 Apr 2022 09:41:35 -0400 Subject: [PATCH 14/16] improve error messages for unsupported APIs/commands --- .../commands/multi_domain_unsupported_commands.spec.ts | 4 ++-- .../e2e/multi-domain/multi_domain_cypress_api.spec.ts | 2 +- packages/driver/src/cypress/error_messages.ts | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_unsupported_commands.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_unsupported_commands.spec.ts index 5f63679a56e9..b6b862da5d72 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_unsupported_commands.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_unsupported_commands.spec.ts @@ -6,7 +6,7 @@ context('cy.origin unsupported commands', () => { it('cy.route() method is deprecated', (done) => { cy.on('fail', (err) => { - expect(err.message).to.equal('`cy.route()` has been deprecated and use is not supported in the `cy.origin()` callback. Consider using `cy.intercept()` (outside of the callback) instead.') + expect(err.message).to.equal('`cy.route()` has been deprecated and its use is not supported in the `cy.origin()` callback. Consider using `cy.intercept()` (outside of the callback) instead.') expect(err.docsUrl).to.equal('https://on.cypress.io/intercept') done() }) @@ -18,7 +18,7 @@ context('cy.origin unsupported commands', () => { it('cy.server() method is deprecated', (done) => { cy.on('fail', (err) => { - expect(err.message).to.equal('`cy.server()` has been deprecated and use is not supported in the `cy.origin()` callback. Consider using `cy.intercept()` (outside of the callback) instead.') + expect(err.message).to.equal('`cy.server()` has been deprecated and its use is not supported in the `cy.origin()` callback. Consider using `cy.intercept()` (outside of the callback) instead.') expect(err.docsUrl).to.equal('https://on.cypress.io/intercept') done() }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/multi_domain_cypress_api.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/multi_domain_cypress_api.spec.ts index 0e67507ea61e..927ec1d5e673 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/multi_domain_cypress_api.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/multi_domain_cypress_api.spec.ts @@ -206,7 +206,7 @@ describe('cy.origin Cypress API', () => { context('not supported', () => { it('throws an error when a user attempts to configure Cypress.Server.defaults() inside of cy.origin', (done) => { cy.on('fail', (err) => { - expect(err.message).to.equal('`Cypress.Server.*` has been deprecated and use is not supported in the `cy.origin()` callback. Consider using `cy.intercept()` (outside of the callback) instead.') + expect(err.message).to.equal('`Cypress.Server.*` has been deprecated and its use is not supported in the `cy.origin()` callback. Consider using `cy.intercept()` (outside of the callback) instead.') expect(err.docsUrl).to.equal('https://on.cypress.io/intercept') done() }) diff --git a/packages/driver/src/cypress/error_messages.ts b/packages/driver/src/cypress/error_messages.ts index 937a349e2a17..28adaa64859e 100644 --- a/packages/driver/src/cypress/error_messages.ts +++ b/packages/driver/src/cypress/error_messages.ts @@ -1205,15 +1205,15 @@ export default { }, unsupported: { route: { - message: `${cmd('route')} has been deprecated and use is not supported in the ${cmd('origin')} callback. Consider using ${cmd('intercept')} (outside of the callback) instead.`, + message: `${cmd('route')} has been deprecated and its use is not supported in the ${cmd('origin')} callback. Consider using ${cmd('intercept')} (outside of the callback) instead.`, docsUrl: 'https://on.cypress.io/intercept', }, server: { - message: `${cmd('server')} has been deprecated and use is not supported in the ${cmd('origin')} callback. Consider using ${cmd('intercept')} (outside of the callback) instead.`, + message: `${cmd('server')} has been deprecated and its use is not supported in the ${cmd('origin')} callback. Consider using ${cmd('intercept')} (outside of the callback) instead.`, docsUrl: 'https://on.cypress.io/intercept', }, Server: { - message: `\`Cypress.Server.*\` has been deprecated and use is not supported in the ${cmd('origin')} callback. Consider using ${cmd('intercept')} (outside of the callback) instead.`, + message: `\`Cypress.Server.*\` has been deprecated and its use is not supported in the ${cmd('origin')} callback. Consider using ${cmd('intercept')} (outside of the callback) instead.`, docsUrl: 'https://on.cypress.io/intercept', }, Cookies_preserveOnce: { From 0bb655e3795e894610357b205b0d3b3d5bd1c819 Mon Sep 17 00:00:00 2001 From: Kukhyeon Heo Date: Fri, 22 Apr 2022 23:28:13 +0900 Subject: [PATCH 15/16] chore: remove command type todos (#20601) Co-authored-by: Zach Bloomquist Co-authored-by: Jennifer Shehane Co-authored-by: Rachel Co-authored-by: Tyler Biethman --- cli/types/cypress.d.ts | 2 +- .../integration/commands/screenshot_spec.js | 6 +- .../driver/src/cy/commands/actions/focus.ts | 30 ++++++--- .../driver/src/cy/commands/actions/scroll.ts | 39 ++++++----- .../driver/src/cy/commands/actions/select.ts | 16 +++-- .../driver/src/cy/commands/actions/submit.ts | 15 +++-- .../driver/src/cy/commands/actions/type.ts | 33 ++++++---- packages/driver/src/cy/commands/angular.ts | 12 ++-- packages/driver/src/cy/commands/clock.ts | 3 +- packages/driver/src/cy/commands/cookies.ts | 64 +++++++++++-------- packages/driver/src/cy/commands/debugging.ts | 27 ++++---- packages/driver/src/cy/commands/exec.ts | 13 ++-- packages/driver/src/cy/commands/files.ts | 24 ++++--- packages/driver/src/cy/commands/location.ts | 23 ++++--- packages/driver/src/cy/commands/misc.ts | 15 +++-- packages/driver/src/cy/commands/navigation.ts | 23 +++---- .../src/cy/commands/querying/focused.ts | 15 +++-- .../src/cy/commands/querying/querying.ts | 40 +++++++----- .../driver/src/cy/commands/querying/root.ts | 16 +++-- packages/driver/src/cy/commands/screenshot.ts | 14 ++-- packages/driver/src/cy/commands/task.ts | 12 ++-- packages/driver/src/cy/commands/window.ts | 53 +++++++-------- packages/driver/src/cy/keyboard.ts | 3 +- packages/driver/src/cy/video-recorder.ts | 2 - packages/driver/src/cypress/browser.ts | 3 +- packages/driver/src/cypress/log.ts | 2 +- .../@types+jquery.scrollto+1.4.29.dev.patch | 58 +++++++++++++++++ 27 files changed, 349 insertions(+), 214 deletions(-) create mode 100644 patches/@types+jquery.scrollto+1.4.29.dev.patch diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index 2e576727860b..b76af718c3c5 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -2519,7 +2519,7 @@ declare namespace Cypress { action: 'select' | 'drag-drop' } - interface BlurOptions extends Loggable, Forceable { } + interface BlurOptions extends Loggable, Timeoutable, Forceable { } interface CheckOptions extends Loggable, Timeoutable, ActionableOptions { interval: number diff --git a/packages/driver/cypress/integration/commands/screenshot_spec.js b/packages/driver/cypress/integration/commands/screenshot_spec.js index 0045c2a7b24a..acb4837802e8 100644 --- a/packages/driver/cypress/integration/commands/screenshot_spec.js +++ b/packages/driver/cypress/integration/commands/screenshot_spec.js @@ -761,9 +761,9 @@ describe('src/cy/commands/screenshot', () => { cy.get('.short-element').within(() => { cy.screenshot({ capture: 'runner' }) }).then(() => { - // the runner was captured - expect(Cypress.action.withArgs('cy:before:screenshot').args[0][1].appOnly).to.be.true - expect(Cypress.automation.withArgs('take:screenshot').args[0][1].capture).to.equal('viewport') + // the runner was captured ("appOnly === true" means to hide the runner UI) + expect(Cypress.action.withArgs('cy:before:screenshot').args[0][1].appOnly).to.be.false + expect(Cypress.automation.withArgs('take:screenshot').args[0][1].capture).to.equal('runner') }) }) diff --git a/packages/driver/src/cy/commands/actions/focus.ts b/packages/driver/src/cy/commands/actions/focus.ts index 5f5bc457a762..e866def4c133 100644 --- a/packages/driver/src/cy/commands/actions/focus.ts +++ b/packages/driver/src/cy/commands/actions/focus.ts @@ -4,16 +4,29 @@ import $dom from '../../../dom' import $utils from '../../../cypress/utils' import $errUtils from '../../../cypress/error_utils' import $elements from '../../../dom/elements' +import type { Log } from '../../../cypress/log' + +interface InternalFocusOptions extends Partial { + _log?: Log + $el: JQuery + error: boolean + verify: boolean +} + +interface InternalBlurOptions extends Partial { + _log?: Log + $el: JQuery + $focused: JQuery + error: boolean + verify: boolean +} export default (Commands, Cypress, cy) => { return Commands.addAll({ prevSubject: ['element', 'window'] }, { - // TODO: any -> Partial - focus (subject, options: any = {}) { - const userOptions = options - + focus (subject, userOptions: Partial = {}) { // we should throw errors by default! // but allow them to be silenced - options = _.defaults({}, userOptions, { + const options: InternalFocusOptions = _.defaults({}, userOptions, { $el: subject, error: true, log: true, @@ -85,13 +98,10 @@ export default (Commands, Cypress, cy) => { return verifyAssertions() }, - // TODO: any -> Partial - blur (subject, options: any = {}) { - const userOptions = options - + blur (subject, userOptions: Partial = {}) { // we should throw errors by default! // but allow them to be silenced - options = _.defaults({}, userOptions, { + const options: InternalBlurOptions = _.defaults({}, userOptions, { $el: subject, $focused: cy.getFocused(), error: true, diff --git a/packages/driver/src/cy/commands/actions/scroll.ts b/packages/driver/src/cy/commands/actions/scroll.ts index 48077d99b2eb..f918f0f459a4 100644 --- a/packages/driver/src/cy/commands/actions/scroll.ts +++ b/packages/driver/src/cy/commands/actions/scroll.ts @@ -5,6 +5,7 @@ import Promise from 'bluebird' import $dom from '../../../dom' import $utils from '../../../cypress/utils' import $errUtils from '../../../cypress/error_utils' +import type { Log } from '../../../cypress/log' const findScrollableParent = ($el, win) => { const $parent = $dom.getParent($el) @@ -28,12 +29,26 @@ const isNaNOrInfinity = (item) => { return _.isNaN(num) || !_.isFinite(num) } +interface InternalScrollIntoViewOptions extends Partial { + _log?: Log + $el: JQuery + $parent: any + axis: string + offset?: object +} + +interface InternalScrollToOptions extends Partial { + _log?: Log + $el: any + x: number + y: number + error?: any + axis: string +} + export default (Commands, Cypress, cy, state) => { Commands.addAll({ prevSubject: 'element' }, { - // TODO: any -> Partial - scrollIntoView (subject, options: any = {}) { - const userOptions = options - + scrollIntoView (subject, userOptions: Partial = {}) { if (!_.isObject(userOptions)) { $errUtils.throwErrByPath('scrollIntoView.invalid_argument', { args: { arg: userOptions } }) } @@ -49,7 +64,7 @@ export default (Commands, Cypress, cy, state) => { $errUtils.throwErrByPath('scrollIntoView.multiple_elements', { args: { num: subject.length } }) } - options = _.defaults({}, userOptions, { + const options: InternalScrollIntoViewOptions = _.defaults({}, userOptions, { $el: subject, $parent: state('window'), log: true, @@ -115,9 +130,6 @@ export default (Commands, Cypress, cy, state) => { const scrollIntoView = () => { return new Promise((resolve, reject) => { // scroll our axes - // TODO: done() came from jQuery animate(), specifically, EffectsOptions at misc.d.ts - // The type definition should be fixed at @types/jquery.scrollto. - // @ts-ignore return $(options.$parent).scrollTo(options.$el, { axis: options.axis, easing: options.easing, @@ -157,10 +169,8 @@ export default (Commands, Cypress, cy, state) => { }) Commands.addAll({ prevSubject: ['optional', 'element', 'window'] }, { - // TODO: any -> Partial - scrollTo (subject, xOrPosition, yOrOptions, options: any = {}) { + scrollTo (subject, xOrPosition, yOrOptions, userOptions: Partial = {}) { let x; let y - let userOptions = options // check for undefined or null values if (xOrPosition === undefined || xOrPosition === null) { @@ -261,7 +271,7 @@ export default (Commands, Cypress, cy, state) => { $errUtils.throwErrByPath('scrollTo.multiple_containers', { args: { num: $container.length } }) } - options = _.defaults({}, userOptions, { + const options: InternalScrollToOptions = _.defaults({}, userOptions, { $el: $container, log: true, duration: 0, @@ -361,10 +371,7 @@ export default (Commands, Cypress, cy, state) => { const scrollTo = () => { return new Promise((resolve, reject) => { - // scroll our axis' - // TODO: done() came from jQuery animate(), specifically, EffectsOptions at misc.d.ts - // The type definition should be fixed at @types/jquery.scrollto. - // @ts-ignore + // scroll our axis $(options.$el).scrollTo({ left: x, top: y }, { axis: options.axis, easing: options.easing, diff --git a/packages/driver/src/cy/commands/actions/select.ts b/packages/driver/src/cy/commands/actions/select.ts index 12b3a28ea7c7..e21e2e31d806 100644 --- a/packages/driver/src/cy/commands/actions/select.ts +++ b/packages/driver/src/cy/commands/actions/select.ts @@ -5,13 +5,19 @@ import $dom from '../../../dom' import $utils from '../../../cypress/utils' import $errUtils from '../../../cypress/error_utils' import $elements from '../../../dom/elements' +import type { Log } from '../../../cypress/log' const newLineRe = /\n/g +interface InternalSelectOptions extends Partial { + _log?: Log + $el: JQuery + error?: any +} + export default (Commands, Cypress, cy) => { Commands.addAll({ prevSubject: 'element' }, { - // TODO: any -> Partial - select (subject, valueOrTextOrIndex, options: any = {}) { + select (subject, valueOrTextOrIndex, userOptions: Partial = {}) { if ( !_.isNumber(valueOrTextOrIndex) && !_.isString(valueOrTextOrIndex) @@ -28,9 +34,7 @@ export default (Commands, Cypress, cy) => { $errUtils.throwErrByPath('select.invalid_array_argument', { args: { value: JSON.stringify(valueOrTextOrIndex) } }) } - const userOptions = options - - options = _.defaults({}, userOptions, { + const options: InternalSelectOptions = _.defaults({}, userOptions, { $el: subject, log: true, force: false, @@ -55,7 +59,7 @@ export default (Commands, Cypress, cy) => { }, }) - options._log.snapshot('before', { next: 'after' }) + options._log!.snapshot('before', { next: 'after' }) } let node diff --git a/packages/driver/src/cy/commands/actions/submit.ts b/packages/driver/src/cy/commands/actions/submit.ts index cbd61919c931..de2b6e10474a 100644 --- a/packages/driver/src/cy/commands/actions/submit.ts +++ b/packages/driver/src/cy/commands/actions/submit.ts @@ -5,14 +5,17 @@ import $dom from '../../../dom' import $utils from '../../../cypress/utils' import $errUtils from '../../../cypress/error_utils' import $actionability from '../../actionability' +import type { Log } from '../../../cypress/log' + +interface InternalSubmitOptions extends Partial{ + _log?: Log + $el: JQuery +} export default (Commands, Cypress, cy) => { Commands.addAll({ prevSubject: 'element' }, { - // TODO: any -> Partial - submit (subject, options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { + submit (subject: JQuery, userOptions: Partial = {}) { + const options: InternalSubmitOptions = _.defaults({}, userOptions, { log: true, $el: subject, }) @@ -35,7 +38,7 @@ export default (Commands, Cypress, cy) => { }, }) - options._log.snapshot('before', { next: 'after' }) + options._log!.snapshot('before', { next: 'after' }) } if (!options.$el.is('form')) { diff --git a/packages/driver/src/cy/commands/actions/type.ts b/packages/driver/src/cy/commands/actions/type.ts index e131970b38f8..a168ebf88160 100644 --- a/packages/driver/src/cy/commands/actions/type.ts +++ b/packages/driver/src/cy/commands/actions/type.ts @@ -8,23 +8,33 @@ import $utils from '../../../cypress/utils' import $errUtils from '../../../cypress/error_utils' import $actionability from '../../actionability' import $Keyboard from '../../../cy/keyboard' +import type { Log } from '../../../cypress/log' + import debugFn from 'debug' const debug = debugFn('cypress:driver:command:type') +interface InternalTypeOptions extends Partial { + _log?: Log + $el: JQuery + ensure?: object + verify: boolean + interval?: number +} + +interface InternalClearOptions extends Partial { + _log?: Log + ensure?: object +} + export default function (Commands, Cypress, cy, state, config) { const { keyboard } = cy.devices - // Note: These "change type of `any` to X" comments are written instead of changing them directly - // because Cypress extends user-given options with Cypress internal options. - // These comments will be removed after removing `// @ts-nocheck` comments in `packages/driver`. - // TODO: change the type of `any` to `Partial` - function type (subject, chars, options: any = {}) { - const userOptions = options + function type (subject, chars, userOptions: Partial = {}) { let updateTable // allow the el we're typing into to be // changed by options -- used by cy.clear() - options = _.defaults({}, userOptions, { + const options: InternalTypeOptions = _.defaults({}, userOptions, { $el: subject, log: true, verify: true, @@ -110,7 +120,7 @@ export default function (Commands, Cypress, cy, state, config) { }, }) - options._log.snapshot('before', { next: 'after' }) + options._log!.snapshot('before', { next: 'after' }) } if (options.$el.length > 1) { @@ -572,11 +582,8 @@ export default function (Commands, Cypress, cy, state, config) { }) } - // TODO: change the type of `any` to `Partial` - function clear (subject, options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { + function clear (subject, userOptions: Partial = {}) { + const options: InternalClearOptions = _.defaults({}, userOptions, { log: true, force: false, waitForAnimations: config('waitForAnimations'), diff --git a/packages/driver/src/cy/commands/angular.ts b/packages/driver/src/cy/commands/angular.ts index 48661b05d8a2..f6b4bf374979 100644 --- a/packages/driver/src/cy/commands/angular.ts +++ b/packages/driver/src/cy/commands/angular.ts @@ -3,9 +3,14 @@ import $ from 'jquery' import Promise from 'bluebird' import $errUtils from '../../cypress/error_utils' +import type { Log } from '../../cypress/log' const ngPrefixes = ['ng-', 'ng_', 'data-ng-', 'x-ng-'] +interface InternalNgOptions extends Partial { + _log?: Log +} + export default (Commands, Cypress, cy, state) => { const findByNgBinding = (binding, options) => { const selector = '.ng-binding' @@ -89,10 +94,7 @@ export default (Commands, Cypress, cy, state) => { } Commands.addAll({ - // TODO: Change the options type from `any` to `Partial`. - ng (type, selector, options: any = {}) { - const userOptions = options - + ng (type: string, selector: string, userOptions: Partial = {}) { // what about requirejs / browserify? // we need to intelligently check to see if we're using those // and if angular is available through them. throw a very specific @@ -102,7 +104,7 @@ export default (Commands, Cypress, cy, state) => { $errUtils.throwErrByPath('ng.no_global') } - options = _.defaults({}, userOptions, { log: true }) + const options: InternalNgOptions = _.defaults({}, userOptions, { log: true }) if (options.log) { options._log = Cypress.log({ diff --git a/packages/driver/src/cy/commands/clock.ts b/packages/driver/src/cy/commands/clock.ts index aa202fbeff46..6ac0a36bb5a1 100644 --- a/packages/driver/src/cy/commands/clock.ts +++ b/packages/driver/src/cy/commands/clock.ts @@ -42,8 +42,7 @@ export default function (Commands, Cypress, cy, state) { }) return Commands.addAll({ type: 'utility' }, { - // TODO: change the options type from `any` to Partial. - clock (subject, now, methods, options: any = {}) { + clock (subject, now, methods, options: Partial = {}) { let userOptions = options const ctx = state('ctx') diff --git a/packages/driver/src/cy/commands/cookies.ts b/packages/driver/src/cy/commands/cookies.ts index 9002763dc0db..69075312e083 100644 --- a/packages/driver/src/cy/commands/cookies.ts +++ b/packages/driver/src/cy/commands/cookies.ts @@ -3,6 +3,7 @@ import Promise from 'bluebird' import $utils from '../../cypress/utils' import $errUtils from '../../cypress/error_utils' +import type { Log } from '../../cypress/log' import { $Location } from '../../cypress/location' // TODO: add hostOnly to COOKIE_PROPS @@ -78,6 +79,30 @@ function cookieValidatesSecurePrefix (options) { return options.secure === false } +interface InternalGetCookieOptions extends Partial { + _log?: Log + cookie?: Cypress.Cookie +} + +interface InternalGetCookiesOptions extends Partial { + _log?: Log + cookies?: Cypress.Cookie[] +} + +interface InternalSetCookieOptions extends Partial { + _log?: Log + name: string + cookie?: Cypress.Cookie +} + +type InternalClearCookieOptions = InternalGetCookieOptions + +interface InternalClearCookiesOptions extends Partial { + _log?: Log + cookies?: Cypress.Cookie[] + domain?: any +} + export default function (Commands, Cypress, cy, state, config) { const automateCookies = function (event, obj = {}, log, timeout) { const automate = () => { @@ -164,11 +189,8 @@ export default function (Commands, Cypress, cy, state, config) { }) return Commands.addAll({ - // TODO: change the type of `any` to `Partial` - getCookie (name, options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { + getCookie (name, userOptions: Partial = {}) { + const options: InternalGetCookieOptions = _.defaults({}, userOptions, { log: true, timeout: config('responseTimeout'), }) @@ -211,11 +233,8 @@ export default function (Commands, Cypress, cy, state, config) { .catch(handleBackendError('getCookie', 'reading the requested cookie from', onFail)) }, - // TODO: change the type of `any` to `Partial` - getCookies (options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { + getCookies (userOptions: Partial = {}) { + const options: InternalGetCookiesOptions = _.defaults({}, userOptions, { log: true, timeout: config('responseTimeout'), }) @@ -250,11 +269,8 @@ export default function (Commands, Cypress, cy, state, config) { .catch(handleBackendError('getCookies', 'reading cookies from', options._log)) }, - // TODO: change the type of `any` to `Partial` - setCookie (name, value, options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { + setCookie (name, value, userOptions: Partial = {}) { + const options: InternalSetCookieOptions = _.defaults({}, userOptions, { name, value, path: '/', @@ -332,11 +348,8 @@ export default function (Commands, Cypress, cy, state, config) { }).catch(handleBackendError('setCookie', 'setting the requested cookie in', onFail)) }, - // TODO: change the type of `any` to `Partial` - clearCookie (name, options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { + clearCookie (name, userOptions: Partial = {}) { + const options: InternalClearCookieOptions = _.defaults({}, userOptions, { log: true, timeout: config('responseTimeout'), }) @@ -382,11 +395,8 @@ export default function (Commands, Cypress, cy, state, config) { .catch(handleBackendError('clearCookie', 'clearing the requested cookie in', onFail)) }, - // TODO: change the type of `any` to `Partial` - clearCookies (options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { + clearCookies (userOptions: Partial = {}) { + const options: InternalClearCookiesOptions = _.defaults({}, userOptions, { log: true, timeout: config('responseTimeout'), }) @@ -396,12 +406,12 @@ export default function (Commands, Cypress, cy, state, config) { message: '', timeout: options.timeout, consoleProps () { - let c + const c = options.cookies const obj = {} obj['Yielded'] = 'null' - if ((c = options.cookies) && c.length) { + if (c && c.length) { obj['Cleared Cookies'] = c obj['Num Cookies'] = c.length } else { diff --git a/packages/driver/src/cy/commands/debugging.ts b/packages/driver/src/cy/commands/debugging.ts index 6318e904b9ef..8ac152cf0604 100644 --- a/packages/driver/src/cy/commands/debugging.ts +++ b/packages/driver/src/cy/commands/debugging.ts @@ -1,6 +1,7 @@ import _ from 'lodash' import $utils from '../../cypress/utils' +import type { Log } from '../../cypress/log' const resume = (state, resumeAll = true) => { const onResume = state('onResume') @@ -32,6 +33,14 @@ const getNextQueuedCommand = (state, queue) => { return search(state('index')) } +interface InternalPauseOptions extends Partial { + _log?: Log +} + +interface InternalDebugOptions extends Partial { + _log?: Log +} + export default (Commands, Cypress, cy, state, config) => { Cypress.on('resume:next', () => { return resume(state, false) @@ -42,18 +51,15 @@ export default (Commands, Cypress, cy, state, config) => { }) Commands.addAll({ type: 'utility', prevSubject: 'optional' }, { - // TODO: change the options type from `any` to `Loggable`. // pause should indefinitely pause until the user // presses a key or clicks in the UI to continue - pause (subject, options: any = {}) { + pause (subject, userOptions: Partial = {}) { // bail if we're in run mode, unless --headed and --no-exit flags are passed if (!config('isInteractive') && (!config('browser').isHeaded || config('exit'))) { return subject } - const userOptions = options - - options = _.defaults({}, userOptions, { log: true }) + const options: InternalPauseOptions = _.defaults({}, userOptions, { log: true }) if (options.log) { options._log = Cypress.log({ @@ -72,8 +78,8 @@ export default (Commands, Cypress, cy, state, config) => { // pause on the very next one state('onPaused', null) - if (options.log) { - options._log.end() + if (options._log) { + options._log!.end() } } @@ -103,11 +109,8 @@ export default (Commands, Cypress, cy, state, config) => { return subject }, - // TODO: change `any` to Loggable - debug (subject, options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { + debug (subject, userOptions: Partial = {}) { + const options: InternalDebugOptions = _.defaults({}, userOptions, { log: true, }) diff --git a/packages/driver/src/cy/commands/exec.ts b/packages/driver/src/cy/commands/exec.ts index d6114590579f..a0131c604ef1 100644 --- a/packages/driver/src/cy/commands/exec.ts +++ b/packages/driver/src/cy/commands/exec.ts @@ -2,14 +2,17 @@ import _ from 'lodash' import Promise from 'bluebird' import $errUtils from '../../cypress/error_utils' +import type { Log } from '../../cypress/log' + +interface InternalExecOptions extends Partial { + _log?: Log + cmd?: string +} export default (Commands, Cypress, cy) => { Commands.addAll({ - // TODO: change the type of `any` to `Partical` - exec (cmd, options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { + exec (cmd: string, userOptions: Partial = {}) { + const options: InternalExecOptions = _.defaults({}, userOptions, { log: true, timeout: Cypress.config('execTimeout'), failOnNonZeroExit: true, diff --git a/packages/driver/src/cy/commands/files.ts b/packages/driver/src/cy/commands/files.ts index 473bc7b02d80..02512836a209 100644 --- a/packages/driver/src/cy/commands/files.ts +++ b/packages/driver/src/cy/commands/files.ts @@ -2,19 +2,26 @@ import _ from 'lodash' import { basename } from 'path' import $errUtils from '../../cypress/error_utils' +import type { Log } from '../../cypress/log' + +interface InternalReadFileOptions extends Partial { + _log?: Log + encoding: Cypress.Encodings +} + +interface InternalWriteFileOptions extends Partial { + _log?: Log +} export default (Commands, Cypress, cy, state) => { Commands.addAll({ - // TODO: change the type of `any` to `Partial` - readFile (file, encoding, options: any = {}) { - let userOptions = options - + readFile (file, encoding, userOptions: Partial = {}) { if (_.isObject(encoding)) { userOptions = encoding encoding = undefined } - options = _.defaults({}, userOptions, { + const options: InternalReadFileOptions = _.defaults({}, userOptions, { // https://github.com/cypress-io/cypress/issues/1558 // If no encoding is specified, then Cypress has historically defaulted // to `utf8`, because of it's focus on text files. This is in contrast to @@ -109,16 +116,13 @@ export default (Commands, Cypress, cy, state) => { return verifyAssertions() }, - // TODO: change the type of `any` to `Partial` - writeFile (fileName, contents, encoding, options: any = {}) { - let userOptions = options - + writeFile (fileName, contents, encoding, userOptions: Partial = {}) { if (_.isObject(encoding)) { userOptions = encoding encoding = undefined } - options = _.defaults({}, userOptions, { + const options: InternalWriteFileOptions = _.defaults({}, userOptions, { // https://github.com/cypress-io/cypress/issues/1558 // If no encoding is specified, then Cypress has historically defaulted // to `utf8`, because of it's focus on text files. This is in contrast to diff --git a/packages/driver/src/cy/commands/location.ts b/packages/driver/src/cy/commands/location.ts index 837d39b8a3d3..900d12cabca1 100644 --- a/packages/driver/src/cy/commands/location.ts +++ b/packages/driver/src/cy/commands/location.ts @@ -2,15 +2,21 @@ import _ from 'lodash' import Promise from 'bluebird' import $errUtils from '../../cypress/error_utils' +import type { Log } from '../../cypress/log' const { throwErrByPath } = $errUtils +interface InternalUrlOptions extends Partial { + _log?: Log +} + +interface InternalHashOptions extends Partial { + _log?: Log +} + export default (Commands, Cypress, cy) => { Commands.addAll({ - // TODO: change the type of `any` to `Partial` - url (options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { log: true }) + url (userOptions: Partial = {}) { + const options: InternalUrlOptions = _.defaults({}, userOptions, { log: true }) if (options.log !== false) { options._log = Cypress.log({ @@ -38,11 +44,8 @@ export default (Commands, Cypress, cy) => { return resolveHref() }, - // TODO: change the type of `any` to `Partial` - hash (options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { log: true }) + hash (userOptions: Partial = {}) { + const options: InternalHashOptions = _.defaults({}, userOptions, { log: true }) if (options.log !== false) { options._log = Cypress.log({ diff --git a/packages/driver/src/cy/commands/misc.ts b/packages/driver/src/cy/commands/misc.ts index 5a0db7a0f094..54d862663cc6 100644 --- a/packages/driver/src/cy/commands/misc.ts +++ b/packages/driver/src/cy/commands/misc.ts @@ -4,6 +4,12 @@ import Promise from 'bluebird' import $Command from '../../cypress/command' import $dom from '../../dom' import $errUtils from '../../cypress/error_utils' +import type { Log } from '../../cypress/log' + +interface InternalWrapOptions extends Partial { + _log?: Log + timeout: number +} export default (Commands, Cypress, cy, state) => { Commands.addAll({ prevSubject: 'optional' }, { @@ -49,11 +55,8 @@ export default (Commands, Cypress, cy, state) => { return null }, - // TODO: change the type of `any` to `Partial` - wrap (arg, options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { + wrap (arg, userOptions: Partial = {}) { + const options: InternalWrapOptions = _.defaults({}, userOptions, { log: true, timeout: Cypress.config('defaultCommandTimeout'), }) @@ -68,7 +71,7 @@ export default (Commands, Cypress, cy, state) => { }) if ($dom.isElement(arg)) { - options._log.set({ $el: arg }) + options._log!.set({ $el: arg }) } } diff --git a/packages/driver/src/cy/commands/navigation.ts b/packages/driver/src/cy/commands/navigation.ts index 97bbb11359e7..da2a73e2b2d7 100644 --- a/packages/driver/src/cy/commands/navigation.ts +++ b/packages/driver/src/cy/commands/navigation.ts @@ -5,7 +5,7 @@ import Promise from 'bluebird' import $utils from '../../cypress/utils' import $errUtils from '../../cypress/error_utils' -import { LogUtils } from '../../cypress/log' +import { LogUtils, Log } from '../../cypress/log' import { bothUrlsMatchAndOneHasHash } from '../navigation' import { $Location } from '../../cypress/location' @@ -410,6 +410,10 @@ type InvalidContentTypeError = Error & { invalidContentType: boolean } +interface InternalVisitOptions extends Partial { + _log?: Log +} + export default (Commands, Cypress, cy, state, config) => { reset() @@ -693,14 +697,11 @@ export default (Commands, Cypress, cy, state, config) => { return $errUtils.throwErrByPath('go.invalid_argument', { onFail: options._log }) }, - // TODO: Change the type of `any` to `Partial`. - visit (url, options: any = {}) { - if (options.url && url) { - $errUtils.throwErrByPath('visit.no_duplicate_url', { args: { optionsUrl: options.url, url } }) + visit (url, userOptions: Partial = {}) { + if (userOptions.url && url) { + $errUtils.throwErrByPath('visit.no_duplicate_url', { args: { optionsUrl: userOptions.url, url } }) } - let userOptions = options - if (_.isObject(url) && _.isEqual(userOptions, {})) { // options specified as only argument userOptions = url @@ -717,7 +718,7 @@ export default (Commands, Cypress, cy, state, config) => { consoleProps['Options'] = _.pick(userOptions, VISIT_OPTS) } - options = _.defaults({}, userOptions, { + const options: InternalVisitOptions = _.defaults({}, userOptions, { auth: null, failOnStatusCode: true, retryOnNetworkFailure: true, @@ -972,14 +973,14 @@ export default (Commands, Cypress, cy, state, config) => { } } - if (options.log) { - let message = options._log.get('message') + if (options._log) { + let message = options._log!.get('message') if (redirects && redirects.length) { message = [message].concat(redirects).join(' -> ') } - options._log.set({ message }) + options._log!.set({ message }) } consoleProps['Resolved Url'] = url diff --git a/packages/driver/src/cy/commands/querying/focused.ts b/packages/driver/src/cy/commands/querying/focused.ts index 45f67366ae20..c96acf77cc4c 100644 --- a/packages/driver/src/cy/commands/querying/focused.ts +++ b/packages/driver/src/cy/commands/querying/focused.ts @@ -2,14 +2,17 @@ import _ from 'lodash' import Promise from 'bluebird' import $dom from '../../../dom' +import type { Log } from '../../../cypress/log' + +interface InternalFocusedOptions extends Partial{ + _log?: Log + verify: boolean +} export default (Commands, Cypress, cy, state) => { Commands.addAll({ - // TODO: any -> Partial - focused (options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { + focused (userOptions: Partial = {}) { + const options: InternalFocusedOptions = _.defaults({}, userOptions, { verify: true, log: true, }) @@ -23,7 +26,7 @@ export default (Commands, Cypress, cy, state) => { return } - options._log.set({ + options._log!.set({ $el, consoleProps () { const ret = $el ? $dom.getElements($el) : '--nothing--' diff --git a/packages/driver/src/cy/commands/querying/querying.ts b/packages/driver/src/cy/commands/querying/querying.ts index aa80eeb3c268..0c4ffb9f1d93 100644 --- a/packages/driver/src/cy/commands/querying/querying.ts +++ b/packages/driver/src/cy/commands/querying/querying.ts @@ -4,14 +4,25 @@ import Promise from 'bluebird' import $dom from '../../../dom' import $elements from '../../../dom/elements' import $errUtils from '../../../cypress/error_utils' +import type { Log } from '../../../cypress/log' import { resolveShadowDomInclusion } from '../../../cypress/shadow_dom_utils' import { getAliasedRequests, isDynamicAliasingPossible } from '../../net-stubbing/aliasing' +interface InternalGetOptions extends Partial { + _log?: Log + _retries?: number + filter?: any + onRetry?: Function + verify?: boolean +} + +interface InternalContainsOptions extends Partial { + _log?: Log +} + export default (Commands, Cypress, cy, state) => { Commands.addAll({ - // TODO: any -> Partial - get (selector, options: any = {}) { - const userOptions = options + get (selector, userOptions: Partial = {}) { const ctx = this if ((userOptions === null) || _.isArray(userOptions) || !_.isPlainObject(userOptions)) { @@ -20,7 +31,7 @@ export default (Commands, Cypress, cy, state) => { }) } - options = _.defaults({}, userOptions, { + const options: InternalGetOptions = _.defaults({}, userOptions, { retry: true, withinSubject: state('withinSubject'), log: true, @@ -28,7 +39,7 @@ export default (Commands, Cypress, cy, state) => { verify: true, }) - options.includeShadowDom = resolveShadowDomInclusion(Cypress, userOptions.includeShadowDom) + options.includeShadowDom = resolveShadowDomInclusion(Cypress, options.includeShadowDom) let aliasObj const consoleProps: Record = {} @@ -100,7 +111,7 @@ export default (Commands, Cypress, cy, state) => { return consoleProps } - options._log.set(obj) + options._log!.set(obj) } let allParts @@ -263,14 +274,14 @@ export default (Commands, Cypress, cy, state) => { consoleProps.Yielded = $dom.getElements($el) consoleProps.Elements = $el != null ? $el.length : undefined - options._log.set({ $el }) + options._log!.set({ $el }) } const getElements = () => { let $el try { - let scope = options.withinSubject + let scope: (typeof options.withinSubject) | Node[] = options.withinSubject if (options.includeShadowDom) { const root = options.withinSubject ? options.withinSubject[0] : cy.state('document') @@ -295,7 +306,7 @@ export default (Commands, Cypress, cy, state) => { return err } - options._log.error(err) + options._log!.error(err) } throw err @@ -305,7 +316,7 @@ export default (Commands, Cypress, cy, state) => { // and we have been explictly told to filter // then just attempt to filter out elements from our within subject if (!$el.length && options.withinSubject && options.filter) { - const filtered = options.withinSubject.filter(selector) + const filtered = (options.withinSubject as JQuery).filter(selector) // reset $el if this found anything if (filtered.length) { @@ -350,10 +361,7 @@ export default (Commands, Cypress, cy, state) => { }) Commands.addAll({ prevSubject: ['optional', 'window', 'document', 'element'] }, { - // TODO: any -> Partial - contains (subject, filter, text, options: any = {}) { - let userOptions = options - + contains (subject, filter, text, userOptions: Partial = {}) { // nuke our subject if its present but not an element. // in these cases its either window or document but // we dont care. @@ -389,7 +397,7 @@ export default (Commands, Cypress, cy, state) => { $errUtils.throwErrByPath('contains.regex_conflict') } - options = _.defaults({}, userOptions, { log: true, matchCase: true }) + const options: InternalContainsOptions = _.defaults({}, userOptions, { log: true, matchCase: true }) if (!(_.isString(text) || _.isFinite(text) || _.isRegExp(text))) { $errUtils.throwErrByPath('contains.invalid_argument') @@ -459,7 +467,7 @@ export default (Commands, Cypress, cy, state) => { consoleProps.Yielded = $dom.getElements($el) consoleProps.Elements = $el != null ? $el.length : undefined - options._log.set({ $el }) + options._log!.set({ $el }) } // find elements by the :cy-contains psuedo selector diff --git a/packages/driver/src/cy/commands/querying/root.ts b/packages/driver/src/cy/commands/querying/root.ts index 579bc461d31f..6847c9b955e3 100644 --- a/packages/driver/src/cy/commands/querying/root.ts +++ b/packages/driver/src/cy/commands/querying/root.ts @@ -1,12 +1,14 @@ import _ from 'lodash' +import type { Log } from '../../../cypress/log' + +interface InternalRootOptions extends Partial { + _log?: Log +} export default (Commands, Cypress, cy, state) => { Commands.addAll({ - // TODO: any -> Partial - root (options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { log: true }) + root (userOptions: Partial = {}) { + const options: InternalRootOptions = _.defaults({}, userOptions, { log: true }) if (options.log !== false) { options._log = Cypress.log({ @@ -16,8 +18,8 @@ export default (Commands, Cypress, cy, state) => { } const log = ($el) => { - if (options.log) { - options._log.set({ $el }) + if (options._log) { + options._log!.set({ $el }) } return $el diff --git a/packages/driver/src/cy/commands/screenshot.ts b/packages/driver/src/cy/commands/screenshot.ts index 53987c587c0b..585cd08639e8 100644 --- a/packages/driver/src/cy/commands/screenshot.ts +++ b/packages/driver/src/cy/commands/screenshot.ts @@ -8,6 +8,7 @@ import $Screenshot from '../../cypress/screenshot' import $dom from '../../dom' import $errUtils from '../../cypress/error_utils' import $utils from '../../cypress/utils' +import type { Log } from '../../cypress/log' const getViewportHeight = (state) => { // TODO this doesn't seem correct @@ -410,6 +411,10 @@ const takeScreenshot = (Cypress, state, screenshotConfig, options: TakeScreensho .finally(after) } +interface InternalScreenshotOptions extends Partial { + _log?: Log +} + export default function (Commands, Cypress, cy, state, config) { // failure screenshot when not interactive Cypress.on('runnable:after:run:async', (test, runnable) => { @@ -440,10 +445,7 @@ export default function (Commands, Cypress, cy, state, config) { }) Commands.addAll({ prevSubject: ['optional', 'element', 'window', 'document'] }, { - // TODO: any -> Partial - screenshot (subject, name, options: any = {}) { - let userOptions = options - + screenshot (subject, name, userOptions: Partial = {}) { if (_.isObject(name)) { userOptions = name name = null @@ -452,7 +454,7 @@ export default function (Commands, Cypress, cy, state, config) { // make sure when we capture the entire test runner // we are not limited to "within" subject // https://github.com/cypress-io/cypress/issues/14253 - if (options.capture !== 'runner') { + if (userOptions.capture !== 'runner') { const withinSubject = state('withinSubject') if (withinSubject && $dom.isElement(withinSubject)) { @@ -463,7 +465,7 @@ export default function (Commands, Cypress, cy, state, config) { // TODO: handle hook titles const runnable = state('runnable') - options = _.defaults({}, userOptions, { + const options: InternalScreenshotOptions = _.defaults({}, userOptions, { log: true, timeout: config('responseTimeout'), }) diff --git a/packages/driver/src/cy/commands/task.ts b/packages/driver/src/cy/commands/task.ts index ff07b7bf8d7e..7223b95084e7 100644 --- a/packages/driver/src/cy/commands/task.ts +++ b/packages/driver/src/cy/commands/task.ts @@ -4,14 +4,16 @@ import Promise from 'bluebird' import $utils from '../../cypress/utils' import $errUtils from '../../cypress/error_utils' import $stackUtils from '../../cypress/stack_utils' +import type { Log } from '../../cypress/log' + +interface InternalTaskOptions extends Partial { + _log?: Log +} export default (Commands, Cypress, cy) => { Commands.addAll({ - // TODO: any -> Partial - task (task, arg, options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { + task (task, arg, userOptions: Partial = {}) { + const options: InternalTaskOptions = _.defaults({}, userOptions, { log: true, timeout: Cypress.config('taskTimeout'), }) diff --git a/packages/driver/src/cy/commands/window.ts b/packages/driver/src/cy/commands/window.ts index a4005d888443..908e81189a25 100644 --- a/packages/driver/src/cy/commands/window.ts +++ b/packages/driver/src/cy/commands/window.ts @@ -2,6 +2,7 @@ import _ from 'lodash' import Promise from 'bluebird' import $errUtils from '../../cypress/error_utils' +import type { Log } from '../../cypress/log' const viewports = { 'macbook-16': '1536x960', @@ -35,6 +36,24 @@ type CurrentViewport = Pick // refresh would cause viewport to hang let currentViewport: CurrentViewport | null = null +interface InternalTitleOptions extends Partial { + _log?: Log +} + +interface InternalWindowOptions extends Partial { + _log?: Log + error?: any +} + +interface InternalDocumentOptions extends Partial { + _log?: Log + error?: any +} + +interface InternalViewportOptions extends Partial { + _log?: Log +} + export default (Commands, Cypress, cy, state) => { const defaultViewport: CurrentViewport = _.pick(Cypress.config() as Cypress.Config, 'viewportWidth', 'viewportHeight') @@ -78,11 +97,8 @@ export default (Commands, Cypress, cy, state) => { } Commands.addAll({ - // TODO: any -> Partial - title (options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { log: true }) + title (userOptions: Partial = {}) { + const options: InternalTitleOptions = _.defaults({}, userOptions, { log: true }) if (options.log) { options._log = Cypress.log({ timeout: options.timeout }) @@ -101,11 +117,8 @@ export default (Commands, Cypress, cy, state) => { return resolveTitle() }, - // TODO: any -> Partial - window (options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { log: true }) + window (userOptions: Partial = {}) { + const options: InternalWindowOptions = _.defaults({}, userOptions, { log: true }) if (options.log) { options._log = Cypress.log({ timeout: options.timeout }) @@ -144,11 +157,8 @@ export default (Commands, Cypress, cy, state) => { return verifyAssertions() }, - // TODO: any -> Partial - document (options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { log: true }) + document (userOptions: Partial = {}) { + const options: InternalDocumentOptions = _.defaults({}, userOptions, { log: true }) if (options.log) { options._log = Cypress.log({ timeout: options.timeout }) @@ -188,15 +198,12 @@ export default (Commands, Cypress, cy, state) => { return verifyAssertions() }, - // TODO: any -> Partial - viewport (presetOrWidth, heightOrOrientation, options: any = {}) { - const userOptions = options - + viewport (presetOrWidth, heightOrOrientation, userOptions: Partial = {}) { if (_.isObject(heightOrOrientation)) { - options = heightOrOrientation + userOptions = heightOrOrientation } - options = _.defaults({}, userOptions, { log: true }) + const options: InternalViewportOptions = _.defaults({}, userOptions, { log: true }) let height let width @@ -208,10 +215,6 @@ export default (Commands, Cypress, cy, state) => { const isPreset = typeof presetOrWidth === 'string' options._log = Cypress.log({ - // TODO: timeout below should be removed - // because cy.viewport option doesn't support `timeout` - // @see https://docs.cypress.io/api/commands/viewport#Arguments - timeout: options.timeout, consoleProps () { const obj: Record = {} diff --git a/packages/driver/src/cy/keyboard.ts b/packages/driver/src/cy/keyboard.ts index f03306b6fa21..c44791ce2fc3 100644 --- a/packages/driver/src/cy/keyboard.ts +++ b/packages/driver/src/cy/keyboard.ts @@ -12,6 +12,7 @@ import type { HTMLTextLikeElement } from '../dom/elements' import $selection from '../dom/selection' import $utils from '../cypress/utils' import $window from '../dom/window' +import type { Log } from '../cypress/log' const debug = Debug('cypress:driver:keyboard') @@ -680,7 +681,7 @@ export interface typeOptions { force?: boolean simulated?: boolean release?: boolean - _log?: any + _log?: Log delay?: number onError?: Function onEvent?: Function diff --git a/packages/driver/src/cy/video-recorder.ts b/packages/driver/src/cy/video-recorder.ts index 980d4aa75e7b..008d4cb6c8d4 100644 --- a/packages/driver/src/cy/video-recorder.ts +++ b/packages/driver/src/cy/video-recorder.ts @@ -24,8 +24,6 @@ export const initVideoRecorder = (Cypress) => { mimeType: 'video/webm', } - // TODO: update TypeScript to 4.4+. - // @ts-ignore const mediaRecorder = new window.MediaRecorder(stream, options) mediaRecorder.start(200) diff --git a/packages/driver/src/cypress/browser.ts b/packages/driver/src/cypress/browser.ts index 559d74843496..a3d188955c06 100644 --- a/packages/driver/src/cypress/browser.ts +++ b/packages/driver/src/cypress/browser.ts @@ -35,8 +35,7 @@ const _isBrowser = (browser, matcher, errPrefix) => { } } -// TODO: change the type of `any` to `IsBrowserMatcher` -const isBrowser = (config, obj: any = '', errPrefix: string = '`Cypress.isBrowser()`') => { +const isBrowser = (config, obj: Cypress.IsBrowserMatcher = '', errPrefix: string = '`Cypress.isBrowser()`') => { return _ .chain(obj) .concat([]) diff --git a/packages/driver/src/cypress/log.ts b/packages/driver/src/cypress/log.ts index 88ec76a1a60a..9418a200bb6a 100644 --- a/packages/driver/src/cypress/log.ts +++ b/packages/driver/src/cypress/log.ts @@ -219,7 +219,7 @@ const defaults = function (state: Cypress.State, config, obj) { return obj } -class Log { +export class Log { cy: any state: Cypress.State config: any diff --git a/patches/@types+jquery.scrollto+1.4.29.dev.patch b/patches/@types+jquery.scrollto+1.4.29.dev.patch new file mode 100644 index 000000000000..8c79239f7a1c --- /dev/null +++ b/patches/@types+jquery.scrollto+1.4.29.dev.patch @@ -0,0 +1,58 @@ +diff --git a/node_modules/@types/jquery.scrollto/index.d.ts b/node_modules/@types/jquery.scrollto/index.d.ts +index 0a00c69..126a3d0 100755 +--- a/node_modules/@types/jquery.scrollto/index.d.ts ++++ b/node_modules/@types/jquery.scrollto/index.d.ts +@@ -6,7 +6,7 @@ + + /// + +-interface ScrollToOptions { ++interface JQueryScrollToOptions extends JQuery.EffectsOptions { + /** + * Which axis must be scrolled, use 'x', 'y', 'xy' or 'yx'. + */ +@@ -48,7 +48,7 @@ interface ScrollToOptions { + onAfterFirst?: (() => void) | undefined; + } + +-interface JQuery { ++interface JQuery { + /** + * Scroll the matched elements + */ +@@ -60,7 +60,7 @@ interface JQuery { + * @param duration The OVERALL length of the animation + * @param settings Set of settings. + */ +- (target: any, duration?: number, settings?: ScrollToOptions): JQuery; ++ (target: any, duration?: number, settings?: JQueryScrollToOptions): JQuery; + /** + * Scroll the matched elements + * +@@ -76,7 +76,7 @@ interface JQuery { + * @param settings Set of settings. + * @param onAfter The onAfter callback. + */ +- (target: any, settings: ScrollToOptions, onAfter?: Function): JQuery; ++ (target: any, settings: JQueryScrollToOptions, onAfter?: Function): JQuery; + + }; + +@@ -94,7 +94,7 @@ interface JQueryStatic { + * @param duration The OVERALL length of the animation + * @param settings Set of settings. + */ +- (target: any, duration?: number, settings?: ScrollToOptions): JQuery; ++ (target: any, duration?: number, settings?: JQueryScrollToOptions): JQuery; + /** + * Scroll window + * +@@ -110,7 +110,7 @@ interface JQueryStatic { + * @param settings Set of settings. + * @param onAfter The onAfter callback. + */ +- (target: any, settings: ScrollToOptions, onAfter?: Function): JQuery; ++ (target: any, settings: JQueryScrollToOptions, onAfter?: Function): JQuery; + + }; + From a1101e65629db7b39efd9aff5a62b8ad927edebd Mon Sep 17 00:00:00 2001 From: Bill Glesias Date: Fri, 22 Apr 2022 10:30:40 -0400 Subject: [PATCH 16/16] feat: support snapshots and console props within multi-domain (#20949) * Empty commit to get a new percy nonce * Implement snapshots and consoleprops within multi origin further progress with getters cleaned up log/snapshot serialization attempt to pass and hydrate value state of serialized dom elements temp commit traversal dom by some stretch of a miracle this is working... still somehow working after massive performance issues with full tree serialization, fix here is to just attach values to inputs for reifying on primary now we are cookin test WIP tests WIP working multi-domain actions snapshots tests added more tests to verify snapshots add tests and refactor certain tests to make simpler added misc snapshot tests add navigation snapshot placeholder add network request snapshot tests add shadow querying snapshot tests update test names added snapshot querying spec added screenshot snapshot test add spies,clocks, and stubs tests implement snapshot tests for traversal commands rename local storeage snapshot tests to fit convention add viewport snapshot tests rename snapshot traversal to fit naming convention add snapshot waiting tests added window snapshot tests implement navigation snapshot tests now that sinon proxy issues internal to log are now fixed refactor multi-domain snapshot tests to leverage utility method over redefining in each spec * fix lint types issues on serializationKeys * rename switchToDomain to origin (might help with failing tests... ya know?) * rename snapshot files to fit origin paradigm and fix misname on primaryDomainCommunicator * fix .tick() snapshot/consoleProps test (figure out the deal with consoleProps sometimes being a function) * rename multiDomainCommunicator to origin primaryDomainCommunicator * don't invoke functions with arguments (we need to be more explicit about the functions we are invoking * opt for my explicit serialization behavior with functions, never attempt to serialize bluebird promises * move serialization to folder and change name to index * refactor log serialization to own file, clean up code and add comments to what is going on in this 'here be dragons' code * make sure to serialize functions for snapshots * fix pause snapshot test for multi origin * refactor postprocess snapshot into own method to handle in final state snapshot processing for cross origin * update snapshot comments to be more accurate * fix renamings within tests * fix path in log.ts serialization * revert about:blank changes in aut-iframe which was breaking session * move all log/snapshot serialization magic invokations into the communicator * update typos and fix namings of preprocess and reify * further name changes * fix snapshot generator to always reify snapshot () over attempting to match in the DOM * unskip test that was fixed with explicit function serialization for logs * fix flaky screenshot test that was screensize dependent * rename a few items in the log serialization file * clean up snapshot style reification to be more straightforward and remove redundancies * refactor snapshots code to be more readable * update reifyDomElement docs to actually explain what hte method does * fix typos within the log serialization file pertaining to comments * use Cypress._ over lodash import to reduce spec bundle size * remove snapshots test folder and migrate tests into commands directory with #consoleProps context blocks for each * change removeSrcAttributeFromAUTIframe name to removeSrcAttribute as it is implied on the AUT * update log consoleProps comment to better reflect cross origin nature * remove skipped consoleProps tests that do not have a command log to test against * add createSnapshot to internal types (might need more specifics on this) * refactor multi-domain consoleProp tests to use shouldWithTimeout custom command to avoid setTimeouts on command queue event to make test implementation cleaner * simplify DOM hydration for input based elements * update preprocessedHTMLElement type * clean up some documentation and remove TS ignores. added getStyles to internal-types. * add comment to aut-iframe on src attr removal for posterity * reverse snapshot ternary for readability * add shouldWithTimeout into spec-types and refactor out of internal-types * add getAll type to cypress spec-types * compare originPolicy of top and AUT instead of just origin to make snapshots work in subdomains * add comment to _storeOriginalState for future developers and to add clarity * add some basic log serialization tests that show full pre/reification of log, as well as state hydration for innerHTML. break out object/array methods from log like serialization into own methods * update variables to metasyntactic * add renderProps assertion for cy.request * apply suggestions from code review to clean up log serializer * make snapshot serialization more generic and typesafe * work around firefox 93 issues by unsetting the document in cy state as the document is in a cross origin context in the primary, which means accessing any elements will not work * clean up code and implement suggestions in code review * remove crossOriginLog in favor of nullish coalescing if visible on the log is not set * if get is null, return null for whole snapshot Co-authored-by: Ryan Manuel Co-authored-by: Matt Henkes --- packages/driver/cypress/fixtures/dom.html | 4 +- .../commands/multi_domain_actions.spec.ts | 621 ++++++++++++++++ .../commands/multi_domain_aliasing.spec.ts | 37 + .../commands/multi_domain_assertions.spec.ts | 43 ++ .../commands/multi_domain_connectors.spec.ts | 73 ++ .../commands/multi_domain_cookies.spec.ts | 140 ++++ .../commands/multi_domain_files.spec.ts | 49 ++ .../multi_domain_local_storage.spec.ts | 32 + .../commands/multi_domain_location.spec.ts | 66 ++ .../commands/multi_domain_misc.spec.ts | 140 +++- .../commands/multi_domain_navigation.spec.ts | 75 ++ .../multi_domain_network_requests.spec.ts | 41 ++ .../commands/multi_domain_querying.spec.ts | 72 ++ .../multi_domain_querying_shadow.spec.ts | 38 + .../commands/multi_domain_screenshot.spec.ts | 43 ++ .../multi_domain_spies_stubs_clocks.spec.ts | 99 +++ .../commands/multi_domain_traversal.spec.ts | 529 ++++++++++++++ .../commands/multi_domain_viewport.spec.ts | 28 + .../commands/multi_domain_waiting.spec.ts | 27 + .../commands/multi_domain_window.spec.ts | 53 ++ .../integration/util/serialization_spec.ts | 688 ++++++++++++++++++ packages/driver/cypress/support/utils.js | 20 + packages/driver/src/cy/snapshots.ts | 193 +++-- packages/driver/src/cypress/log.ts | 7 +- .../driver/src/multi-domain/communicator.ts | 26 +- packages/driver/src/multi-domain/cypress.ts | 14 + .../driver/src/multi-domain/events/logs.ts | 6 +- .../index.ts} | 15 +- packages/driver/src/util/serialization/log.ts | 425 +++++++++++ packages/driver/types/internal-types.d.ts | 2 + packages/driver/types/spec-types.d.ts | 8 + packages/runner-ct/src/iframe/iframes.tsx | 2 + packages/runner-shared/src/event-manager.js | 3 + .../runner-shared/src/iframe/aut-iframe.js | 51 ++ .../runner-shared/src/iframe/iframe-model.js | 29 +- packages/runner/index.d.ts | 1 + packages/runner/src/iframe/iframes.jsx | 2 + 37 files changed, 3621 insertions(+), 81 deletions(-) create mode 100644 packages/driver/cypress/integration/util/serialization_spec.ts rename packages/driver/src/util/{serialization.ts => serialization/index.ts} (91%) create mode 100644 packages/driver/src/util/serialization/log.ts create mode 100644 packages/driver/types/spec-types.d.ts diff --git a/packages/driver/cypress/fixtures/dom.html b/packages/driver/cypress/fixtures/dom.html index 1d3e241f2a46..6347924ceccf 100644 --- a/packages/driver/cypress/fixtures/dom.html +++ b/packages/driver/cypress/fixtures/dom.html @@ -437,8 +437,8 @@ not to be checked') + expect(assertionLogs[1].consoleProps.Message).to.equal('expected not to be disabled') + + assertionLogs.forEach(({ $el, consoleProps }) => { + expect($el.jquery).to.be.ok + + expect(consoleProps.Command).to.equal('assert') + expect(consoleProps.subject[0]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.subject[0]).to.have.property('value').that.equals('blue') + expect(consoleProps.subject[0].getAttribute('name')).to.equal('colors') + }) + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_connectors.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_connectors.spec.ts index 732ce983827e..6b94fc87c3a8 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_connectors.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_connectors.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin connectors', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -43,4 +45,75 @@ context('cy.origin connectors', () => { }) }) }) + + context('#consoleProps', () => { + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.its()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-id>input').its('length') + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps, $el } = findCrossOriginLogs('its', logs, 'foobar.com') + + expect($el.jquery).to.be.ok + + expect(consoleProps.Command).to.equal('its') + expect(consoleProps.Property).to.equal('.length') + expect(consoleProps.Yielded).to.equal(3) + + expect(consoleProps.Subject.length).to.equal(3) + + // make sure subject elements are indexed in the correct order + expect(consoleProps.Subject[0]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Subject[0]).to.have.property('id').that.equals('input') + + expect(consoleProps.Subject[1]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Subject[1]).to.have.property('id').that.equals('name') + + expect(consoleProps.Subject[2]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Subject[2]).to.have.property('id').that.equals('age') + }) + }) + + it('.invoke()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#button').invoke('text') + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps, $el } = findCrossOriginLogs('invoke', logs, 'foobar.com') + + expect($el.jquery).to.be.ok + + expect(consoleProps.Command).to.equal('invoke') + expect(consoleProps.Function).to.equal('.text()') + expect(consoleProps.Yielded).to.equal('button') + + expect(consoleProps.Subject).to.have.property('tagName').that.equals('BUTTON') + expect(consoleProps.Subject).to.have.property('id').that.equals('button') + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_cookies.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_cookies.spec.ts index b068abb275db..ce088c50c29a 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_cookies.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_cookies.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin cookies', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -34,4 +36,142 @@ context('cy.origin cookies', () => { cy.getCookies().should('be.empty') }) }) + + context('#consoleProps', () => { + const { _ } = Cypress + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.getCookie()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.getCookies().should('be.empty') + cy.setCookie('foo', 'bar') + cy.getCookie('foo') + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('getCookie', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('getCookie') + expect(consoleProps.Yielded).to.have.property('domain').that.includes('foobar.com') + expect(consoleProps.Yielded).to.have.property('expiry').that.is.a('number') + expect(consoleProps.Yielded).to.have.property('httpOnly').that.equals(false) + expect(consoleProps.Yielded).to.have.property('secure').that.equals(false) + expect(consoleProps.Yielded).to.have.property('name').that.equals('foo') + expect(consoleProps.Yielded).to.have.property('value').that.equals('bar') + expect(consoleProps.Yielded).to.have.property('path').that.is.a('string') + }) + }) + + it('.getCookies()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.getCookies().should('be.empty') + + cy.setCookie('foo', 'bar') + cy.getCookies() + }) + + cy.shouldWithTimeout(() => { + // get the last 'getCookies' command, which is the one we care about for this test + const allGetCookieLogs = findCrossOriginLogs('getCookies', logs, 'foobar.com') + + const { consoleProps } = allGetCookieLogs.pop() as any + + expect(consoleProps.Command).to.equal('getCookies') + expect(consoleProps['Num Cookies']).to.equal(1) + + // can't exactly assert on length() as this is a array proxy object + expect(consoleProps.Yielded.length).to.equal(1) + expect(consoleProps.Yielded[0]).to.have.property('expiry').that.is.a('number') + expect(consoleProps.Yielded[0]).to.have.property('httpOnly').that.equals(false) + expect(consoleProps.Yielded[0]).to.have.property('secure').that.equals(false) + expect(consoleProps.Yielded[0]).to.have.property('name').that.equals('foo') + expect(consoleProps.Yielded[0]).to.have.property('value').that.equals('bar') + expect(consoleProps.Yielded[0]).to.have.property('path').that.is.a('string') + }) + }) + + it('.setCookie()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.getCookies().should('be.empty') + + cy.setCookie('foo', 'bar') + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('setCookie', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('setCookie') + expect(consoleProps.Yielded).to.have.property('domain').that.includes('foobar.com') + expect(consoleProps.Yielded).to.have.property('expiry').that.is.a('number') + expect(consoleProps.Yielded).to.have.property('httpOnly').that.equals(false) + expect(consoleProps.Yielded).to.have.property('secure').that.equals(false) + expect(consoleProps.Yielded).to.have.property('name').that.equals('foo') + expect(consoleProps.Yielded).to.have.property('value').that.equals('bar') + expect(consoleProps.Yielded).to.have.property('path').that.is.a('string') + }) + }) + + it('.clearCookie()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.setCookie('foo', 'bar') + cy.getCookie('foo').should('not.be.null') + cy.clearCookie('foo') + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('clearCookie', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('clearCookie') + expect(consoleProps.Yielded).to.equal('null') + expect(consoleProps['Cleared Cookie']).to.have.property('domain').that.includes('foobar.com') + expect(consoleProps['Cleared Cookie']).to.have.property('expiry').that.is.a('number') + expect(consoleProps['Cleared Cookie']).to.have.property('httpOnly').that.equals(false) + expect(consoleProps['Cleared Cookie']).to.have.property('secure').that.equals(false) + expect(consoleProps['Cleared Cookie']).to.have.property('name').that.equals('foo') + expect(consoleProps['Cleared Cookie']).to.have.property('value').that.equals('bar') + expect(consoleProps['Cleared Cookie']).to.have.property('path').that.is.a('string') + }) + }) + + it('.clearCookies()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.setCookie('foo', 'bar') + cy.setCookie('faz', 'baz') + + cy.getCookies().should('have.length', 2) + cy.clearCookies() + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('clearCookies', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('clearCookies') + expect(consoleProps['Num Cookies']).to.equal(2) + + expect(consoleProps.Yielded).to.equal('null') + + expect(consoleProps['Cleared Cookies'].length).to.equal(2) + + expect(consoleProps['Cleared Cookies'][0]).to.have.property('name').that.equals('foo') + expect(consoleProps['Cleared Cookies'][0]).to.have.property('value').that.equals('bar') + + expect(consoleProps['Cleared Cookies'][1]).to.have.property('name').that.equals('faz') + expect(consoleProps['Cleared Cookies'][1]).to.have.property('value').that.equals('baz') + + _.forEach(consoleProps['Cleared Cookies'], (clearedCookie) => { + expect(clearedCookie).to.have.property('httpOnly').that.equals(false) + expect(clearedCookie).to.have.property('secure').that.equals(false) + expect(clearedCookie).to.have.property('path').that.is.a('string') + }) + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_files.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_files.spec.ts index 611bcf83cdda..b741e55e2ac6 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_files.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_files.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin files', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -44,4 +46,51 @@ context('cy.origin files', () => { }) }) }) + + context('#consoleProps', () => { + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.readFile()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.readFile('cypress/fixtures/example.json') + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('readFile', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('readFile') + expect(consoleProps['File Path']).to.include('cypress/fixtures/example.json') + expect(consoleProps.Contents).to.deep.equal({ example: true }) + }) + }) + + it('.writeFile()', () => { + cy.origin('http://foobar.com:3500', () => { + const contents = JSON.stringify({ foo: 'bar' }) + + cy.stub(Cypress, 'backend').resolves({ + contents, + filePath: 'foo.json', + }) + + cy.writeFile('foo.json', contents) + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('writeFile', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('writeFile') + expect(consoleProps['File Path']).to.equal('foo.json') + expect(consoleProps.Contents).to.equal('{"foo":"bar"}') + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_local_storage.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_local_storage.spec.ts index 7996d9aed2d9..4ca617ef20d3 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_local_storage.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_local_storage.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin local storage', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -17,4 +19,34 @@ context('cy.origin local storage', () => { }) }) }) + + context('#consoleProps', () => { + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.clearLocalStorage()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.window().then((win) => { + win.localStorage.setItem('foo', 'bar') + expect(win.localStorage.getItem('foo')).to.equal('bar') + }) + + cy.clearLocalStorage() + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('clearLocalStorage', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('clearLocalStorage') + expect(consoleProps.Yielded).to.be.null + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_location.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_location.spec.ts index ba4b9a9b5b6e..cb920a1daa55 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_location.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_location.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin location', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -24,4 +26,68 @@ context('cy.origin location', () => { cy.url().should('equal', 'http://www.foobar.com:3500/fixtures/multi-domain-secondary.html') }) }) + + context('#consoleProps', () => { + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.hash()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.hash() + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('hash', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('hash') + }) + }) + + it('.location()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.location() + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('location', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('location') + + expect(consoleProps.Yielded).to.have.property('auth').that.is.a('string') + expect(consoleProps.Yielded).to.have.property('authObj').that.is.undefined + expect(consoleProps.Yielded).to.have.property('hash').that.is.a('string') + expect(consoleProps.Yielded).to.have.property('host').that.is.a('string') + expect(consoleProps.Yielded).to.have.property('hostname').that.is.a('string') + expect(consoleProps.Yielded).to.have.property('href').that.is.a('string') + expect(consoleProps.Yielded).to.have.property('origin').that.is.a('string') + expect(consoleProps.Yielded).to.have.property('originPolicy').that.is.a('string') + expect(consoleProps.Yielded).to.have.property('pathname').that.is.a('string') + expect(consoleProps.Yielded).to.have.property('port').that.is.a('string') + expect(consoleProps.Yielded).to.have.property('protocol').that.is.a('string') + expect(consoleProps.Yielded).to.have.property('search').that.is.a('string') + expect(consoleProps.Yielded).to.have.property('superDomain').that.is.a('string') + }) + }) + + it('.url()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.url() + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('url', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('url') + + expect(consoleProps.Yielded).to.equal('http://www.foobar.com:3500/fixtures/multi-domain-secondary.html') + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_misc.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_misc.spec.ts index beca1cf6cf05..0b5c075c23d8 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_misc.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_misc.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin misc', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -56,12 +58,146 @@ context('cy.origin misc', () => { cy.task('return:arg', 'works').should('eq', 'works') }) }) + + context('#consoleProps', () => { + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.exec()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.exec('echo foobar') + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('exec', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('exec') + expect(consoleProps['Shell Used']).to.be.undefined + expect(consoleProps.Yielded).to.have.property('code').that.equals(0) + expect(consoleProps.Yielded).to.have.property('stderr').that.equals('') + expect(consoleProps.Yielded).to.have.property('stdout').that.equals('foobar') + }) + }) + + it('.focused()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#button').click().focused() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('focused', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('focused') + expect(consoleProps.Elements).to.equal(1) + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('BUTTON') + expect(consoleProps.Yielded).to.have.property('id').that.equals('button') + }) + }) + + it('.wrap()', () => { + cy.origin('http://foobar.com:3500', () => { + const arr = ['foo', 'bar', 'baz'] + + cy.wrap(arr).spread((foo, bar, baz) => { + expect(foo).to.equal('foo') + expect(bar).to.equal('bar') + expect(baz).to.equal('baz') + }) + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('wrap', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('wrap') + expect(consoleProps.Yielded[0]).to.equal('foo') + expect(consoleProps.Yielded[1]).to.equal('bar') + expect(consoleProps.Yielded[2]).to.equal('baz') + }) + }) + + it('.debug()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#button').debug() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('debug', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('debug') + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('BUTTON') + expect(consoleProps.Yielded).to.have.property('id').that.equals('button') + }) + }) + + it('.pause()', () => { + cy.origin('http://foobar.com:3500', () => { + const afterPaused = new Promise((resolve) => { + cy.once('paused', () => { + Cypress.emit('resume:all') + resolve() + }) + }) + + cy.pause().wrap({}).should('deep.eq', {}) + // pause is a noop in run mode, so only wait for it if in open mode + if (Cypress.config('isInteractive')) { + cy.wrap(afterPaused) + } + }) + + cy.shouldWithTimeout(() => { + if (Cypress.config('isInteractive')) { + // if `isInteractive`, the .pause() will NOT show up in the command log in this case. Essentially a no-op. + return + } + + const { consoleProps } = findCrossOriginLogs('pause', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('pause') + expect(consoleProps.Yielded).to.be.undefined + }) + }) + + it('.task()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.task('return:arg', 'works') + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('task', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('task') + expect(consoleProps.Yielded).to.equal('works') + expect(consoleProps.arg).to.equal('works') + expect(consoleProps.task).to.equal('return:arg') + }) + }) + }) }) it('verifies number of cy commands', () => { // @ts-ignore - // remove 'getAll' command since it's a custom command we add for our own testing and not an actual cy command - const actualCommands = Cypress._.reject(Object.keys(cy.commandFns), (command) => command === 'getAll') + // remove 'getAll' and 'shouldWithTimeout' commands since they are custom commands we added for our own testing and are not actual cy commands + const actualCommands = Cypress._.reject(Object.keys(cy.commandFns), (command) => command === 'getAll' || command === 'shouldWithTimeout') const expectedCommands = [ 'check', 'uncheck', 'click', 'dblclick', 'rightclick', 'focus', 'blur', 'hover', 'scrollIntoView', 'scrollTo', 'select', 'selectFile', 'submit', 'type', 'clear', 'trigger', 'as', 'ng', 'should', 'and', 'clock', 'tick', 'spread', 'each', 'then', diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_navigation.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_navigation.spec.ts index e6bc322cdb45..bc95ec846cc6 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_navigation.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_navigation.spec.ts @@ -1,4 +1,5 @@ const { stripIndent } = require('common-tags') +import { findCrossOriginLogs } from '../../../../support/utils' context('cy.origin navigation', () => { it('.go()', () => { @@ -496,4 +497,78 @@ context('cy.origin navigation', () => { cy.location('pathname').should('equal', '/fixtures/dom.html') }) }) + + context('#consoleProps', () => { + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.go()', () => { + cy.visit('/fixtures/multi-domain.html') + cy.get('a[data-cy="cross-origin-secondary-link"]').click() + + cy.origin('http://foobar.com:3500', () => { + cy.visit('http://www.foobar.com:3500/fixtures/dom.html') + + cy.go('back') + }) + + cy.shouldWithTimeout(() => { + const { consoleProps, ...attrs } = findCrossOriginLogs('go', logs, 'foobar.com') + + expect(attrs.name).to.equal('go') + expect(attrs.message).to.equal('back') + + expect(consoleProps.Command).to.equal('go') + expect(consoleProps.Yielded).to.be.null + }) + }) + + it('.reload()', () => { + cy.visit('/fixtures/multi-domain.html') + cy.get('a[data-cy="dom-link"]').click() + + cy.origin('http://foobar.com:3500', () => { + cy.reload() + }) + + cy.shouldWithTimeout(() => { + const { consoleProps, ...attrs } = findCrossOriginLogs('reload', logs, 'foobar.com') + + expect(attrs.name).to.equal('reload') + expect(attrs.message).to.equal('') + + expect(consoleProps.Command).to.equal('reload') + expect(consoleProps.Yielded).to.be.null + }) + }) + + it('visit()', () => { + cy.visit('/fixtures/multi-domain.html') + + cy.origin('http://foobar.com:3500', () => { + cy.visit('http://www.foobar.com:3500/fixtures/multi-domain-secondary.html') + + cy.get('[data-cy="dom-check"]').should('have.text', 'From a secondary origin') + }) + + cy.shouldWithTimeout(() => { + const { consoleProps, ...attrs } = findCrossOriginLogs('visit', logs, 'foobar.com') + + expect(attrs.name).to.equal('visit') + expect(attrs.message).to.equal('http://www.foobar.com:3500/fixtures/multi-domain-secondary.html') + + expect(consoleProps.Command).to.equal('visit') + expect(consoleProps).to.have.property('Cookies Set').that.is.an('object') + expect(consoleProps).to.have.property('Redirects').that.is.an('object') + expect(consoleProps).to.have.property('Resolved Url').that.equals('http://www.foobar.com:3500/fixtures/multi-domain-secondary.html') + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_network_requests.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_network_requests.spec.ts index 1afecedf3cb8..dfe3e7f3df52 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_network_requests.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_network_requests.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin network requests', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -30,4 +32,43 @@ context('cy.origin network requests', () => { }) }) }) + + context('#consoleProps', () => { + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.request()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.request('http://www.foobar.com:3500/fixtures/example.json') + }) + + cy.shouldWithTimeout(() => { + const { consoleProps, renderProps } = findCrossOriginLogs('request', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('request') + + expect(consoleProps.Request).to.have.property('Request Body').that.equals(null) + expect(consoleProps.Request).to.have.property('Request Headers').that.is.a('object') + expect(consoleProps.Request).to.have.property('Request URL').that.equals('http://www.foobar.com:3500/fixtures/example.json') + expect(consoleProps.Request).to.have.property('Response Body').that.is.a('string') + expect(consoleProps.Request).to.have.property('Response Headers').that.is.a('object') + expect(consoleProps.Request).to.have.property('Response Status').that.equals(200) + + expect(consoleProps.Yielded).to.have.property('body').that.deep.equals({ example: true }) + expect(consoleProps.Yielded).to.have.property('duration').that.is.a('number') + expect(consoleProps.Yielded).to.have.property('headers').that.is.a('object') + expect(consoleProps.Yielded).to.have.property('status').that.equals(200) + + expect(renderProps).to.have.property('indicator').that.equals('successful') + expect(renderProps).to.have.property('message').that.equals('GET 200 http://www.foobar.com:3500/fixtures/example.json') + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_querying.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_querying.spec.ts index e22baad757ec..75fc0859bdb6 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_querying.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_querying.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin querying', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -29,4 +31,74 @@ context('cy.origin querying', () => { cy.root().should('match', 'html') }) }) + + context('#consoleProps', () => { + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.contains()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.contains('Nested Find') + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('contains', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('contains') + expect(consoleProps['Applied To']).to.be.undefined + expect(consoleProps.Elements).to.equal(1) + expect(consoleProps.Content).to.equal('Nested Find') + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('DIV') + expect(consoleProps.Yielded).to.have.property('id').that.equals('nested-find') + }) + }) + + it('.within()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-id').within(() => { + cy.get('#input') + }) + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('within', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('within') + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('FORM') + expect(consoleProps.Yielded).to.have.property('id').that.equals('by-id') + }) + }) + + it('.root()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.root() + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('root', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('root') + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('HTML') + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_querying_shadow.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_querying_shadow.spec.ts index a7ec229ebad2..3171d39ef553 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_querying_shadow.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_querying_shadow.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin shadow dom', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -10,4 +12,40 @@ context('cy.origin shadow dom', () => { .should('have.text', 'Shadow Content 1') }) }) + + context('#consoleProps', () => { + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.shadow()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#shadow-element-1').shadow() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('shadow', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('shadow') + expect(consoleProps.Elements).to.equal(1) + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('CY-TEST-ELEMENT') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('shadow-element-1') + + expect(consoleProps.Yielded).to.be.null + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_screenshot.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_screenshot.spec.ts index ecbeffff9919..dab3e9136dca 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_screenshot.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_screenshot.spec.ts @@ -275,4 +275,47 @@ context('cy.origin screenshot', () => { }) }) }) + + context('#consoleProps', () => { + const { findCrossOriginLogs } = require('../../../../support/utils') + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + + cy.visit('/fixtures/multi-domain.html') + cy.get('a[data-cy="screenshots-link"]').click() + }) + + it('.screenshot()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.screenshot({ capture: 'fullPage' }) + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('screenshot', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('screenshot') + + expect(consoleProps).to.have.property('blackout') + expect(consoleProps).to.have.property('capture').that.equals('fullPage') + expect(consoleProps).to.have.property('dimensions').that.is.a('string') + expect(consoleProps).to.have.property('disableTimersAndAnimations').that.is.a('boolean') + expect(consoleProps).to.have.property('duration').that.is.a('string') + expect(consoleProps).to.have.property('multipart').that.is.a('boolean') + expect(consoleProps).to.have.property('name').to.be.null + expect(consoleProps).to.have.property('path').that.is.a('string') + expect(consoleProps).to.have.property('pixelRatio').that.is.a('number') + expect(consoleProps).to.have.property('scaled').that.is.a('boolean') + expect(consoleProps).to.have.property('size').that.is.a('string') + expect(consoleProps).to.have.property('specName').that.is.a('string') + expect(consoleProps).to.have.property('takenAt').that.is.a('string') + expect(consoleProps).to.have.property('testAttemptIndex').that.is.a('number') + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_spies_stubs_clocks.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_spies_stubs_clocks.spec.ts index 34bfa8b9bf55..51929443d1b8 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_spies_stubs_clocks.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_spies_stubs_clocks.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin spies, stubs, and clock', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -80,4 +82,101 @@ context('cy.origin spies, stubs, and clock', () => { }) }) }) + + context('#consoleProps', () => { + const { _ } = Cypress + let logs: Map + + beforeEach(() => { + logs = new Map() + + // cy.clock only adds a log and does NOT update + cy.on('log:added', (attrs, log) => { + logs.set(attrs.id, log) + }) + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('spy()', () => { + cy.origin('http://foobar.com:3500', () => { + const foo = { bar () { } } + + cy.spy(foo, 'bar') + foo.bar() + expect(foo.bar).to.be.called + }) + + cy.shouldWithTimeout(() => { + const spyLog = findCrossOriginLogs('spy-1', logs, 'foobar.com') + + expect(spyLog.consoleProps.Command).to.equal('spy-1') + expect(spyLog.callCount).to.be.a('number') + expect(spyLog.functionName).to.equal('bar') + }) + }) + + it('.stub()', () => { + cy.origin('http://foobar.com:3500', () => { + const foo = { bar () { } } + + cy.stub(foo, 'bar') + foo.bar() + expect(foo.bar).to.be.called + }) + + cy.shouldWithTimeout(() => { + const stubLog = findCrossOriginLogs('stub-1', logs, 'foobar.com') + + expect(stubLog.consoleProps.Command).to.equal('stub-1') + expect(stubLog.callCount).to.be.a('number') + expect(stubLog.functionName).to.equal('bar') + }) + }) + + it('.clock()', () => { + cy.origin('http://foobar.com:3500', () => { + const now = Date.UTC(2022, 0, 12) + + cy.clock(now) + }) + + cy.shouldWithTimeout(() => { + const clockLog = findCrossOriginLogs('clock', logs, 'foobar.com') + + expect(clockLog.name).to.equal('clock') + + const consoleProps = clockLog.consoleProps() + + expect(consoleProps.Command).to.equal('clock') + expect(consoleProps).to.have.property('Methods replaced').that.is.a('object') + expect(consoleProps).to.have.property('Now').that.is.a('number') + }) + }) + + it('.tick()', () => { + cy.origin('http://foobar.com:3500', () => { + const now = Date.UTC(2022, 0, 12) + + cy.clock(now) + + cy.tick(10000) + }) + + cy.shouldWithTimeout(() => { + const tickLog = findCrossOriginLogs('tick', logs, 'foobar.com') + + expect(tickLog.name).to.equal('tick') + + const consoleProps = _.isFunction(tickLog.consoleProps) ? tickLog.consoleProps() : tickLog.consoleProps + + expect(consoleProps.Command).to.equal('tick') + expect(consoleProps).to.have.property('Methods replaced').that.is.a('object') + expect(consoleProps).to.have.property('Now').that.is.a('number') + expect(consoleProps).to.have.property('Ticked').that.is.a('string') + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_traversal.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_traversal.spec.ts index 9e06a6acbd6c..a06101342991 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_traversal.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_traversal.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin traversal', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -112,4 +114,531 @@ context('cy.origin traversal', () => { cy.get('#input').siblings().should('have.length', 2) }) }) + + context('#consoleProps', () => { + const { _ } = Cypress + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.children()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-id').children() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('children', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('FORM') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('by-id') + expect(consoleProps.Command).to.equal('children') + expect(consoleProps.Elements).to.equal(3) + expect(consoleProps.Selector).to.equal('') + expect(consoleProps.Yielded.length).to.equal(3) + expect(consoleProps.Yielded[0]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[0]).to.have.property('id').that.equals('input') + expect(consoleProps.Yielded[1]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[1]).to.have.property('id').that.equals('name') + expect(consoleProps.Yielded[2]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[2]).to.have.property('id').that.equals('age') + }) + }) + + it('.closest()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-id').closest('form') + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('closest', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('FORM') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('by-id') + expect(consoleProps.Command).to.equal('closest') + expect(consoleProps.Elements).to.equal(1) + expect(consoleProps.Selector).to.equal('form') + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('FORM') + expect(consoleProps.Yielded).to.have.property('id').that.equals('by-id') + expect(consoleProps.Yielded.querySelector('input#input')).to.be.ok + expect(consoleProps.Yielded.querySelector('input#name')).to.be.ok + expect(consoleProps.Yielded.querySelector('input#age')).to.be.ok + }) + }) + + it('.eq()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-id>input').eq(1) + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('eq', logs, 'foobar.com') + + expect(consoleProps['Applied To'].length).to.equal(3) + expect(consoleProps['Applied To'][0]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To'][0]).to.have.property('id').that.equals('input') + expect(consoleProps['Applied To'][1]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To'][1]).to.have.property('id').that.equals('name') + expect(consoleProps['Applied To'][2]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To'][2]).to.have.property('id').that.equals('age') + + expect(consoleProps.Command).to.equal('eq') + expect(consoleProps.Elements).to.equal(1) + expect(consoleProps.Selector).to.equal('1') + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded).to.have.property('id').that.equals('name') + }) + }) + + it('.filter()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-name>input') + .filter('[name="dogs"]') + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('filter', logs, 'foobar.com') + + expect(consoleProps['Applied To'].length).to.equal(12) + expect(consoleProps.Command).to.equal('filter') + expect(consoleProps.Elements).to.equal(4) + expect(consoleProps.Selector).to.equal('[name="dogs"]') + + expect(consoleProps.Yielded.length).to.equal(4) + + _.forEach(consoleProps.Yielded, (yielded) => { + expect(yielded).to.have.property('tagName').that.equals('INPUT') + expect(yielded).to.have.property('name').that.equals('dogs') + }) + }) + }) + + it('.find()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-id').find('input') + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('find', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('FORM') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('by-id') + + expect(consoleProps.Command).to.equal('find') + expect(consoleProps.Elements).to.equal(3) + expect(consoleProps.Selector).to.equal('input') + + expect(consoleProps.Yielded.length).to.equal(3) + expect(consoleProps.Yielded[0]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[0]).to.have.property('id').that.equals('input') + expect(consoleProps.Yielded[1]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[1]).to.have.property('id').that.equals('name') + expect(consoleProps.Yielded[2]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[2]).to.have.property('id').that.equals('age') + }) + }) + + it('.first()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-id>input').first() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('first', logs, 'foobar.com') + + expect(consoleProps['Applied To'].length).to.equal(3) + expect(consoleProps['Applied To'][0]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To'][0]).to.have.property('id').that.equals('input') + expect(consoleProps['Applied To'][1]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To'][1]).to.have.property('id').that.equals('name') + expect(consoleProps['Applied To'][2]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To'][2]).to.have.property('id').that.equals('age') + + expect(consoleProps.Command).to.equal('first') + expect(consoleProps.Elements).to.equal(1) + expect(consoleProps.Selector).to.equal('') + + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded).to.have.property('id').that.equals('input') + }) + }) + + it('.last()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-id>input').last() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('last', logs, 'foobar.com') + + expect(consoleProps['Applied To'].length).to.equal(3) + expect(consoleProps['Applied To'][0]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To'][0]).to.have.property('id').that.equals('input') + expect(consoleProps['Applied To'][1]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To'][1]).to.have.property('id').that.equals('name') + expect(consoleProps['Applied To'][2]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To'][2]).to.have.property('id').that.equals('age') + + expect(consoleProps.Command).to.equal('last') + expect(consoleProps.Elements).to.equal(1) + expect(consoleProps.Selector).to.equal('') + + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded).to.have.property('id').that.equals('age') + }) + }) + + it('.next()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#input').next() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('next', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('input') + + expect(consoleProps.Command).to.equal('next') + expect(consoleProps.Elements).to.equal(1) + expect(consoleProps.Selector).to.equal('') + + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded).to.have.property('id').that.equals('name') + }) + }) + + it('.nextAll()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#input').nextAll() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('nextAll', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('input') + + expect(consoleProps.Command).to.equal('nextAll') + expect(consoleProps.Elements).to.equal(2) + expect(consoleProps.Selector).to.equal('') + + expect(consoleProps.Yielded.length).to.equal(2) + expect(consoleProps.Yielded[0]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[0]).to.have.property('id').that.equals('name') + expect(consoleProps.Yielded[1]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[1]).to.have.property('id').that.equals('age') + }) + }) + + it('.nextUntil()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#input').nextUntil('#age') + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('nextUntil', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('input') + + expect(consoleProps.Command).to.equal('nextUntil') + expect(consoleProps.Elements).to.equal(1) + expect(consoleProps.Selector).to.equal('#age') + + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded).to.have.property('id').that.equals('name') + }) + }) + + it('.not()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-id>input').not('#age') + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('not', logs, 'foobar.com') + + expect(consoleProps['Applied To'].length).to.equal(3) + expect(consoleProps['Applied To'][0]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To'][0]).to.have.property('id').that.equals('input') + expect(consoleProps['Applied To'][1]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To'][1]).to.have.property('id').that.equals('name') + expect(consoleProps['Applied To'][2]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To'][2]).to.have.property('id').that.equals('age') + + expect(consoleProps.Command).to.equal('not') + expect(consoleProps.Elements).to.equal(2) + expect(consoleProps.Selector).to.equal('#age') + + expect(consoleProps.Yielded.length).to.equal(2) + expect(consoleProps.Yielded[0]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[0]).to.have.property('id').that.equals('input') + expect(consoleProps.Yielded[1]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[1]).to.have.property('id').that.equals('name') + }) + }) + + it('.parent()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-id').parent() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('parent', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('FORM') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('by-id') + + expect(consoleProps.Command).to.equal('parent') + expect(consoleProps.Elements).to.equal(1) + expect(consoleProps.Selector).to.equal('') + + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('DIV') + expect(consoleProps.Yielded).to.have.property('id').that.equals('dom') + }) + }) + + it('.parents()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-id').parents() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('parents', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('FORM') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('by-id') + + expect(consoleProps.Command).to.equal('parents') + expect(consoleProps.Elements).to.equal(3) + expect(consoleProps.Selector).to.equal('') + + expect(consoleProps.Yielded.length).to.equal(3) + expect(consoleProps.Yielded[0]).to.have.property('tagName').that.equals('DIV') + expect(consoleProps.Yielded[0]).to.have.property('id').that.equals('dom') + expect(consoleProps.Yielded[1]).to.have.property('tagName').that.equals('BODY') + expect(consoleProps.Yielded[2]).to.have.property('tagName').that.equals('HTML') + }) + }) + + it('.parentsUntil()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#by-id').parentsUntil('body') + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('parentsUntil', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('FORM') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('by-id') + + expect(consoleProps.Command).to.equal('parentsUntil') + expect(consoleProps.Elements).to.equal(1) + expect(consoleProps.Selector).to.equal('body') + + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('DIV') + expect(consoleProps.Yielded).to.have.property('id').that.equals('dom') + }) + }) + + it('.prev()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#age').prev() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('prev', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('age') + + expect(consoleProps.Command).to.equal('prev') + expect(consoleProps.Elements).to.equal(1) + expect(consoleProps.Selector).to.equal('') + + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded).to.have.property('id').that.equals('name') + }) + }) + + it('.prevAll()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#age').prevAll() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('prevAll', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('age') + + expect(consoleProps.Command).to.equal('prevAll') + expect(consoleProps.Elements).to.equal(2) + expect(consoleProps.Selector).to.equal('') + + expect(consoleProps.Yielded.length).to.equal(2) + expect(consoleProps.Yielded[0]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[0]).to.have.property('id').that.equals('name') + expect(consoleProps.Yielded[1]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[1]).to.have.property('id').that.equals('input') + }) + }) + + it('.prevUntil()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#age').prevUntil('#input') + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('prevUntil', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('age') + + expect(consoleProps.Command).to.equal('prevUntil') + expect(consoleProps.Elements).to.equal(1) + expect(consoleProps.Selector).to.equal('#input') + + expect(consoleProps.Yielded).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded).to.have.property('id').that.equals('name') + }) + }) + + it('.siblings()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.get('#input').siblings() + }) + + cy.shouldWithTimeout(() => { + // in the case of some firefox browsers, the document state is left in a cross origin context when running these assertions + // set to context to undefined to run the assertions + if (Cypress.isBrowser('firefox')) { + cy.state('document', undefined) + } + + const { consoleProps } = findCrossOriginLogs('siblings', logs, 'foobar.com') + + expect(consoleProps['Applied To']).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps['Applied To']).to.have.property('id').that.equals('input') + + expect(consoleProps.Command).to.equal('siblings') + expect(consoleProps.Elements).to.equal(2) + expect(consoleProps.Selector).to.equal('') + + expect(consoleProps.Yielded.length).to.equal(2) + expect(consoleProps.Yielded[0]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[0]).to.have.property('id').that.equals('name') + expect(consoleProps.Yielded[1]).to.have.property('tagName').that.equals('INPUT') + expect(consoleProps.Yielded[1]).to.have.property('id').that.equals('age') + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_viewport.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_viewport.spec.ts index e49a346b961a..cfe34498fda2 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_viewport.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_viewport.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin viewport', () => { it('syncs the viewport from the primary to secondary', () => { // change the viewport in the primary first @@ -178,5 +180,31 @@ context('cy.origin viewport', () => { }) }) }) + + context('#consoleProps', () => { + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.viewport()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.viewport(320, 480) + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('viewport', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('viewport') + expect(consoleProps.Width).to.equal(320) + expect(consoleProps.Height).to.equal(480) + }) + }) + }) }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_waiting.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_waiting.spec.ts index 54a7f51bcb7c..67f188e603e7 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_waiting.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_waiting.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin waiting', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -9,4 +11,29 @@ context('cy.origin waiting', () => { cy.wait(500) }) }) + + context('#consoleProps', () => { + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.wait()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.wait(200) + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('wait', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('wait') + expect(consoleProps).to.have.property('Waited For').to.equal('200ms before continuing') + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_window.spec.ts b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_window.spec.ts index 95b56f279d36..84d7bfc03708 100644 --- a/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_window.spec.ts +++ b/packages/driver/cypress/integration/e2e/multi-domain/commands/multi_domain_window.spec.ts @@ -1,3 +1,5 @@ +import { findCrossOriginLogs } from '../../../../support/utils' + context('cy.origin window', () => { beforeEach(() => { cy.visit('/fixtures/multi-domain.html') @@ -21,4 +23,55 @@ context('cy.origin window', () => { cy.title().should('include', 'DOM Fixture') }) }) + + context('#consoleProps', () => { + let logs: Map + + beforeEach(() => { + logs = new Map() + + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) + }) + + it('.window()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.window() + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('window', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('window') + expect(consoleProps.Yielded).to.be.null + }) + }) + + it('.document()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.document() + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('document', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('document') + expect(consoleProps.Yielded).to.be.null + }) + }) + + it('.title()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.title() + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('title', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('title') + expect(consoleProps.Yielded).to.equal('DOM Fixture') + }) + }) + }) }) diff --git a/packages/driver/cypress/integration/util/serialization_spec.ts b/packages/driver/cypress/integration/util/serialization_spec.ts new file mode 100644 index 000000000000..b8c74725223b --- /dev/null +++ b/packages/driver/cypress/integration/util/serialization_spec.ts @@ -0,0 +1,688 @@ +import { reifyDomElement, preprocessDomElement, preprocessLogLikeForSerialization, preprocessLogForSerialization, reifyLogFromSerialization } from '../../../src/util/serialization/log' + +describe('Log Serialization', () => { + const buildSnapshot = (innerSnapshotElement) => { + const mockSnapshot = document.createElement('body') + + // populate some items into the mockSnapshot that would mimic what the DOM might actually look like, along with our inner snapshot element + const mockContainer = document.createElement('div') + const mockInnerHeader = document.createElement('h1') + const mockTextNode = document.createTextNode('Mock Snapshot Header') + + mockInnerHeader.appendChild(mockTextNode) + mockContainer.appendChild(mockInnerHeader) + mockContainer.appendChild(innerSnapshotElement) + + mockSnapshot.appendChild(mockContainer) + + return mockSnapshot + } + + it('preprocesses complex log-like data structures by preprocessing log DOM elements and table functions', () => { + const mockSpan = document.createElement('span') + + mockSpan.innerHTML = 'click button' + + const mockButton = document.createElement('button') + + mockButton.appendChild(mockSpan) + + const mockClickedElement = document.createElement('form') + + mockClickedElement.appendChild(mockButton) + mockClickedElement.id = 'button-inside-a' + + const mockSnapshot = buildSnapshot(mockClickedElement) + + const mockSnapshots = ['before', 'after'].map((snapshotName) => { + return { + name: snapshotName, + htmlAttrs: {}, + body: { + get: () => Cypress.$(mockSnapshot), + }, + } + }) + + // mockLogAttrs should look just like log attributes that are emitted from log:changed/log:added events. This example is what a 'click' log may look like + const mockLogAttrs = { + $el: Cypress.$(mockClickedElement), + alias: undefined, + chainerId: 'mock-chainer-id', + consoleProps: { + ['Applied To']: mockClickedElement, + Command: 'click', + Coords: { + x: 100, + y: 50, + }, + Options: undefined, + Yielded: undefined, + table: { + 1: () => { + return { + name: 'Mouse Events', + // NOTE: click data length is truncated for test readability + data: [ + { + 'Active Modifiers': null, + 'Event Type': 'pointerover', + 'Prevented Default': null, + 'Stopped Propagation': null, + 'Target Element': mockClickedElement, + }, + { + 'Active Modifiers': null, + 'Event Type': 'mouseover', + 'Prevented Default': null, + 'Stopped Propagation': null, + 'Target Element': mockClickedElement, + }, + ], + } + }, + }, + }, + coords: { top: 50, left: 50, topCenter: 100, leftCenter: 1000, x: 100, y: 50 }, + ended: true, + err: undefined, + event: false, + highlightAttr: 'data-cypress-el', + hookId: 'r4', + id: 'mock-log-id', + instrument: 'command', + message: '', + name: 'click', + numElements: 1, + referencesAlias: undefined, + renderProps: {}, + snapshots: mockSnapshots, + state: 'passed', + testCurrentRetry: 0, + testId: 'r4', + timeout: 4000, + type: 'child', + url: 'http://www.foobar.com', + viewportHeight: 660, + viewportWidth: 1000, + visible: true, + wallClockStartedAt: '2022-04-18T21:52:37.833Z', + } + + const { consoleProps, snapshots, $el, ...logAttrs } = preprocessLogForSerialization(mockLogAttrs) + + expect(logAttrs).to.deep.equal({ + alias: undefined, + chainerId: 'mock-chainer-id', + coords: { top: 50, left: 50, topCenter: 100, leftCenter: 1000, x: 100, y: 50 }, + ended: true, + err: undefined, + event: false, + highlightAttr: 'data-cypress-el', + hookId: 'r4', + id: 'mock-log-id', + instrument: 'command', + message: '', + name: 'click', + numElements: 1, + referencesAlias: undefined, + renderProps: {}, + state: 'passed', + testCurrentRetry: 0, + testId: 'r4', + timeout: 4000, + type: 'child', + url: 'http://www.foobar.com', + viewportHeight: 660, + viewportWidth: 1000, + visible: true, + wallClockStartedAt: '2022-04-18T21:52:37.833Z', + }) + + expect($el).to.deep.equal([ + { + attributes: { + id: 'button-inside-a', + }, + innerHTML: '', + serializationKey: 'dom', + tagName: 'FORM', + }, + ]) + + expect(consoleProps).to.deep.equal({ + ['Applied To']: { + attributes: { + id: 'button-inside-a', + }, + innerHTML: '', + serializationKey: 'dom', + tagName: 'FORM', + }, + Command: 'click', + Coords: { + x: 100, + y: 50, + }, + Options: undefined, + Yielded: undefined, + table: { + 1: { + serializationKey: 'function', + value: { + name: 'Mouse Events', + data: [ + { + 'Active Modifiers': null, + 'Event Type': 'pointerover', + 'Prevented Default': null, + 'Stopped Propagation': null, + 'Target Element': { + attributes: { + id: 'button-inside-a', + }, + innerHTML: '', + serializationKey: 'dom', + tagName: 'FORM', + }, + }, + { + 'Active Modifiers': null, + 'Event Type': 'mouseover', + 'Prevented Default': null, + 'Stopped Propagation': null, + 'Target Element': { + attributes: { + id: 'button-inside-a', + }, + innerHTML: '', + serializationKey: 'dom', + tagName: 'FORM', + }, + }, + ], + }, + }, + }, + }) + + expect(snapshots).to.deep.equal([ + { + name: 'before', + htmlAttrs: {}, + styles: {}, + body: { + get: { + serializationKey: 'function', + value: [{ + attributes: {}, + innerHTML: `

Mock Snapshot Header

`, + serializationKey: 'dom', + tagName: 'BODY', + }], + }, + }, + }, + { + name: 'after', + htmlAttrs: {}, + styles: {}, + body: { + get: { + serializationKey: 'function', + value: [{ + attributes: {}, + innerHTML: `

Mock Snapshot Header

`, + serializationKey: 'dom', + tagName: 'BODY', + }], + }, + }, + }, + ]) + }) + + it('reifies complex log-like data structures by reifying serialized DOM elements and table functions back into native data types, respectively', () => { + // this should log identical to the test output above from what a preprocessed click log looks like after postMessage() + const mockPreprocessedLogAttrs = { + $el: [ + { + attributes: { + id: 'button-inside-a', + }, + innerHTML: '', + serializationKey: 'dom', + tagName: 'FORM', + }, + ], + alias: undefined, + chainerId: 'mock-chainer-id', + consoleProps: { + ['Applied To']: { + attributes: { + id: 'button-inside-a', + }, + innerHTML: '', + serializationKey: 'dom', + tagName: 'FORM', + }, + Command: 'click', + Coords: { + x: 100, + y: 50, + }, + Options: undefined, + Yielded: undefined, + table: { + 1: { + serializationKey: 'function', + value: { + name: 'Mouse Events', + // NOTE: click data length is truncated for test readability + data: [ + { + 'Active Modifiers': null, + 'Event Type': 'pointerover', + 'Prevented Default': null, + 'Stopped Propagation': null, + 'Target Element': { + attributes: { + id: 'button-inside-a', + }, + innerHTML: '', + serializationKey: 'dom', + tagName: 'FORM', + }, + }, + { + 'Active Modifiers': null, + 'Event Type': 'mouseover', + 'Prevented Default': null, + 'Stopped Propagation': null, + 'Target Element': { + attributes: { + id: 'button-inside-a', + }, + innerHTML: '', + serializationKey: 'dom', + tagName: 'FORM', + }, + }, + ], + }, + }, + }, + }, + coords: { top: 50, left: 50, topCenter: 100, leftCenter: 1000, x: 100, y: 50 }, + ended: true, + err: undefined, + event: false, + highlightAttr: 'data-cypress-el', + hookId: 'r4', + id: 'mock-log-id', + instrument: 'command', + message: '', + name: 'click', + numElements: 1, + referencesAlias: undefined, + renderProps: {}, + snapshots: [ + { + name: 'before', + htmlAttrs: {}, + styles: {}, + body: { + get: { + serializationKey: 'function', + value: [{ + attributes: {}, + innerHTML: `

Mock Snapshot Header

`, + serializationKey: 'dom', + tagName: 'BODY', + }], + }, + }, + }, + { + name: 'after', + htmlAttrs: {}, + styles: {}, + body: { + get: { + serializationKey: 'function', + value: [{ + attributes: {}, + innerHTML: `

Mock Snapshot Header

`, + serializationKey: 'dom', + tagName: 'BODY', + }], + }, + }, + }, + ], + state: 'passed', + testCurrentRetry: 0, + testId: 'r4', + timeout: 4000, + type: 'child', + url: 'http://www.foobar.com', + viewportHeight: 660, + viewportWidth: 1000, + visible: true, + wallClockStartedAt: '2022-04-18T21:52:37.833Z', + } + + const { consoleProps, snapshots, $el, ...logAttrs } = reifyLogFromSerialization(mockPreprocessedLogAttrs) + + expect(logAttrs).to.deep.equal({ + alias: undefined, + chainerId: 'mock-chainer-id', + coords: { top: 50, left: 50, topCenter: 100, leftCenter: 1000, x: 100, y: 50 }, + ended: true, + err: undefined, + event: false, + highlightAttr: 'data-cypress-el', + hookId: 'r4', + id: 'mock-log-id', + instrument: 'command', + message: '', + name: 'click', + numElements: 1, + referencesAlias: undefined, + renderProps: {}, + state: 'passed', + testCurrentRetry: 0, + testId: 'r4', + timeout: 4000, + type: 'child', + url: 'http://www.foobar.com', + viewportHeight: 660, + viewportWidth: 1000, + visible: true, + wallClockStartedAt: '2022-04-18T21:52:37.833Z', + }) + + expect($el.jquery).to.be.ok + expect($el.length).to.equal(1) + expect($el[0]).to.be.instanceOf(HTMLFormElement) + expect($el[0].id).to.equal('button-inside-a') + expect($el[0].textContent).to.equal('click button') + + // most of the consoleProps logic is tested in the e2e/multi-domain folder. focus in this test will be mostly snapshot serialization + expect(consoleProps['Applied To']).to.be.instanceOf(HTMLFormElement) + expect(consoleProps['Applied To']).to.have.property('id').that.equals('button-inside-a') + expect(consoleProps['Applied To']).to.have.property('textContent').that.equals('click button') + + expect(consoleProps.table).to.have.property('1') + expect(consoleProps.table[1]).to.be.a('function') + + expect(snapshots).to.have.lengthOf(2) + + expect(snapshots[0]).to.have.property('name').that.equals('before') + expect(snapshots[0]).to.have.property('htmlAttrs').that.deep.equals({}) + // styles should now live in the CSS map after a snapshot is processed through createSnapshot and snapshots should exist in document map + expect(snapshots[0]).to.not.have.property('styles') + expect(snapshots[0]).to.have.property('body').that.has.property('get').that.is.a('function') + + const snapshotBodyBefore = snapshots[0].body.get() + + expect(snapshotBodyBefore.length).to.equal(1) + + expect(snapshotBodyBefore[0]).to.be.instanceOf(HTMLBodyElement) + // verify to some degree that the reified elements above can be matched into the snapshot + expect(snapshotBodyBefore[0].querySelector('form#button-inside-a')).to.be.instanceOf(HTMLFormElement) + + expect(snapshots[1]).to.have.property('name').that.equals('after') + expect(snapshots[1]).to.have.property('htmlAttrs').that.deep.equals({}) + expect(snapshots[1]).to.not.have.property('styles') + expect(snapshots[1]).to.have.property('body').that.has.property('get').that.is.a('function') + + const snapshotBodyAfter = snapshots[1].body.get() + + expect(snapshotBodyAfter.length).to.equal(1) + + expect(snapshotBodyAfter[0]).to.be.instanceOf(HTMLBodyElement) + // verify to some degree that the reified elements above can be matched into the snapshot + expect(snapshotBodyAfter[0].querySelector('form#button-inside-a')).to.be.instanceOf(HTMLFormElement) + }) + + // purpose of these 'DOM Elements' tests is to give a very basic understanding of how DOM element serialization works in the log serializer + context('DOM Elements- preprocesses/reifies a given DOM element with stateful', () => { + context('input', () => { + it('preprocess', () => { + const inputElement = document.createElement('input') + + inputElement.type = 'text' + inputElement.value = 'foo' + inputElement.setAttribute('data-cy', 'bar') + + const snapshot = buildSnapshot(inputElement) + + snapshot.setAttribute('foo', 'bar') + + const preprocessedSnapshot = preprocessDomElement(snapshot) + + expect(preprocessedSnapshot).to.have.property('tagName').that.equals('BODY') + expect(preprocessedSnapshot).to.have.property('serializationKey').that.equals('dom') + expect(preprocessedSnapshot).to.have.property('attributes').that.deep.equals({ + foo: 'bar', + }) + + expect(preprocessedSnapshot).to.have.property('innerHTML').that.equals(`

Mock Snapshot Header

`) + }) + + it('reifies', () => { + const preprocessedSnapshot = { + tagName: 'BODY', + serializationKey: 'dom', + attributes: { + foo: 'bar', + }, + innerHTML: `

Mock Snapshot Header

`, + } + + const reifiedSnapshot = reifyDomElement(preprocessedSnapshot) + + expect(reifiedSnapshot).to.be.instanceOf(HTMLBodyElement) + expect(reifiedSnapshot.getAttribute('foo')).to.equal('bar') + expect(reifiedSnapshot.querySelector('input[type="text"][value="foo"][data-cy="bar"]')).to.be.instanceOf(HTMLInputElement) + }) + }) + + context('select', () => { + it('preprocess', () => { + const selectElement = document.createElement('select') + + selectElement.id = 'metasyntactic-variables' + selectElement.name = 'Metasyntactic Variables' + + const options = ['Hank Hill', 'Buck Strickland', 'Donna', 'Old Donna'].map((val) => { + const option = document.createElement('option') + + option.value = val + + return option + }) + + options.forEach((option) => selectElement.appendChild(option)) + + selectElement.selectedIndex = 1 + + const snapshot = buildSnapshot(selectElement) + + const preprocessedSnapshot = preprocessDomElement(snapshot) + + expect(preprocessedSnapshot).to.have.property('tagName').that.equals('BODY') + expect(preprocessedSnapshot).to.have.property('serializationKey').that.equals('dom') + expect(preprocessedSnapshot).to.have.property('innerHTML').that.equals(`

Mock Snapshot Header

`) + }) + + it('reifies', () => { + const preprocessedSnapshot = { + tagName: 'BODY', + serializationKey: 'dom', + attributes: {}, + innerHTML: `

Mock Snapshot Header

`, + } + + const reifiedSnapshot = reifyDomElement(preprocessedSnapshot) + + expect(reifiedSnapshot).to.be.instanceOf(HTMLBodyElement) + expect(reifiedSnapshot.querySelector('select#metasyntactic-variables option[selected]')).to.have.property('value').that.equals('Buck Strickland') + }) + }) + + context('textarea', () => { + it('preprocess', () => { + const textAreaElement = document.createElement('textarea') + + textAreaElement.rows = 4 + textAreaElement.cols = 20 + textAreaElement.value = 'Generic variable names that function as placeholders' + + const snapshot = buildSnapshot(textAreaElement) + + const preprocessedSnapshot = preprocessDomElement(snapshot) + + expect(preprocessedSnapshot).to.have.property('tagName').that.equals('BODY') + expect(preprocessedSnapshot).to.have.property('serializationKey').that.equals('dom') + expect(preprocessedSnapshot).to.have.property('innerHTML').that.equals(`

Mock Snapshot Header

`) + }) + + it('reifies', () => { + const preprocessedSnapshot = { + tagName: 'BODY', + serializationKey: 'dom', + attributes: {}, + innerHTML: `

Mock Snapshot Header

`, + } + + const reifiedSnapshot = reifyDomElement(preprocessedSnapshot) + + expect(reifiedSnapshot).to.be.instanceOf(HTMLBodyElement) + expect(reifiedSnapshot.querySelector('textarea[rows="4"]')).to.have.property('textContent').that.equals('Generic variable names that function as placeholders') + }) + }) + + context('radio', () => { + it('preprocess', () => { + const formElement = document.createElement('form') + + const radioInputs = ['foo', 'bar', 'baz'].map((val) => { + const radioInput = document.createElement('input') + + radioInput.type = 'radio' + radioInput.value = val + + return radioInput + }) + + radioInputs[1].checked = true + + radioInputs.forEach((radioInput) => formElement.appendChild(radioInput)) + + const snapshot = buildSnapshot(formElement) + + const preprocessedSnapshot = preprocessDomElement(snapshot) + + expect(preprocessedSnapshot).to.have.property('tagName').that.equals('BODY') + expect(preprocessedSnapshot).to.have.property('serializationKey').that.equals('dom') + expect(preprocessedSnapshot).to.have.property('innerHTML').that.equals(`

Mock Snapshot Header

`) + }) + + it('reifies', () => { + const preprocessedSnapshot = { + tagName: 'BODY', + serializationKey: 'dom', + attributes: {}, + innerHTML: `

Mock Snapshot Header

`, + } + + const reifiedSnapshot = reifyDomElement(preprocessedSnapshot) + + expect(reifiedSnapshot).to.be.instanceOf(HTMLBodyElement) + expect(reifiedSnapshot.querySelector('form input[value="bar"]')).to.have.property('checked').that.equals(true) + }) + }) + + context('checkbox', () => { + it('preprocess', () => { + const formElement = document.createElement('form') + + const checkboxInputs = ['foo', 'bar', 'bar'].map((val) => { + const checkboxInput = document.createElement('input') + + checkboxInput.type = 'checkbox' + checkboxInput.value = val + + return checkboxInput + }) + + checkboxInputs[1].checked = true + + checkboxInputs.forEach((checkboxInput) => formElement.appendChild(checkboxInput)) + + const snapshot = buildSnapshot(formElement) + + const preprocessedSnapshot = preprocessDomElement(snapshot) + + expect(preprocessedSnapshot).to.have.property('tagName').that.equals('BODY') + expect(preprocessedSnapshot).to.have.property('serializationKey').that.equals('dom') + expect(preprocessedSnapshot).to.have.property('innerHTML').that.equals(`

Mock Snapshot Header

`) + }) + + it('reifies', () => { + const preprocessedSnapshot = { + tagName: 'BODY', + serializationKey: 'dom', + attributes: {}, + innerHTML: `"

Mock Snapshot Header

"`, + } + + const reifiedSnapshot = reifyDomElement(preprocessedSnapshot) + + expect(reifiedSnapshot).to.be.instanceOf(HTMLBodyElement) + expect(reifiedSnapshot.querySelector('form input[value="bar"]')).to.have.property('checked').that.equals(true) + }) + }) + }) + + // purpose of these 'DOM Elements' tests is to give a very basic understanding of how DOM element serialization works in the log serializer + context('Functions', () => { + it('does NOT try to serialize a function unless `attemptToSerializeFunctions` is set to true', () => { + const serializedFunction = preprocessLogLikeForSerialization(() => 'foo') + + expect(serializedFunction).to.be.null + }) + + it('Tries to serialize EXPLICIT/KNOWN serializable functions by setting `attemptToSerializeFunctions` to true', () => { + const functionContents = [ + 'foo', + { + bar: 'baz', + }, + document.createElement('html'), + ] + + const myKnownSerializableFunction = () => functionContents + + const serializedFunction = preprocessLogLikeForSerialization(myKnownSerializableFunction, true) + + expect(serializedFunction).to.deep.equal({ + serializationKey: 'function', + value: [ + 'foo', + { + bar: 'baz', + }, + { + tagName: 'HTML', + serializationKey: 'dom', + attributes: {}, + innerHTML: '', + }, + ], + }) + }) + }) +}) diff --git a/packages/driver/cypress/support/utils.js b/packages/driver/cypress/support/utils.js index c358c3d657c8..8ae506576458 100644 --- a/packages/driver/cypress/support/utils.js +++ b/packages/driver/cypress/support/utils.js @@ -72,6 +72,20 @@ export const assertLogLength = (logs, expectedLength) => { expect(logs.length).to.eq(expectedLength, `received ${logs.length} logs when we expected ${expectedLength}: [${receivedLogs}]`) } +export const findCrossOriginLogs = (consolePropCommand, logMap, matchingOrigin) => { + const matchedLogs = Array.from(logMap.values()).filter((log) => { + const props = log.get() + + let consoleProps = _.isFunction(props?.consoleProps) ? props.consoleProps() : props?.consoleProps + + return consoleProps.Command === consolePropCommand && props.id.includes(matchingOrigin) + }) + + const logAttrs = matchedLogs.map((log) => log.get()) + + return logAttrs.length === 1 ? logAttrs[0] : logAttrs +} + export const attachListeners = (listenerArr) => { return (els) => { _.each(els, (el, elName) => { @@ -94,6 +108,10 @@ const getAllFn = (...aliases) => { ) } +const shouldWithTimeout = (cb, timeout = 250) => { + cy.wrap({}, { timeout }).should(cb) +} + export const keyEvents = [ 'keydown', 'keyup', @@ -120,6 +138,8 @@ export const expectCaret = (start, end) => { Cypress.Commands.add('getAll', getAllFn) +Cypress.Commands.add('shouldWithTimeout', shouldWithTimeout) + const chaiSubset = require('chai-subset') chai.use(chaiSubset) diff --git a/packages/driver/src/cy/snapshots.ts b/packages/driver/src/cy/snapshots.ts index 6d8edd3a421b..9d0a05328101 100644 --- a/packages/driver/src/cy/snapshots.ts +++ b/packages/driver/src/cy/snapshots.ts @@ -5,6 +5,8 @@ import { create as createSnapshotsCSS } from './snapshots_css' export const HIGHLIGHT_ATTR = 'data-cypress-el' +export const FINAL_SNAPSHOT_NAME = 'final state' + export const create = ($$, state) => { const snapshotsCss = createSnapshotsCSS($$, state) const snapshotsMap = new WeakMap() @@ -99,15 +101,20 @@ export const create = ($$, state) => { } const getStyles = (snapshot) => { - const styleIds = snapshotsMap.get(snapshot) + const { ids, styles } = snapshotsMap.get(snapshot) || {} - if (!styleIds) { + if (!ids && !styles) { return {} } + // If a cross origin processed snapshot, styles are directly added into the CSS map. Simply return them. + if (styles?.headStyles || styles?.bodyStyles) { + return styles + } + return { - headStyles: snapshotsCss.getStylesByIds(styleIds.headStyleIds), - bodyStyles: snapshotsCss.getStylesByIds(styleIds.bodyStyleIds), + headStyles: snapshotsCss.getStylesByIds(ids?.headStyleIds), + bodyStyles: snapshotsCss.getStylesByIds(ids?.bodyStyleIds), } } @@ -119,20 +126,24 @@ export const create = ($$, state) => { $body.find('script,link[rel="stylesheet"],style').remove() const snapshot = { - name: 'final state', + name: FINAL_SNAPSHOT_NAME, htmlAttrs, body: { get: () => $body.detach(), }, } - snapshotsMap.set(snapshot, { headStyleIds, bodyStyleIds }) + snapshotsMap.set(snapshot, { + ids: { + headStyleIds, + bodyStyleIds, + }, + }) return snapshot } - const createSnapshot = (name, $elToHighlight) => { - Cypress.action('cy:snapshot', name) + const createSnapshotBody = ($elToHighlight) => { // create a unique selector for this el // but only IF the subject is truly an element. For example // we might be wrapping a primitive like "$([1, 2]).first()" @@ -141,64 +152,89 @@ export const create = ($$, state) => { // jQuery v3 runs in strict mode and throws an error if you attempt to set a property // TODO: in firefox sometimes this throws a cross-origin access error - try { - const isJqueryElement = $dom.isElement($elToHighlight) && $dom.isJquery($elToHighlight) + const isJqueryElement = $dom.isElement($elToHighlight) && $dom.isJquery($elToHighlight) - if (isJqueryElement) { - ($elToHighlight as JQuery).attr(HIGHLIGHT_ATTR, 'true') - } + if (isJqueryElement) { + ($elToHighlight as JQuery).attr(HIGHLIGHT_ATTR, 'true') + } - // TODO: throw error here if cy is undefined! - - // cloneNode can actually trigger functions attached to custom elements - // so we have to use importNode to clone the element - // https://github.com/cypress-io/cypress/issues/7187 - // https://github.com/cypress-io/cypress/issues/1068 - // we import it to a transient document (snapshotDocument) so that there - // are no side effects from cloning it. see below for how we re-attach - // it to the AUT document - // https://github.com/cypress-io/cypress/issues/8679 - // this can fail if snapshotting before the page has fully loaded, - // so we catch this below and return null for the snapshot - // https://github.com/cypress-io/cypress/issues/15816 - const $body = $$(snapshotDocument.importNode($$('body')[0], true)) - - // for the head and body, get an array of all CSS, - // whether it's links or style tags - // if it's same-origin, it will get the actual styles as a string - // it it's cross-origin, it will get a reference to the link's href - const { headStyleIds, bodyStyleIds } = snapshotsCss.getStyleIds() - - // replaces iframes with placeholders - replaceIframes($body) - - // remove tags we don't want in body - $body.find('script,link[rel=\'stylesheet\'],style').remove() - - // here we need to figure out if we're in a remote manual environment - // if so we need to stringify the DOM: - // 1. grab all inputs / textareas / options and set their value on the element - // 2. convert DOM to string: body.prop("outerHTML") - // 3. send this string via websocket to our server - // 4. server rebroadcasts this to our client and its stored as a property - - // its also possible for us to store the DOM string completely on the server - // without ever sending it back to the browser (until its requests). - // we could just store it in memory and wipe it out intelligently. - // this would also prevent having to store the DOM structure on the client, - // which would reduce memory, and some CPU operations - - // now remove it after we clone - if (isJqueryElement) { - ($elToHighlight as JQuery).removeAttr(HIGHLIGHT_ATTR) - } + // TODO: throw error here if cy is undefined! + + // cloneNode can actually trigger functions attached to custom elements + // so we have to use importNode to clone the element + // https://github.com/cypress-io/cypress/issues/7187 + // https://github.com/cypress-io/cypress/issues/1068 + // we import it to a transient document (snapshotDocument) so that there + // are no side effects from cloning it. see below for how we re-attach + // it to the AUT document + // https://github.com/cypress-io/cypress/issues/8679 + // this can fail if snapshotting before the page has fully loaded, + // so we catch this below and return null for the snapshot + // https://github.com/cypress-io/cypress/issues/15816 + const $body = $$(snapshotDocument.importNode($$('body')[0], true)) + // for the head and body, get an array of all CSS, + // whether it's links or style tags + // if it's same-origin, it will get the actual styles as a string + // if it's cross-origin, it will get a reference to the link's href + const { headStyleIds, bodyStyleIds } = snapshotsCss.getStyleIds() + + // replaces iframes with placeholders + replaceIframes($body) + + // remove tags we don't want in body + $body.find('script,link[rel=\'stylesheet\'],style').remove() + + // here we need to figure out if we're in a remote manual environment + // if so we need to stringify the DOM: + // 1. grab all inputs / textareas / options and set their value on the element + // 2. convert DOM to string: body.prop("outerHTML") + // 3. send this string via websocket to our server + // 4. server rebroadcasts this to our client and its stored as a property + + // its also possible for us to store the DOM string completely on the server + // without ever sending it back to the browser (until its requests). + // we could just store it in memory and wipe it out intelligently. + // this would also prevent having to store the DOM structure on the client, + // which would reduce memory, and some CPU operations + + // now remove it after we clone + if (isJqueryElement) { + ($elToHighlight as JQuery).removeAttr(HIGHLIGHT_ATTR) + } + + const $htmlAttrs = getHtmlAttrs($$('html')[0]) + + return { + $body, + $htmlAttrs, + headStyleIds, + bodyStyleIds, + } + } + + const reifySnapshotBody = (preprocessedSnapshot) => { + const $body = preprocessedSnapshot.body.get() + const $htmlAttrs = preprocessedSnapshot.htmlAttrs + const { headStyles, bodyStyles } = preprocessedSnapshot.styles + + return { + $body, + $htmlAttrs, + headStyles, + bodyStyles, + } + } + + const createSnapshot = (name, $elToHighlight, preprocessedSnapshot) => { + Cypress.action('cy:snapshot', name) + + try { + const { + $body, + $htmlAttrs, + ...styleAttrs + } = preprocessedSnapshot ? reifySnapshotBody(preprocessedSnapshot) : createSnapshotBody($elToHighlight) - // preserve attributes on the tag - const htmlAttrs = getHtmlAttrs($$('html')[0]) - // the body we clone via importNode above is attached to a transient document - // so that there are no side effects from cloning it. we only attach it back - // to the AUT document at the last moment (when restoring the snapshot) - // https://github.com/cypress-io/cypress/issues/8679 let attachedBody const body = { get: () => { @@ -212,11 +248,38 @@ export const create = ($$, state) => { const snapshot = { name, - htmlAttrs, + htmlAttrs: $htmlAttrs, body, } - snapshotsMap.set(snapshot, { headStyleIds, bodyStyleIds }) + const { + headStyleIds, + bodyStyleIds, + headStyles, + bodyStyles, + }: { + headStyleIds?: string[] + bodyStyleIds?: string[] + headStyles?: string[] + bodyStyles?: string[] + } = styleAttrs + + if (headStyleIds && bodyStyleIds) { + snapshotsMap.set(snapshot, { + ids: { + headStyleIds, + bodyStyleIds, + }, + }) + } else if (headStyles && bodyStyles) { + // The Snapshot is being reified from cross origin. Get inline styles of reified snapshot. + snapshotsMap.set(snapshot, { + styles: { + headStyles, + bodyStyles, + }, + }) + } return snapshot } catch (e) { diff --git a/packages/driver/src/cypress/log.ts b/packages/driver/src/cypress/log.ts index 66a00e464af0..da408e891170 100644 --- a/packages/driver/src/cypress/log.ts +++ b/packages/driver/src/cypress/log.ts @@ -444,7 +444,7 @@ class Log { this.obj = { highlightAttr: HIGHLIGHT_ATTR, numElements: $el.length, - visible: $el.length === $el.filter(':visible').length, + visible: this.get('visible') ?? $el.length === $el.filter(':visible').length, } return this.set(this.obj, { silent: true }) @@ -505,8 +505,11 @@ class Log { consoleObj[key] = _this.get('name') + // in the case a log is being recreated from the cross-origin spec bridge to the primary, consoleProps may be an Object + const consoleObjDefaults = _.isFunction(consoleProps) ? consoleProps.apply(this, args) : consoleProps + // merge in the other properties from consoleProps - _.extend(consoleObj, consoleProps.apply(this, args)) + _.extend(consoleObj, consoleObjDefaults) // TODO: right here we need to automatically // merge in "Yielded + Element" if there is an $el diff --git a/packages/driver/src/multi-domain/communicator.ts b/packages/driver/src/multi-domain/communicator.ts index 3d8df0e4b537..c9f8cfa3e97f 100644 --- a/packages/driver/src/multi-domain/communicator.ts +++ b/packages/driver/src/multi-domain/communicator.ts @@ -3,10 +3,13 @@ import { EventEmitter } from 'events' import { preprocessConfig, preprocessEnv } from '../util/config' import { preprocessForSerialization, reifySerializedError } from '../util/serialization' import { $Location } from '../cypress/location' +import { preprocessLogForSerialization, reifyLogFromSerialization, preprocessSnapshotForSerialization, reifySnapshotFromSerialization } from '../util/serialization/log' const debug = debugFn('cypress:driver:multi-origin') const CROSS_ORIGIN_PREFIX = 'cross:origin:' +const LOG_EVENTS = [`${CROSS_ORIGIN_PREFIX}log:added`, `${CROSS_ORIGIN_PREFIX}log:changed`] +const FINAL_SNAPSHOT_EVENT = `${CROSS_ORIGIN_PREFIX}final:snapshot:generated` /** * Primary Origin communicator. Responsible for sending/receiving events throughout @@ -42,6 +45,16 @@ export class PrimaryOriginCommunicator extends EventEmitter { this.crossOriginDriverWindows[data.originPolicy] = source as Window } + // reify any logs coming back from the cross-origin spec bridges to serialize snapshot/consoleProp DOM elements as well as select functions. + if (LOG_EVENTS.includes(data?.event)) { + data.data = reifyLogFromSerialization(data.data as any) + } + + // reify the final snapshot coming back from the secondary domain if requested by the runner. + if (FINAL_SNAPSHOT_EVENT === data?.event) { + data.data = reifySnapshotFromSerialization(data.data as any) + } + if (data?.data?.err) { data.data.err = reifySerializedError(data.data.err, this.userInvocationStack as string) } @@ -171,13 +184,24 @@ export class SpecBridgeCommunicator extends EventEmitter { */ toPrimary (event: string, data?: Cypress.ObjectLike, options: { syncGlobals: boolean } = { syncGlobals: false }) { const { originPolicy } = $Location.create(window.location.href) + const eventName = `${CROSS_ORIGIN_PREFIX}${event}` + + // Preprocess logs before sending through postMessage() to attempt to serialize some DOM nodes and functions. + if (LOG_EVENTS.includes(eventName)) { + data = preprocessLogForSerialization(data as any) + } + + // If requested by the runner, preprocess the final snapshot before sending through postMessage() to attempt to serialize the DOM body of the snapshot. + if (FINAL_SNAPSHOT_EVENT === eventName) { + data = preprocessSnapshotForSerialization(data as any) + } debug('<= to Primary ', event, data, originPolicy) if (options.syncGlobals) this.syncGlobalsToPrimary() this.handleSubjectAndErr(data, (data: Cypress.ObjectLike) => { window.top?.postMessage({ - event: `${CROSS_ORIGIN_PREFIX}${event}`, + event: eventName, data, originPolicy, }, '*') diff --git a/packages/driver/src/multi-domain/cypress.ts b/packages/driver/src/multi-domain/cypress.ts index ad485f391412..5a8d8cfb9425 100644 --- a/packages/driver/src/multi-domain/cypress.ts +++ b/packages/driver/src/multi-domain/cypress.ts @@ -6,10 +6,12 @@ import '../config/lodash' import $Cypress from '../cypress' import { $Cy } from '../cypress/cy' +import { $Location } from '../cypress/location' import $Commands from '../cypress/commands' import { create as createLog } from '../cypress/log' import { bindToListeners } from '../cy/listeners' import { handleOriginFn } from './domain_fn' +import { FINAL_SNAPSHOT_NAME } from '../cy/snapshots' import { handleLogs } from './events/logs' import { handleSocketEvents } from './events/socket' import { handleSpecWindowEvents } from './events/spec_window' @@ -30,6 +32,18 @@ const createCypress = () => { setup(config, env) }) + Cypress.specBridgeCommunicator.on('generate:final:snapshot', (snapshotUrl: string) => { + const currentAutOriginPolicy = cy.state('autOrigin') + const requestedSnapshotUrlLocation = $Location.create(snapshotUrl) + + if (requestedSnapshotUrlLocation.originPolicy === currentAutOriginPolicy) { + // if true, this is the correct specbridge to take the snapshot and send it back + const finalSnapshot = cy.createSnapshot(FINAL_SNAPSHOT_NAME) + + Cypress.specBridgeCommunicator.toPrimary('final:snapshot:generated', finalSnapshot) + } + }) + Cypress.specBridgeCommunicator.toPrimary('bridge:ready') } diff --git a/packages/driver/src/multi-domain/events/logs.ts b/packages/driver/src/multi-domain/events/logs.ts index 1a7973c375d6..c686c5004020 100644 --- a/packages/driver/src/multi-domain/events/logs.ts +++ b/packages/driver/src/multi-domain/events/logs.ts @@ -1,12 +1,10 @@ -import { LogUtils } from '../../cypress/log' - export const handleLogs = (Cypress: Cypress.Cypress) => { const onLogAdded = (attrs) => { - Cypress.specBridgeCommunicator.toPrimary('log:added', LogUtils.getDisplayProps(attrs)) + Cypress.specBridgeCommunicator.toPrimary('log:added', attrs) } const onLogChanged = (attrs) => { - Cypress.specBridgeCommunicator.toPrimary('log:changed', LogUtils.getDisplayProps(attrs)) + Cypress.specBridgeCommunicator.toPrimary('log:changed', attrs) } Cypress.on('log:added', onLogAdded) diff --git a/packages/driver/src/util/serialization.ts b/packages/driver/src/util/serialization/index.ts similarity index 91% rename from packages/driver/src/util/serialization.ts rename to packages/driver/src/util/serialization/index.ts index 16d82f3e8bf7..32cfc3ef353e 100644 --- a/packages/driver/src/util/serialization.ts +++ b/packages/driver/src/util/serialization/index.ts @@ -1,7 +1,7 @@ import _ from 'lodash' import structuredClonePonyfill from 'core-js-pure/actual/structured-clone' -import $stackUtils from '../cypress/stack_utils' -import $errUtils from '../cypress/error_utils' +import $stackUtils from '../../cypress/stack_utils' +import $errUtils from '../../cypress/error_utils' export const UNSERIALIZABLE = '__cypress_unserializable_value' @@ -10,7 +10,7 @@ export const UNSERIALIZABLE = '__cypress_unserializable_value' // @ts-ignore const structuredCloneRef = window?.structuredClone || structuredClonePonyfill -const isSerializableInCurrentBrowser = (value: any) => { +export const isSerializableInCurrentBrowser = (value: any) => { try { structuredCloneRef(value) @@ -24,6 +24,12 @@ const isSerializableInCurrentBrowser = (value: any) => { return false } + // In some instances of structuredClone, Bluebird promises are considered serializable, but can be very deep objects + // For ours needs, we really do NOT want to serialize these + if (value instanceof Cypress.Promise) { + return false + } + return true } catch (e) { return false @@ -106,7 +112,8 @@ export const preprocessForSerialization = (valueToSanitize: { [key: string]: // Even if native errors can be serialized through postMessage, many properties are omitted on structuredClone(), including prototypical hierarchy // because of this, we preprocess native errors to objects and postprocess them once they come back to the primary origin - if (_.isArray(valueToSanitize)) { + // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays. This is important for commands like .selectFile() using buffer streams + if (_.isArray(valueToSanitize) || _.isTypedArray(valueToSanitize)) { return _.map(valueToSanitize, preprocessForSerialization) as unknown as T } diff --git a/packages/driver/src/util/serialization/log.ts b/packages/driver/src/util/serialization/log.ts new file mode 100644 index 000000000000..d8a19f0823c7 --- /dev/null +++ b/packages/driver/src/util/serialization/log.ts @@ -0,0 +1,425 @@ +import _ from 'lodash' +import { isSerializableInCurrentBrowser, preprocessForSerialization } from './index' +import $dom from '../../dom' + +interface PreprocessedHTMLElement { + tagName: string + attributes: { [key: string]: string } + innerHTML: string + serializationKey: 'dom' +} + +interface PreprocessedFunction { + value: any + serializationKey: 'function' +} + +/** + * Takes an HTMLElement that might be a for a given snapshot or any other element, likely pertaining to log consoleProps, + * on the page that needs to be preprocessed for serialization. The method here is to do a very shallow serialization, + * by trying to make the HTML as stateful as possible before preprocessing. + * + * @param {HTMLElement} props - an HTMLElement + * @returns {PreprocessedHTMLElement} a preprocessed element that can be fed through postMessage() that can be reified in the primary. + */ +export const preprocessDomElement = (props: HTMLElement) => { + const inputPreprocessArray = Array.from(props.querySelectorAll('input, textarea, select')) + + // Since we serialize on innerHTML, we also need to account for the props element itself in the case it is an input, select, or textarea. + inputPreprocessArray.push(props) + + // Hydrate values in the HTML copy so when serialized they show up correctly in snapshot. + // We do this by mapping certain properties to attributes that are not already reflected in the attributes map. + // Things like id, class, type, and others are reflected in the attribute map and do not need to be explicitly added. + inputPreprocessArray.forEach((el: any) => { + switch (el.type) { + case 'checkbox': + case 'radio': + if (el.checked) { + el.setAttribute('checked', '') + } + + break + case 'select-one': + case 'select-multiple': { + const options = el.type === 'select-one' ? el.options : el.selectedOptions + + if (el.selectedIndex !== -1) { + for (let option of options) { + if (option.selected) { + option.setAttribute('selected', 'true') + } else { + option.removeAttribute('selected') + } + } + } + } + break + case 'textarea': { + el.innerHTML = el.value + } + break + default: + if (el.value !== undefined) { + el.setAttribute('value', el.value) + } + } + }) + + const el: PreprocessedHTMLElement = { + tagName: props.tagName, + attributes: {}, + innerHTML: props.innerHTML, + serializationKey: 'dom', + } + + // get all attributes and classes off the element + props.getAttributeNames().forEach((attributeName) => { + el.attributes[attributeName] = props.getAttribute(attributeName) || '' + }) + + return el +} + +/** + * Takes an PreprocessedHTMLElement that might represent a given snapshot or any other element that needs to be reified + * after postMessage() serialization. The method here is to do a very basic reification, + * attempting to create an element based off the PreprocessedHTMLElement tagName, and populating some basic state if applicable, + * such as element type, id, value, classes, attributes, etc. + * + * @param {PreprocessedHTMLElement} props - a preprocessed element that was fed through postMessage() that need to be reified in the primary. + * @returns {HTMLElement} a reified element, likely a log snapshot, $el, or consoleProp elements. + */ +export const reifyDomElement = (props: any) => { + const reifiedEl = document.createElement(props.tagName) + + reifiedEl.innerHTML = props.innerHTML + + Object.keys(props.attributes).forEach((attribute) => { + reifiedEl.setAttribute(attribute, props.attributes[attribute]) + }) + + return reifiedEl +} + +/** + * Attempts to preprocess an Object/Array by excluding unserializable values except for DOM elements and possible functions (if attemptToSerializeFunctions is true). + * DOM elements are processed to a serializable object via preprocessDomElement, and functions are serialized to an object with a value key containing their output contents. + * + * @param {any} props an Object/Array that needs to be preprocessed before being sent through postMessage(). + * @param {boolean} [attemptToSerializeFunctions=false] - Whether or not the function should attempt to preprocess a function by invoking it. + * @returns + */ +export const preprocessObjectLikeForSerialization = (props, attemptToSerializeFunctions = false) => { + if (_.isArray(props)) { + return props.map((prop) => preprocessLogLikeForSerialization(prop, attemptToSerializeFunctions)) + } + + if (_.isPlainObject(props)) { + // only attempt to try and serialize dom elements and functions (if attemptToSerializeFunctions is set to true) + let objWithPossiblySerializableProps = _.pickBy(props, (value) => { + const isSerializable = isSerializableInCurrentBrowser(value) + + if (!isSerializable && $dom.isDom(value) || _.isFunction(value) || _.isObject(value)) { + return true + } + + return false + }) + + let objWithOnlySerializableProps = _.pickBy(props, (value) => isSerializableInCurrentBrowser(value)) + + // assign the properties we know we can serialize here + let preprocessed: any = preprocessForSerialization(objWithOnlySerializableProps) + + // and attempt to serialize possibly unserializable props here and fail gracefully if unsuccessful + _.forIn(objWithPossiblySerializableProps, (value, key) => { + preprocessed[key] = preprocessLogLikeForSerialization(value, attemptToSerializeFunctions) + }) + + return preprocessed + } + + return preprocessForSerialization(props) +} + +/** + * Attempts to take an Object and reify it correctly. Most of this is handled by reifyLogLikeFromSerialization, with the exception here being DOM elements. + * DOM elements, if needed to match against the snapshot DOM, are defined as getters on the object to have their values calculated at request. + * This is important for certain log items, such as consoleProps, to be rendered correctly against the snapshot. Other DOM elements, such as snapshots, do not need to be matched + * against the current DOM and can be reified immediately. Since there is a potential need for object getters to exist within an array, arrays are wrapped in a proxy, with array indices + * proxied to the reified object or array, and other methods proxying to the preprocessed array (such as native array methods like map, foreach, etc...). + * + * @param {Object} props - a preprocessed Object/Array that was fed through postMessage() that need to be reified in the primary. + * @param {boolean} matchElementsAgainstSnapshotDOM - whether DOM elements within the Object/Array should be matched against + * @returns {Object|Proxy} - a reified version of the Object or Array (Proxy). + */ +export const reifyObjectLikeForSerialization = (props, matchElementsAgainstSnapshotDOM) => { + let reifiedObjectOrArray = {} + + _.forIn(props, (value, key) => { + const val = reifyLogLikeFromSerialization(value, matchElementsAgainstSnapshotDOM) + + if (val?.serializationKey === 'dom') { + if (matchElementsAgainstSnapshotDOM) { + // dynamically calculate the element (snapshot or otherwise). + // This is important for consoleProp/$el based properties on the log because it calculates the requested element AFTER the snapshot has been rendered into the AUT. + reifiedObjectOrArray = { + ...reifiedObjectOrArray, + get [key] () { + return val.reifyElement() + }, + } + } else { + // The DOM element in question is something like a snapshot. It can be reified immediately + reifiedObjectOrArray[key] = val.reifyElement() + } + } else { + reifiedObjectOrArray[key] = reifyLogLikeFromSerialization(value, matchElementsAgainstSnapshotDOM) + } + }) + + // NOTE: transforms arrays into objects to have defined getters for DOM elements, and proxy back to that object via an ES6 Proxy. + if (_.isArray(props)) { + // if an array, map the array to our special getter object. + return new Proxy(reifiedObjectOrArray, { + get (target, name) { + return target[name] || props[name] + }, + }) + } + + // otherwise, just returned the object with our special getter + return reifiedObjectOrArray +} + +/** + * Attempts to take a generic data structure that is log-like and preprocess them for serialization. This generic may contain properties that are either + * a) unserializable entirely + * b) unserializable natively but can be processed to a serializable form (DOM elements or Functions) + * c) serializable + * + * DOM elements are preprocessed via some key properties + * (attributes, classes, ids, tagName, value) including their innerHTML. Before the innerHTML is captured, inputs are traversed to set their stateful value + * inside the DOM element. This is crucial for body copy snapshots that are being sent to the primary domain to make the snapshot 'stateful'. Functions, if + * explicitly stated, will be preprocessed with whatever value they return (assuming that value is serializable). If a value cannot be preprocessed for whatever reason, + * null is returned. + * + * + * NOTE: this function recursively calls itself to preprocess a log + * + * @param {any} props a generic variable that represents a value that needs to be preprocessed before being sent through postMessage(). + * @param {boolean} [attemptToSerializeFunctions=false] - Whether or not the function should attempt to preprocess a function by invoking it. USE WITH CAUTION! + * @returns {any} the serializable version of the generic. + */ +export const preprocessLogLikeForSerialization = (props, attemptToSerializeFunctions = false) => { + try { + if ($dom.isDom(props)) { + if (props.length !== undefined && $dom.isJquery(props)) { + const serializableArray: any[] = [] + + // in the case we are dealing with a jQuery array, preprocess to a native array to nuke any prevObject(s) or unserializable values + props.each((key) => serializableArray.push(preprocessLogLikeForSerialization(props[key], attemptToSerializeFunctions))) + + return serializableArray + } + + // otherwise, preprocess the element to an object with pertinent DOM properties + const serializedDom = preprocessDomElement(props) + + return serializedDom + } + + /** + * When preprocessing a log, there might be certain functions we want to attempt to serialize. + * One of these instances is the 'table' key in consoleProps, which has contents that CAN be serialized. + * If there are other functions that have serializable contents, the invoker/developer will need to be EXPLICIT + * in what needs serialization. Otherwise, functions should NOT be serialized. + */ + if (_.isFunction(props)) { + if (attemptToSerializeFunctions) { + return { + value: preprocessLogLikeForSerialization(props(), attemptToSerializeFunctions), + serializationKey: 'function', + } as PreprocessedFunction + } + + return null + } + + if (_.isObject(props)) { + return preprocessObjectLikeForSerialization(props, attemptToSerializeFunctions) + } + + return preprocessForSerialization(props) + } catch (e) { + return null + } +} + +/** + * Attempts to take in a preprocessed/serialized log-like attributes and reify them. DOM elements are lazily calculated via + * getter properties on an object. If these DOM elements are in an array, the array is defined as an ES6 proxy that + * ultimately proxies to these getter objects. Functions, if serialized, are rewrapped. If a value cannot be reified for whatever reason, + * null is returned. + * + * This is logLike because there is a need outside of logs, such as in the iframe-model in the runner. + * to serialize DOM elements, such as the final snapshot upon request. + * + * NOTE: this function recursively calls itself to reify a log + * + * @param {any} props - a generic variable that represents a value that has been preprocessed and sent through postMessage() and needs to be reified. + * @param {boolean} matchElementsAgainstSnapshotDOM - Whether or not the element should be reconstructed lazily + * against the currently rendered DOM (usually against a rendered snapshot) or should be completely recreated from scratch (common with snapshots as they will replace the DOM) + * @returns {any} the reified version of the generic. + */ +export const reifyLogLikeFromSerialization = (props, matchElementsAgainstSnapshotDOM = true) => { + try { + if (props?.serializationKey === 'dom') { + props.reifyElement = function () { + let reifiedElement + + // If the element needs to be matched against the currently rendered DOM. This is useful when analyzing consoleProps or $el in a log + // where elements need to be evaluated LAZILY after the snapshot is attached to the page. + // this option is set to false when reifying snapshots, since they will be replacing the current DOM when the user interacts with said snapshot. + if (matchElementsAgainstSnapshotDOM) { + const attributes = Object.keys(props.attributes).map((attribute) => { + return `[${attribute}="${props.attributes[attribute]}"]` + }).join('') + + const selector = `${props.tagName}${attributes}` + + reifiedElement = Cypress.$(selector) + + if (reifiedElement.length) { + return reifiedElement.length > 1 ? reifiedElement : reifiedElement[0] + } + } + + // if the element couldn't be found, return a synthetic copy that doesn't actually exist on the page + return reifyDomElement(props) + } + + return props + } + + if (props?.serializationKey === 'function') { + const reifiedFunctionData = reifyLogLikeFromSerialization(props.value, matchElementsAgainstSnapshotDOM) + + return () => reifiedFunctionData + } + + if (_.isObject(props)) { + return reifyObjectLikeForSerialization(props, matchElementsAgainstSnapshotDOM) + } + + return props + } catch (e) { + return null + } +} + +/** + * Preprocess a snapshot to a serializable form before piping them over through postMessage(). + * This method is also used by a spec bridge on request if a 'final state' snapshot is requested outside that of the primary domain + * + * @param {any} snapshot - a snapshot matching the same structure that is returned from cy.createSnapshot. + * @returns a serializable form of a snapshot, including a serializable with styles + */ +export const preprocessSnapshotForSerialization = (snapshot) => { + try { + const preprocessedSnapshot = preprocessLogLikeForSerialization(snapshot, true) + + if (!preprocessedSnapshot.body.get) { + return null + } + + preprocessedSnapshot.styles = cy.getStyles(snapshot) + + return preprocessedSnapshot + } catch (e) { + return null + } +} + +/** + * Reifies a snapshot from the serializable from to an actual HTML body snapshot that exists in the primary document. + * @param {any} snapshot - a snapshot that has been preprocessed and sent through post message and needs to be reified in the primary. + * @returns the reified snapshot that exists in the primary document + */ +export const reifySnapshotFromSerialization = (snapshot) => { + snapshot.body = reifyLogLikeFromSerialization(snapshot.body, false) + + return cy.createSnapshot(snapshot.name, null, snapshot) +} + +/** + * Sanitizes the log messages going to the primary domain before piping them to postMessage(). + * This is designed to function as an extension of preprocessForSerialization, but also attempts to serialize DOM elements, + * as well as functions if explicitly stated. + * + * DOM elements are serialized with their outermost properties (attributes, classes, ids, tagName) including their innerHTML. + * DOM Traversal serialization is not possible with larger html bodies and will likely cause a stack overflow. + * + * Functions are serialized when explicitly state (ex: table in consoleProps). + * NOTE: If not explicitly handling function serialization for a given property, the property will be set to null + * + * @param logAttrs raw log attributes passed in from either a log:changed or log:added event + * @returns a serializable form of the log, including attempted serialization of DOM elements and Functions (if explicitly stated) + */ +export const preprocessLogForSerialization = (logAttrs) => { + let { snapshots, ...logAttrsRest } = logAttrs + + const preprocessed = preprocessLogLikeForSerialization(logAttrsRest) + + if (preprocessed) { + if (snapshots) { + preprocessed.snapshots = snapshots.map((snapshot) => preprocessSnapshotForSerialization(snapshot)) + } + + if (logAttrs?.consoleProps?.table) { + preprocessed.consoleProps.table = preprocessLogLikeForSerialization(logAttrs.consoleProps.table, true) + } + } + + return preprocessed +} + +/** + * Redefines log messages being received in the primary domain before sending them out through the event-manager. + * + * Efforts here include importing captured snapshots from the spec bridge into the primary snapshot document, importing inline + * snapshot styles into the snapshot css map, and reconstructing DOM elements and functions somewhat naively. + * + * To property render consoleProps/$el elements in snapshots or the console, DOM elements are lazily calculated via + * getter properties on an object. If these DOM elements are in an array, the array is defined as an ES6 proxy that + * ultimately proxies to these getter objects. + * + * The secret here is that consoleProp DOM elements needs to be reified at console printing runtime AFTER the serialized snapshot + * is attached to the DOM so the element can be located and displayed properly + * + * In most cases, the element can be queried by attributes that exist specifically on the element or by the `HIGHLIGHT_ATTR`. If that fails or does not locate an element, + * then a new element is created against the snapshot context. This element will NOT be found on the page, but will represent what the element + * looked like at the time of the snapshot. + * + * @param logAttrs serialized/preprocessed log attributes passed to the primary domain from a spec bridge + * @returns a reified version of what a log is supposed to look like in Cypress + */ +export const reifyLogFromSerialization = (logAttrs) => { + let { snapshots, ... logAttrsRest } = logAttrs + + if (snapshots) { + snapshots = snapshots.filter((snapshot) => !!snapshot).map((snapshot) => reifySnapshotFromSerialization(snapshot)) + } + + const reified = reifyLogLikeFromSerialization(logAttrsRest) + + if (reified.$el && reified.$el.length) { + // Make sure $els are jQuery Arrays to keep what is expected in the log. + reified.$el = Cypress.$(reified.$el.map((el) => el)) + } + + reified.snapshots = snapshots + + return reified +} diff --git a/packages/driver/types/internal-types.d.ts b/packages/driver/types/internal-types.d.ts index 82a0754ded3e..4c470a0f8b9a 100644 --- a/packages/driver/types/internal-types.d.ts +++ b/packages/driver/types/internal-types.d.ts @@ -46,6 +46,8 @@ declare namespace Cypress { isAnticipatingCrossOriginResponseFor: IStability['isAnticipatingCrossOriginResponseFor'] fail: (err: Error, options:{ async?: boolean }) => Error getRemoteLocation: ILocation['getRemoteLocation'] + createSnapshot: ISnapshots['createSnapshot'] + getStyles: ISnapshots['getStyles'] } interface Cypress { diff --git a/packages/driver/types/spec-types.d.ts b/packages/driver/types/spec-types.d.ts new file mode 100644 index 000000000000..c0ebdbfc6d2a --- /dev/null +++ b/packages/driver/types/spec-types.d.ts @@ -0,0 +1,8 @@ +// NOTE: This is for internal Cypress spec types that exist in support/utils.js for testing convenience and do not ship with Cypress + +declare namespace Cypress { + interface Chainable { + getAll(...aliases: string[]): Chainable + shouldWithTimeout(cb: (subj: {}) => void, timeout?: number): Chainable + } +} diff --git a/packages/runner-ct/src/iframe/iframes.tsx b/packages/runner-ct/src/iframe/iframes.tsx index 2c7771e1c9e9..2658c9a269b3 100644 --- a/packages/runner-ct/src/iframe/iframes.tsx +++ b/packages/runner-ct/src/iframe/iframes.tsx @@ -133,6 +133,8 @@ export const Iframes = namedObserver('Iframes', ({ restoreDom: autIframe.current.restoreDom, highlightEl: autIframe.current.highlightEl, detachDom: autIframe.current.detachDom, + isAUTSameOrigin: autIframe.current.doesAUTMatchTopOriginPolicy, + removeSrc: autIframe.current.removeSrcAttribute, snapshotControls: (snapshotProps) => ( { + // If the test is over and the user enters interactive snapshot mode, do not add cross origin logs to the test runner. + if (Cypress.state('test')?.final) return + // Create a new local log representation of the cross origin log. // It will be attached to the current command. // We also keep a reference to it to update it in the future. diff --git a/packages/runner-shared/src/iframe/aut-iframe.js b/packages/runner-shared/src/iframe/aut-iframe.js index 96275c00221f..4a321ba4f31e 100644 --- a/packages/runner-shared/src/iframe/aut-iframe.js +++ b/packages/runner-shared/src/iframe/aut-iframe.js @@ -69,6 +69,40 @@ export class AutIframe { return Cypress.cy.detachDom(this._contents()) } + /** + * If the AUT is cross origin relative to top, a security error is thrown and the method returns false + * If the AUT is cross origin relative to top and chromeWebSecurity is false, origins of the AUT and top need to be compared and returns false + * Otherwise, if top and the AUT match origins, the method returns true. + * If the AUT origin is "about://blank", that means the src attribute has been stripped off the iframe and is adhering to same origin policy + */ + doesAUTMatchTopOriginPolicy = () => { + const Cypress = eventManager.getCypress() + + if (!Cypress) return + + try { + const { href: currentHref } = this.$iframe[0].contentWindow.document.location + const locationTop = Cypress.Location.create(window.location.href) + const locationAUT = Cypress.Location.create(currentHref) + + return locationTop.originPolicy === locationAUT.originPolicy || locationAUT.originPolicy === 'about://blank' + } catch (err) { + if (err.name === 'SecurityError') { + return false + } + + throw err + } + } + + /** + * Removes the src attribute from the AUT iframe, resulting in 'about:blank' being loaded into the iframe + * See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-src for more details + */ + removeSrcAttribute = () => { + this.$iframe.removeAttr('src') + } + visitBlank = ({ type } = { type: null }) => { return new Promise((resolve) => { this.$iframe[0].src = 'about:blank' @@ -91,6 +125,23 @@ export class AutIframe { } restoreDom = (snapshot) => { + if (!this.doesAUTMatchTopOriginPolicy()) { + /** + * A load event fires here when the src is removed (as does an unload event). + * This is equivalent to loading about:blank (see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#attr-src). + * This doesn't resort in a log message being generated for a new page. + * In the event-manager code, we stop adding logs from other domains once the spec is finished. + */ + this.$iframe.one('load', () => { + this.restoreDom(snapshot) + }) + + // The iframe is in a cross origin state. Remove the src attribute to adhere to same origin policy. NOTE: This should only be done ONCE. + this.removeSrcAttribute() + + return + } + const Cypress = eventManager.getCypress() const { headStyles, bodyStyles } = Cypress ? Cypress.cy.getStyles(snapshot) : {} const { body, htmlAttrs } = snapshot diff --git a/packages/runner-shared/src/iframe/iframe-model.js b/packages/runner-shared/src/iframe/iframe-model.js index e2639ce6974c..fca3665fb22c 100644 --- a/packages/runner-shared/src/iframe/iframe-model.js +++ b/packages/runner-shared/src/iframe/iframe-model.js @@ -6,12 +6,14 @@ import { studioRecorder } from '../studio' import { eventManager } from '../event-manager' export class IframeModel { - constructor ({ state, detachDom, restoreDom, highlightEl, snapshotControls }) { + constructor ({ state, detachDom, restoreDom, highlightEl, snapshotControls, isAUTSameOrigin, removeSrc }) { this.state = state this.detachDom = detachDom this.restoreDom = restoreDom this.highlightEl = highlightEl this.snapshotControls = snapshotControls + this.isAUTSameOrigin = isAUTSameOrigin + this.removeSrc = removeSrc this._reset() } @@ -217,6 +219,31 @@ export class IframeModel { } _storeOriginalState () { + if (!this.isAUTSameOrigin()) { + const Cypress = eventManager.getCypress() + + /** + * This only happens if the AUT ends in a cross origin state that the primary doesn't have access to. + * In this case, the final snapshot request from the primary is sent out to the cross-origin spec bridges. + * The spec bridge that matches the origin policy will take a snapshot and send it back to the primary for the runner to store in originalState. + */ + Cypress.primaryOriginCommunicator.toAllSpecBridges('generate:final:snapshot', this.state.url) + Cypress.primaryOriginCommunicator.once('final:snapshot:generated', (finalSnapshot) => { + this.originalState = { + body: finalSnapshot.body, + htmlAttrs: finalSnapshot.htmlAttrs, + snapshot: finalSnapshot, + url: this.state.url, + // TODO: use same attr for both runner and runner-ct states. + // these refer to the same thing - the viewport dimensions. + viewportWidth: this.state.width, + viewportHeight: this.state.height, + } + }) + + return + } + const finalSnapshot = this.detachDom() if (!finalSnapshot) return diff --git a/packages/runner/index.d.ts b/packages/runner/index.d.ts index 918d244cd9e7..8e559dc28663 100644 --- a/packages/runner/index.d.ts +++ b/packages/runner/index.d.ts @@ -8,3 +8,4 @@ /// /// +/// diff --git a/packages/runner/src/iframe/iframes.jsx b/packages/runner/src/iframe/iframes.jsx index cf5407378eef..f5aea2a75673 100644 --- a/packages/runner/src/iframe/iframes.jsx +++ b/packages/runner/src/iframe/iframes.jsx @@ -109,6 +109,8 @@ export default class Iframes extends Component { restoreDom: this.autIframe.restoreDom, highlightEl: this.autIframe.highlightEl, detachDom: this.autIframe.detachDom, + isAUTSameOrigin: this.autIframe.doesAUTMatchTopOriginPolicy, + removeSrc: this.autIframe.removeSrcAttribute, snapshotControls: (snapshotProps) => (