From 304d8bd73a5b576747416115a5a16eabe1cef622 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Mon, 7 Feb 2022 10:22:04 -0800 Subject: [PATCH 01/35] Make performance-reporter for system tests use get-next-version script --- scripts/get-next-version.js | 6 ++++++ system-tests/lib/performance-reporter.js | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/scripts/get-next-version.js b/scripts/get-next-version.js index b389a28dc7f6..949e9ba7fc22 100644 --- a/scripts/get-next-version.js +++ b/scripts/get-next-version.js @@ -24,6 +24,12 @@ const getNextVersionForPath = async (path) => { return semver.inc(currentVersion, releaseType || 'patch') } +if (require.main !== module) { + module.exports.getNextVersionForPath = getNextVersionForPath + + return +} + Bluebird.mapSeries(paths, async (path) => { const pathNextVersion = await getNextVersionForPath(path) diff --git a/system-tests/lib/performance-reporter.js b/system-tests/lib/performance-reporter.js index 8200ae4effca..0d51f8eacecc 100644 --- a/system-tests/lib/performance-reporter.js +++ b/system-tests/lib/performance-reporter.js @@ -2,9 +2,9 @@ const path = require('path') const chalk = require('chalk') const Libhoney = require('libhoney') -const pkg = require('@packages/root') const ciProvider = require('@packages/server/lib/util/ci_provider') const { commitInfo } = require('@cypress/commit-info') +const { getNextVersionForPath } = require('../../scripts/get-next-version') class StatsdReporter { constructor (runner) { @@ -16,6 +16,7 @@ class StatsdReporter { let branch let commitSha + let nextVersion this.honey = new Libhoney({ dataset: 'systemtest-performance', @@ -29,6 +30,8 @@ class StatsdReporter { commitSha = commitInformation.sha || ciInformation.sha }) + getNextVersionForPath('../../packages').then((next) => nextVersion = next) + runner.on('test', (test) => { test.wallclockStart = Date.now() }) @@ -64,7 +67,7 @@ class StatsdReporter { buildUrl: process.env.CIRCLE_BUILD_URL, platform: process.platform, arch: process.arch, - version: pkg.version, + version: nextVersion, }) honeycombEvent.send() From ac5bfd319bfaab36829f1ebfdac9a4bbea3b3867 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Mon, 7 Feb 2022 11:37:55 -0800 Subject: [PATCH 02/35] Use honeycomb tracing --- system-tests/lib/performance-reporter.js | 109 +++++++++++++++-------- 1 file changed, 74 insertions(+), 35 deletions(-) diff --git a/system-tests/lib/performance-reporter.js b/system-tests/lib/performance-reporter.js index 0d51f8eacecc..38f6162aad72 100644 --- a/system-tests/lib/performance-reporter.js +++ b/system-tests/lib/performance-reporter.js @@ -1,47 +1,44 @@ const path = require('path') const chalk = require('chalk') const Libhoney = require('libhoney') +const { v4: uuidv4 } = require('uuid') const ciProvider = require('@packages/server/lib/util/ci_provider') const { commitInfo } = require('@cypress/commit-info') const { getNextVersionForPath } = require('../../scripts/get-next-version') -class StatsdReporter { +class HoneycombReporter { constructor (runner) { if (!process.env.HONEYCOMB_API_KEY) { return } console.log(chalk.green('Reporting to honeycomb')) - - let branch - let commitSha - let nextVersion - this.honey = new Libhoney({ dataset: 'systemtest-performance', writeKey: process.env.HONEYCOMB_API_KEY, }) - commitInfo().then((commitInformation) => { - const ciInformation = ciProvider.commitParams() || {} + runner.on('suite', (suite) => { + if (suite.root) { + suite.honeycombEvent = this.rootEvent() - branch = commitInformation.branch || ciInformation.branch - commitSha = commitInformation.sha || ciInformation.sha - }) + return + } - getNextVersionForPath('../../packages').then((next) => nextVersion = next) + suite.honeycombEvent = this.honey.newEvent() + suite.honeycombEvent.timestamp = Date.now() + suite.honeycombEvent.add({ + suite: suite.title, + specFile: path.basename(suite.file), - runner.on('test', (test) => { - test.wallclockStart = Date.now() + spanId: uuidv4(), + parentId: suite.parent.honeycombEvent.data.spanId, + traceId: suite.parent.honeycombEvent.data.traceId, + }) }) - runner.on('test end', (test) => { - // Skipped tests never get a 'start' event, but they still get 'test end' somehow. - if (!test.state || test.state === 'skipped') { - return - } - + runner.on('test', (test) => { const title = test.titlePath().join(' / ') // This regex pulls apart a string like `e2e async timeouts / failing1 [electron]` // into `e2e async timeouts / failing1` and `electron`, letting us use the same @@ -50,27 +47,40 @@ class StatsdReporter { // in which case it will be undefined and not passed as a field to honeycomb. const [, testTitle, browser] = title.match(/(.+?)(?: \[([a-z]+)\])?$/) - const honeycombEvent = this.honey.newEvent() - - honeycombEvent.timestamp = test.wallclockStart - honeycombEvent.add({ + test.honeycombEvent = this.honey.newEvent() + test.honeycombEvent.timestamp = Date.now() + test.honeycombEvent.add({ test: testTitle, - specFile: path.basename(test.file), browser, + + spanId: uuidv4(), + parentId: test.parent.honeycombEvent.data.spanId, + traceId: test.parent.honeycombEvent.data.traceId, + }) + }) + + runner.on('test end', (test) => { + // Skipped tests never get a 'start' event, but they still get 'test end' somehow. + if (!test.state || test.state === 'skipped') { + return + } + + test.honeycombEvent.add({ state: test.state, err: test.err && test.err.message, errStack: test.err && test.err.stack, - durationMs: Date.now() - test.wallclockStart, - mochaDurationMs: test.duration, - branch, - commitSha, - buildUrl: process.env.CIRCLE_BUILD_URL, - platform: process.platform, - arch: process.arch, - version: nextVersion, + durationMs: Date.now() - test.honeycombEvent.timestamp, + }) + + test.honeycombEvent.send() + }) + + runner.on('suite end', (suite) => { + suite.honeycombEvent.add({ + durationMs: Date.now() - suite.honeycombEvent.timestamp, }) - honeycombEvent.send() + suite.honeycombEvent.send() }) } @@ -80,6 +90,35 @@ class StatsdReporter { this.honey.flush().then(callback) } } + + rootEvent () { + const honeycombEvent = this.honey.newEvent() + + honeycombEvent.timestamp = Date.now() + honeycombEvent.add({ + buildUrl: process.env.CIRCLE_BUILD_URL, + platform: process.platform, + arch: process.arch, + + spanId: uuidv4(), + traceId: uuidv4(), + }) + + commitInfo().then((commitInformation) => { + const ciInformation = ciProvider.commitParams() || {} + + honeycombEvent.add({ + branch: commitInformation.branch || ciInformation.branch, + commitSha: commitInformation.sha || ciInformation.sha, + }) + }) + + getNextVersionForPath('../../packages').then((next) => { + honeycombEvent.add({ nextVersion: next }) + }) + + return honeycombEvent + } } -module.exports = StatsdReporter +module.exports = HoneycombReporter From 0d834bc6b3b92f57863b160693128e7d0ae32564 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Mon, 7 Feb 2022 12:25:35 -0800 Subject: [PATCH 03/35] Add data to all events sent, not just top level --- system-tests/lib/performance-reporter.js | 44 ++++++++++++++++-------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/system-tests/lib/performance-reporter.js b/system-tests/lib/performance-reporter.js index 38f6162aad72..74ff8e4e3cba 100644 --- a/system-tests/lib/performance-reporter.js +++ b/system-tests/lib/performance-reporter.js @@ -29,13 +29,15 @@ class HoneycombReporter { suite.honeycombEvent = this.honey.newEvent() suite.honeycombEvent.timestamp = Date.now() suite.honeycombEvent.add({ + ...suite.parent.honeycombEvent.data, suite: suite.title, specFile: path.basename(suite.file), spanId: uuidv4(), parentId: suite.parent.honeycombEvent.data.spanId, - traceId: suite.parent.honeycombEvent.data.traceId, }) + + this.addAsyncInfo(suite.honeycombEvent) }) runner.on('test', (test) => { @@ -50,13 +52,15 @@ class HoneycombReporter { test.honeycombEvent = this.honey.newEvent() test.honeycombEvent.timestamp = Date.now() test.honeycombEvent.add({ + ...test.parent.honeycombEvent.data, test: testTitle, browser, spanId: uuidv4(), parentId: test.parent.honeycombEvent.data.spanId, - traceId: test.parent.honeycombEvent.data.traceId, }) + + this.addAsyncInfo(test.honeycombEvent) }) runner.on('test end', (test) => { @@ -72,7 +76,8 @@ class HoneycombReporter { durationMs: Date.now() - test.honeycombEvent.timestamp, }) - test.honeycombEvent.send() + console.log(test.honeycombEvent.data) + // test.honeycombEvent.send() }) runner.on('suite end', (suite) => { @@ -104,20 +109,31 @@ class HoneycombReporter { traceId: uuidv4(), }) - commitInfo().then((commitInformation) => { - const ciInformation = ciProvider.commitParams() || {} + this.addAsyncInfo(honeycombEvent) - honeycombEvent.add({ - branch: commitInformation.branch || ciInformation.branch, - commitSha: commitInformation.sha || ciInformation.sha, - }) - }) + return honeycombEvent + } - getNextVersionForPath('../../packages').then((next) => { - honeycombEvent.add({ nextVersion: next }) - }) + // Because mocha has no way to wait on async functions inside hooks, + // and we need to call various async functions to gather data about + // the testing environment, we create a promise that can be used by each + // honeycomb event to add async data that won't be initialized by the + // time mocha starts running tests. + addAsyncInfo (honeycombEvent) { + if (!this.asyncInfo) { + this.asyncInfo = Promise.all([getNextVersionForPath('../../packages'), commitInfo()]) + .then(([nextVersion, commitInformation]) => { + const ciInformation = ciProvider.commitParams() || {} + + return { + nextVersion, + branch: commitInformation.branch || ciInformation.branch, + commitSha: commitInformation.sha || ciInformation.sha, + } + }) + } - return honeycombEvent + this.asyncInfo.then((info) => honeycombEvent.add(info)) } } From 980b951580f8973f555195b8e9d39bb065ae2675 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Tue, 8 Feb 2022 09:34:59 -0800 Subject: [PATCH 04/35] Tweak honeycomb events further --- system-tests/lib/performance-reporter.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/system-tests/lib/performance-reporter.js b/system-tests/lib/performance-reporter.js index 74ff8e4e3cba..9cb13694f61a 100644 --- a/system-tests/lib/performance-reporter.js +++ b/system-tests/lib/performance-reporter.js @@ -41,13 +41,13 @@ class HoneycombReporter { }) runner.on('test', (test) => { - const title = test.titlePath().join(' / ') - // This regex pulls apart a string like `e2e async timeouts / failing1 [electron]` - // into `e2e async timeouts / failing1` and `electron`, letting us use the same + const path = test.titlePath() + // This regex pulls apart a string like `failing1 [electron]` + // into `failing1` and `electron`, letting us use the same // test name for all browsers, with the browser as a separate field. // The browser capture group is optional because some tests aren't browser specific, // in which case it will be undefined and not passed as a field to honeycomb. - const [, testTitle, browser] = title.match(/(.+?)(?: \[([a-z]+)\])?$/) + const [, testTitle, browser] = path[path.length - 1].match(/(.+?)(?: \[([a-z]+)\])?$/) test.honeycombEvent = this.honey.newEvent() test.honeycombEvent.timestamp = Date.now() @@ -76,8 +76,7 @@ class HoneycombReporter { durationMs: Date.now() - test.honeycombEvent.timestamp, }) - console.log(test.honeycombEvent.data) - // test.honeycombEvent.send() + test.honeycombEvent.send() }) runner.on('suite end', (suite) => { From 5e96b5cc27b81544482360e72c8ee0b7388de3d8 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Tue, 8 Feb 2022 09:52:17 -0800 Subject: [PATCH 05/35] Attepmt to associate all circleci jobs for a given build into one trace --- system-tests/lib/performance-reporter.js | 2 +- yarn.lock | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/system-tests/lib/performance-reporter.js b/system-tests/lib/performance-reporter.js index 9cb13694f61a..cde49fbe6ac2 100644 --- a/system-tests/lib/performance-reporter.js +++ b/system-tests/lib/performance-reporter.js @@ -105,7 +105,7 @@ class HoneycombReporter { arch: process.arch, spanId: uuidv4(), - traceId: uuidv4(), + traceId: process.env.CIRCLE_WORKFLOW_ID || uuidv4(), }) this.addAsyncInfo(honeycombEvent) diff --git a/yarn.lock b/yarn.lock index d2b0f7d25522..d66397cfb501 100644 --- a/yarn.lock +++ b/yarn.lock @@ -35559,7 +35559,7 @@ shell-quote@1.7.2, shell-quote@^1.4.2, shell-quote@^1.6.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== -shelljs@0.8.5: +shelljs@0.8.5, shelljs@^0.8.4: version "0.8.5" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== @@ -35568,15 +35568,6 @@ shelljs@0.8.5: interpret "^1.0.0" rechoir "^0.6.2" -shelljs@^0.8.4: - version "0.8.4" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" - integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" From f694bd2bb6edcdb8bbf285742c3d2e2f168a2188 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Tue, 8 Feb 2022 10:33:15 -0800 Subject: [PATCH 06/35] Another attempt to wrap all events into one trace --- circle.yml | 8 +++ system-tests/lib/performance-reporter.js | 67 ++++++++++++------------ 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/circle.yml b/circle.yml index 008a830a3f8d..5aae40de43d0 100644 --- a/circle.yml +++ b/circle.yml @@ -233,6 +233,13 @@ commands: paths: - system_tests_node_modules_installed + send_system_test_honecomb_event: + description: 'Send a root event to honeycomb for this build' + steps: + - run: + name: Send honeycomb event + command: node ./system-tests/lib/performance-reporter.js + caching-dependency-installer: description: 'Installs & caches the dependencies based on yarn lock & package json dependencies' parameters: @@ -1155,6 +1162,7 @@ jobs: steps: - restore_cached_workspace - update_cached_system_tests_deps + - send_system_test_honecomb_event system-tests-chrome: <<: *defaults diff --git a/system-tests/lib/performance-reporter.js b/system-tests/lib/performance-reporter.js index cde49fbe6ac2..f7af6856cb47 100644 --- a/system-tests/lib/performance-reporter.js +++ b/system-tests/lib/performance-reporter.js @@ -7,6 +7,33 @@ const ciProvider = require('@packages/server/lib/util/ci_provider') const { commitInfo } = require('@cypress/commit-info') const { getNextVersionForPath } = require('../../scripts/get-next-version') +const honey = new Libhoney({ + dataset: 'systemtest-performance', + writeKey: process.env.HONEYCOMB_API_KEY, +}) + +const spanId = process.env.CIRCLE_WORKFLOW_ID || uuidv4() +const circleCiRootEvent = honey.newEvent() + +circleCiRootEvent.timestamp = Date.now() +circleCiRootEvent.add({ + buildUrl: process.env.CIRCLE_BUILD_URL, + platform: process.platform, + arch: process.arch, + + spanId, + traceId: spanId, +}) + +// This file is executed once as a script at the beginning of the circleci build, +// so that we can send the root event exactly once and associate all the various +// system test tasks and build steps into a single span. +if (require.main === module) { + console.log(circleCiRootEvent.data) + circleCiRootEvent.send() + honey.flush() +} + class HoneycombReporter { constructor (runner) { if (!process.env.HONEYCOMB_API_KEY) { @@ -14,27 +41,19 @@ class HoneycombReporter { } console.log(chalk.green('Reporting to honeycomb')) - this.honey = new Libhoney({ - dataset: 'systemtest-performance', - writeKey: process.env.HONEYCOMB_API_KEY, - }) runner.on('suite', (suite) => { - if (suite.root) { - suite.honeycombEvent = this.rootEvent() + const parent = suite.root ? circleCiRootEvent : suite.parent.honeycombEvent - return - } - - suite.honeycombEvent = this.honey.newEvent() + suite.honeycombEvent = honey.newEvent() suite.honeycombEvent.timestamp = Date.now() suite.honeycombEvent.add({ - ...suite.parent.honeycombEvent.data, + ...parent.data, suite: suite.title, specFile: path.basename(suite.file), spanId: uuidv4(), - parentId: suite.parent.honeycombEvent.data.spanId, + parentId: parent.data.spanId, }) this.addAsyncInfo(suite.honeycombEvent) @@ -49,7 +68,7 @@ class HoneycombReporter { // in which case it will be undefined and not passed as a field to honeycomb. const [, testTitle, browser] = path[path.length - 1].match(/(.+?)(?: \[([a-z]+)\])?$/) - test.honeycombEvent = this.honey.newEvent() + test.honeycombEvent = honey.newEvent() test.honeycombEvent.timestamp = Date.now() test.honeycombEvent.add({ ...test.parent.honeycombEvent.data, @@ -90,27 +109,7 @@ class HoneycombReporter { // If there is no done callback, then mocha-multi-reporter will kill the process without waiting for our honeycomb post to complete. done (failures, callback) { - if (this.honey) { - this.honey.flush().then(callback) - } - } - - rootEvent () { - const honeycombEvent = this.honey.newEvent() - - honeycombEvent.timestamp = Date.now() - honeycombEvent.add({ - buildUrl: process.env.CIRCLE_BUILD_URL, - platform: process.platform, - arch: process.arch, - - spanId: uuidv4(), - traceId: process.env.CIRCLE_WORKFLOW_ID || uuidv4(), - }) - - this.addAsyncInfo(honeycombEvent) - - return honeycombEvent + honey.flush().then(callback) } // Because mocha has no way to wait on async functions inside hooks, From b9c0d5e59b8c9c776e0c0c808e84d2d379e35c74 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Tue, 8 Feb 2022 10:37:52 -0800 Subject: [PATCH 07/35] fix indentation --- circle.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index 5aae40de43d0..46b83e793ac5 100644 --- a/circle.yml +++ b/circle.yml @@ -237,8 +237,8 @@ commands: description: 'Send a root event to honeycomb for this build' steps: - run: - name: Send honeycomb event - command: node ./system-tests/lib/performance-reporter.js + name: Send honeycomb event + command: node ./system-tests/lib/performance-reporter.js caching-dependency-installer: description: 'Installs & caches the dependencies based on yarn lock & package json dependencies' From 705262fb764c6abb1b54d636f8a3cefb48fcad8a Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Tue, 8 Feb 2022 10:48:17 -0800 Subject: [PATCH 08/35] Fix --- circle.yml | 11 +++-------- system-tests/lib/performance-reporter.js | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/circle.yml b/circle.yml index 46b83e793ac5..b4cb7c9ceef2 100644 --- a/circle.yml +++ b/circle.yml @@ -221,6 +221,9 @@ commands: - run: name: Update system-tests node_modules cache command: yarn workspace @tooling/system-tests projects:yarn:install + - run: + name: Send root honeycomb event + command: node ./system-tests/lib/performance-reporter.js - save_cache: name: Save system tests node_modules cache key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} @@ -233,13 +236,6 @@ commands: paths: - system_tests_node_modules_installed - send_system_test_honecomb_event: - description: 'Send a root event to honeycomb for this build' - steps: - - run: - name: Send honeycomb event - command: node ./system-tests/lib/performance-reporter.js - caching-dependency-installer: description: 'Installs & caches the dependencies based on yarn lock & package json dependencies' parameters: @@ -1162,7 +1158,6 @@ jobs: steps: - restore_cached_workspace - update_cached_system_tests_deps - - send_system_test_honecomb_event system-tests-chrome: <<: *defaults diff --git a/system-tests/lib/performance-reporter.js b/system-tests/lib/performance-reporter.js index f7af6856cb47..d9f98be6ac45 100644 --- a/system-tests/lib/performance-reporter.js +++ b/system-tests/lib/performance-reporter.js @@ -50,7 +50,7 @@ class HoneycombReporter { suite.honeycombEvent.add({ ...parent.data, suite: suite.title, - specFile: path.basename(suite.file), + specFile: suite.file && path.basename(suite.file), spanId: uuidv4(), parentId: parent.data.spanId, From 9d433c764d2bed33b83a58a208a0d85a8821bed9 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Tue, 8 Feb 2022 12:50:24 -0800 Subject: [PATCH 09/35] Send root honeycomb event even if node_modules cache already exists --- circle.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/circle.yml b/circle.yml index b4cb7c9ceef2..18b4718a6df6 100644 --- a/circle.yml +++ b/circle.yml @@ -206,6 +206,9 @@ commands: name: Restore cache state, to check for known modules cache existence keys: - v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }} + - run: + name: Send root honeycomb event for this CI build + command: node ./system-tests/lib/performance-reporter.js - run: name: Bail if specific cache exists command: | @@ -221,9 +224,6 @@ commands: - run: name: Update system-tests node_modules cache command: yarn workspace @tooling/system-tests projects:yarn:install - - run: - name: Send root honeycomb event - command: node ./system-tests/lib/performance-reporter.js - save_cache: name: Save system tests node_modules cache key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} From 3cf4a2b296cc73dc2c0e05e85c8648023bc39155 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Tue, 8 Feb 2022 12:55:50 -0800 Subject: [PATCH 10/35] Reduce event duplication --- system-tests/lib/performance-reporter.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/system-tests/lib/performance-reporter.js b/system-tests/lib/performance-reporter.js index d9f98be6ac45..448d5f4b1de7 100644 --- a/system-tests/lib/performance-reporter.js +++ b/system-tests/lib/performance-reporter.js @@ -43,7 +43,11 @@ class HoneycombReporter { console.log(chalk.green('Reporting to honeycomb')) runner.on('suite', (suite) => { - const parent = suite.root ? circleCiRootEvent : suite.parent.honeycombEvent + if (!suite.title) { + return + } + + const parent = suite.parent && suite.parent.honeycombEvent ? suite.parent.honeycombEvent : circleCiRootEvent suite.honeycombEvent = honey.newEvent() suite.honeycombEvent.timestamp = Date.now() @@ -99,6 +103,10 @@ class HoneycombReporter { }) runner.on('suite end', (suite) => { + if (!suite.honeycombEvent) { + return + } + suite.honeycombEvent.add({ durationMs: Date.now() - suite.honeycombEvent.timestamp, }) From 57decf45efb2cd434a9d9dfe1114d65245881c2c Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Tue, 8 Feb 2022 13:21:57 -0800 Subject: [PATCH 11/35] Include honeycomb key so we can send root event --- circle.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/circle.yml b/circle.yml index 18b4718a6df6..efc4b97c8589 100644 --- a/circle.yml +++ b/circle.yml @@ -2076,6 +2076,7 @@ linux-workflow: &linux-workflow requires: - build - system-tests-node-modules-install: + context: test-runner:performance-tracking requires: - build - system-tests-chrome: From f7c46fc47246c9861c01d6d7113b0cca9163978d Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Tue, 8 Feb 2022 14:35:00 -0800 Subject: [PATCH 12/35] Refactor async data into more convenient helper --- system-tests/lib/performance-reporter.js | 70 +++++++++++++----------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/system-tests/lib/performance-reporter.js b/system-tests/lib/performance-reporter.js index 448d5f4b1de7..2a453e4b8099 100644 --- a/system-tests/lib/performance-reporter.js +++ b/system-tests/lib/performance-reporter.js @@ -15,6 +15,30 @@ const honey = new Libhoney({ const spanId = process.env.CIRCLE_WORKFLOW_ID || uuidv4() const circleCiRootEvent = honey.newEvent() +// Mocha events ('test', 'test end', etc) have no way to wait +// for async callbacks, so we can't guarantee we have this +// data ready by the time any of the reporter's events are emitted. + +// Therefore, we have each honeycomb event await this promise +// before sending itself. +let asyncInfo = Promise.all([getNextVersionForPath('../../packages'), commitInfo()]) +.then(([nextVersion, commitInformation]) => { + const ciInformation = ciProvider.commitParams() || {} + + return { + nextVersion, + branch: commitInformation.branch || ciInformation.branch, + commitSha: commitInformation.sha || ciInformation.sha, + } +}) + +function addAsyncInfoAndSend (honeycombEvent) { + return asyncInfo.then((info) => { + honeycombEvent.add(info) + honeycombEvent.send() + }) +} + circleCiRootEvent.timestamp = Date.now() circleCiRootEvent.add({ buildUrl: process.env.CIRCLE_BUILD_URL, @@ -29,9 +53,10 @@ circleCiRootEvent.add({ // so that we can send the root event exactly once and associate all the various // system test tasks and build steps into a single span. if (require.main === module) { - console.log(circleCiRootEvent.data) - circleCiRootEvent.send() - honey.flush() + addAsyncInfoAndSend(circleCiRootEvent).then(() => { + console.log(circleCiRootEvent.data) + honey.flush() + }) } class HoneycombReporter { @@ -59,8 +84,6 @@ class HoneycombReporter { spanId: uuidv4(), parentId: parent.data.spanId, }) - - this.addAsyncInfo(suite.honeycombEvent) }) runner.on('test', (test) => { @@ -82,8 +105,6 @@ class HoneycombReporter { spanId: uuidv4(), parentId: test.parent.honeycombEvent.data.spanId, }) - - this.addAsyncInfo(test.honeycombEvent) }) runner.on('test end', (test) => { @@ -99,7 +120,7 @@ class HoneycombReporter { durationMs: Date.now() - test.honeycombEvent.timestamp, }) - test.honeycombEvent.send() + addAsyncInfoAndSend(test.honeycombEvent) }) runner.on('suite end', (suite) => { @@ -111,35 +132,18 @@ class HoneycombReporter { durationMs: Date.now() - suite.honeycombEvent.timestamp, }) - suite.honeycombEvent.send() + addAsyncInfoAndSend(suite.honeycombEvent) }) } - // If there is no done callback, then mocha-multi-reporter will kill the process without waiting for our honeycomb post to complete. + // If there is no done method, then mocha-multi-reporter will kill the process + // without waiting for our honeycomb posts to complete. done (failures, callback) { - honey.flush().then(callback) - } - - // Because mocha has no way to wait on async functions inside hooks, - // and we need to call various async functions to gather data about - // the testing environment, we create a promise that can be used by each - // honeycomb event to add async data that won't be initialized by the - // time mocha starts running tests. - addAsyncInfo (honeycombEvent) { - if (!this.asyncInfo) { - this.asyncInfo = Promise.all([getNextVersionForPath('../../packages'), commitInfo()]) - .then(([nextVersion, commitInformation]) => { - const ciInformation = ciProvider.commitParams() || {} - - return { - nextVersion, - branch: commitInformation.branch || ciInformation.branch, - commitSha: commitInformation.sha || ciInformation.sha, - } - }) - } - - this.asyncInfo.then((info) => honeycombEvent.add(info)) + // Await the asyncInfo promise one last time, to ensure all events have + // added the data and sent themselves before we flush honeycomb's queue and exit. + asyncInfo + .then(() => honey.flush()) + .then(callback) } } From fa0b68af52ce4ce8f9ed102c4ef03ef831ac3d3c Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Tue, 8 Feb 2022 14:50:04 -0800 Subject: [PATCH 13/35] Fix path --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index efc4b97c8589..c6593af628a1 100644 --- a/circle.yml +++ b/circle.yml @@ -208,7 +208,7 @@ commands: - v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }} - run: name: Send root honeycomb event for this CI build - command: node ./system-tests/lib/performance-reporter.js + command: cd system-tests/lib && node ./performance-reporter.js - run: name: Bail if specific cache exists command: | From 97e6c14b91661658b856038da8a0f5fa4319b19b Mon Sep 17 00:00:00 2001 From: ElevateBart Date: Wed, 9 Feb 2022 17:52:38 -0600 Subject: [PATCH 14/35] fix: create a dummy commit to trigger release --- npm/vue/src/shims-vue.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/vue/src/shims-vue.d.ts b/npm/vue/src/shims-vue.d.ts index a1dbcdb9adfe..f43ed923b679 100644 --- a/npm/vue/src/shims-vue.d.ts +++ b/npm/vue/src/shims-vue.d.ts @@ -2,4 +2,4 @@ declare module '*.vue' { import { DefineComponent } from 'vue' const component: DefineComponent<{}, {}, any> export default component - } \ No newline at end of file +} \ No newline at end of file From 9b967e06f5df1e8ae2c5b13d5c7f7170b069f5bc Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Thu, 10 Feb 2022 16:26:20 +1000 Subject: [PATCH 15/35] fix: set correct default when using react-scripts plugin (#20141) --- npm/react/examples/react-scripts/cypress/plugins/index.js | 2 +- .../react-scripts/findReactScriptsWebpackConfig.js | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/npm/react/examples/react-scripts/cypress/plugins/index.js b/npm/react/examples/react-scripts/cypress/plugins/index.js index 33bce3362bea..df575d3a8745 100644 --- a/npm/react/examples/react-scripts/cypress/plugins/index.js +++ b/npm/react/examples/react-scripts/cypress/plugins/index.js @@ -8,7 +8,7 @@ const devServer = require('@cypress/react/plugins/react-scripts') * @type {Cypress.PluginConfig} */ module.exports = (on, config) => { - devServer(on, config) + devServer(on, config, {}) // IMPORTANT to return the config object // with the any changed environment variables diff --git a/npm/react/plugins/react-scripts/findReactScriptsWebpackConfig.js b/npm/react/plugins/react-scripts/findReactScriptsWebpackConfig.js index 48c8402f7051..98d9fc7fb058 100644 --- a/npm/react/plugins/react-scripts/findReactScriptsWebpackConfig.js +++ b/npm/react/plugins/react-scripts/findReactScriptsWebpackConfig.js @@ -7,9 +7,11 @@ const { getTranspileFolders } = require('../utils/get-transpile-folders') const { addFolderToBabelLoaderTranspileInPlace } = require('../utils/babel-helpers') const { reactScriptsFiveModifications, isReactScripts5 } = require('../../dist/react-scripts/reactScriptsFive') -module.exports = function findReactScriptsWebpackConfig (config, { - webpackConfigPath, -} = { webpackConfigPath: 'react-scripts/config/webpack.config' }) { +module.exports = function findReactScriptsWebpackConfig (config, devServerOptions) { + const webpackConfigPath = (devServerOptions && devServerOptions.webpackConfigPath) + ? devServerOptions.webpackConfigPath + : 'react-scripts/config/webpack.config' + // this is required because // 1) we use our own HMR and we don't need react-refresh transpiling overhead // 2) it doesn't work with process.env=test @see https://github.com/cypress-io/cypress-realworld-app/pull/832 From 6a96ca567eae48f721e9f7e2761a8aa3ccef5b6d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 10 Feb 2022 15:16:23 -0500 Subject: [PATCH 16/35] chore: release @cypress/react-v5.12.3 [skip ci] --- npm/react/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/npm/react/CHANGELOG.md b/npm/react/CHANGELOG.md index ed06d61a820f..ef127dafa1fe 100644 --- a/npm/react/CHANGELOG.md +++ b/npm/react/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cypress/react-v5.12.3](https://github.com/cypress-io/cypress/compare/@cypress/react-v5.12.2...@cypress/react-v5.12.3) (2022-02-10) + + +### Bug Fixes + +* set correct default when using react-scripts plugin ([#20141](https://github.com/cypress-io/cypress/issues/20141)) ([9b967e0](https://github.com/cypress-io/cypress/commit/9b967e06f5df1e8ae2c5b13d5c7f7170b069f5bc)) + # [@cypress/react-v5.12.2](https://github.com/cypress-io/cypress/compare/@cypress/react-v5.12.1...@cypress/react-v5.12.2) (2022-02-08) From bb26e9821663ee9ffc5eb40cdd5fac37c6128979 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 10 Feb 2022 15:16:39 -0500 Subject: [PATCH 17/35] chore: release @cypress/vue-v3.1.1 [skip ci] --- npm/vue/CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/npm/vue/CHANGELOG.md b/npm/vue/CHANGELOG.md index 7bf89fc516c0..36a6bc47d375 100644 --- a/npm/vue/CHANGELOG.md +++ b/npm/vue/CHANGELOG.md @@ -1,3 +1,10 @@ +# [@cypress/vue-v3.1.1](https://github.com/cypress-io/cypress/compare/@cypress/vue-v3.1.0...@cypress/vue-v3.1.1) (2022-02-10) + + +### Bug Fixes + +* create a dummy commit to trigger release ([97e6c14](https://github.com/cypress-io/cypress/commit/97e6c14b91661658b856038da8a0f5fa4319b19b)) + # [@cypress/vue-v3.1.0](https://github.com/cypress-io/cypress/compare/@cypress/vue-v3.0.5...@cypress/vue-v3.1.0) (2021-12-16) From 961e764037606d6b80e4872ca35eaacfd12eb9ae Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Thu, 10 Feb 2022 14:21:44 -0800 Subject: [PATCH 18/35] Move sending root event to own script --- circle.yml | 2 +- system-tests/lib/performance-reporter.js | 42 +++++++++---------- .../scripts/send-root-honecomb-event.js | 13 ++++++ 3 files changed, 35 insertions(+), 22 deletions(-) create mode 100644 system-tests/scripts/send-root-honecomb-event.js diff --git a/circle.yml b/circle.yml index c6593af628a1..90f381d5ad91 100644 --- a/circle.yml +++ b/circle.yml @@ -208,7 +208,7 @@ commands: - v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }} - run: name: Send root honeycomb event for this CI build - command: cd system-tests/lib && node ./performance-reporter.js + command: cd system-tests/scripts && node ./send-root-honecomb-event.js - run: name: Bail if specific cache exists command: | diff --git a/system-tests/lib/performance-reporter.js b/system-tests/lib/performance-reporter.js index 2a453e4b8099..22339fdd1cbb 100644 --- a/system-tests/lib/performance-reporter.js +++ b/system-tests/lib/performance-reporter.js @@ -12,16 +12,32 @@ const honey = new Libhoney({ writeKey: process.env.HONEYCOMB_API_KEY, }) +// This event is created here independently every time the reporter +// is imported (in each parallel instance of the system-tests +// in circleci) so that we can use it as the parent, +// but ../scripts/send-root-honeycomb-event.js +// is only invoked once at the start of the build, +// and is responsible for sending it to honeycomb. const spanId = process.env.CIRCLE_WORKFLOW_ID || uuidv4() const circleCiRootEvent = honey.newEvent() +circleCiRootEvent.timestamp = Date.now() +circleCiRootEvent.add({ + buildUrl: process.env.CIRCLE_BUILD_URL, + platform: process.platform, + arch: process.arch, + + spanId, + traceId: spanId, +}) + // Mocha events ('test', 'test end', etc) have no way to wait // for async callbacks, so we can't guarantee we have this // data ready by the time any of the reporter's events are emitted. // Therefore, we have each honeycomb event await this promise // before sending itself. -let asyncInfo = Promise.all([getNextVersionForPath('../../packages'), commitInfo()]) +let asyncInfo = Promise.all([getNextVersionForPath(path.resolve(__dirname, '../../packages')), commitInfo()]) .then(([nextVersion, commitInformation]) => { const ciInformation = ciProvider.commitParams() || {} @@ -39,26 +55,6 @@ function addAsyncInfoAndSend (honeycombEvent) { }) } -circleCiRootEvent.timestamp = Date.now() -circleCiRootEvent.add({ - buildUrl: process.env.CIRCLE_BUILD_URL, - platform: process.platform, - arch: process.arch, - - spanId, - traceId: spanId, -}) - -// This file is executed once as a script at the beginning of the circleci build, -// so that we can send the root event exactly once and associate all the various -// system test tasks and build steps into a single span. -if (require.main === module) { - addAsyncInfoAndSend(circleCiRootEvent).then(() => { - console.log(circleCiRootEvent.data) - honey.flush() - }) -} - class HoneycombReporter { constructor (runner) { if (!process.env.HONEYCOMB_API_KEY) { @@ -148,3 +144,7 @@ class HoneycombReporter { } module.exports = HoneycombReporter + +HoneycombReporter.honey = honey +HoneycombReporter.circleCiRootEvent = circleCiRootEvent +HoneycombReporter.addAsyncInfoAndSend = addAsyncInfoAndSend diff --git a/system-tests/scripts/send-root-honecomb-event.js b/system-tests/scripts/send-root-honecomb-event.js new file mode 100644 index 000000000000..e3dc7bcdc67f --- /dev/null +++ b/system-tests/scripts/send-root-honecomb-event.js @@ -0,0 +1,13 @@ +const { addAsyncInfoAndSend, circleCiRootEvent, honey } = require('../lib/performance-reporter') + +// This file is executed once during the circleci build, +// so that we can send the root event honeycomb event for this +// run of the system tests exactly once. +// All the system test build hosts reference this root event, +// joining them into a single trace. +if (require.main === module) { + addAsyncInfoAndSend(circleCiRootEvent).then(() => { + console.log(circleCiRootEvent.data) + honey.flush() + }) +} From 02cc29af9eb40aaf050f3facf0083210f3cca068 Mon Sep 17 00:00:00 2001 From: Emily Rohrbough Date: Fri, 11 Feb 2022 11:56:38 -0600 Subject: [PATCH 19/35] chore(driver): move cy.focused and cy.root into their own files (#20054) --- .../commands/querying/focused_spec.js | 227 ++++++++++++ .../commands/querying/querying_spec.js | 325 ------------------ .../commands/querying/root_spec.js | 114 ++++++ .../src/cy/commands/querying/focused.ts | 70 ++++ .../driver/src/cy/commands/querying/index.ts | 4 + .../src/cy/commands/querying/querying.ts | 92 ----- .../driver/src/cy/commands/querying/root.ts | 35 ++ 7 files changed, 450 insertions(+), 417 deletions(-) create mode 100644 packages/driver/cypress/integration/commands/querying/focused_spec.js create mode 100644 packages/driver/cypress/integration/commands/querying/root_spec.js create mode 100644 packages/driver/src/cy/commands/querying/focused.ts create mode 100644 packages/driver/src/cy/commands/querying/root.ts diff --git a/packages/driver/cypress/integration/commands/querying/focused_spec.js b/packages/driver/cypress/integration/commands/querying/focused_spec.js new file mode 100644 index 000000000000..ff7873099e39 --- /dev/null +++ b/packages/driver/cypress/integration/commands/querying/focused_spec.js @@ -0,0 +1,227 @@ +const { assertLogLength } = require('../../../support/utils') + +const { _ } = Cypress + +describe('src/cy/commands/querying', () => { + beforeEach(() => { + cy.visit('/fixtures/dom.html') + }) + + context('#focused', () => { + it('returns the activeElement', () => { + const $button = cy.$$('#button') + + $button.get(0).focus() + + expect(cy.state('document').activeElement).to.eq($button.get(0)) + + cy.focused().then(($focused) => { + expect($focused.get(0)).to.eq($button.get(0)) + }) + }) + + it('returns null if no activeElement', () => { + const $button = cy.$$('#button') + + $button.get(0).focus() + $button.get(0).blur() + + cy.focused().should('not.exist').then(($focused) => { + expect($focused).to.be.null + }) + }) + + describe('assertion verification', () => { + beforeEach(function () { + cy.on('log:added', (attrs, log) => { + if (log.get('name') === 'assert') { + this.lastLog = log + } + }) + + return null + }) + + it('eventually passes the assertion', () => { + cy.on('command:retry', _.after(2, () => { + cy.$$(':text:first').addClass('focused').focus() + })) + + cy.focused().should('have.class', 'focused').then(function () { + const { lastLog } = this + + expect(lastLog.get('name')).to.eq('assert') + expect(lastLog.get('state')).to.eq('passed') + + expect(lastLog.get('ended')).to.be.true + }) + }) + + // https://github.com/cypress-io/cypress/issues/409 + it('retries on an elements value', () => { + const $input = cy.$$('input:first') + + cy.on('command:retry', _.after(2, () => { + $input.val('1234') + + $input.get(0).focus() + })) + + cy.focused().should('have.value', '1234').then(function () { + const { lastLog } = this + + expect(lastLog.get('name')).to.eq('assert') + expect(lastLog.get('state')).to.eq('passed') + + expect(lastLog.get('ended')).to.be.true + }) + }) + }) + + describe('.log', () => { + beforeEach(function () { + cy.$$('input:first').get(0).focus() + + cy.on('log:added', (attrs, log) => { + if (log.get('name') === 'focused') { + this.lastLog = log + } + }) + + return null + }) + + it('is a parent command', () => { + cy.get('body').focused().then(function () { + const { lastLog } = this + + expect(lastLog.get('type')).to.eq('parent') + }) + }) + + it('ends immediately', () => { + cy.focused().then(function () { + const { lastLog } = this + + expect(lastLog.get('ended')).to.be.true + + expect(lastLog.get('state')).to.eq('passed') + }) + }) + + it('snapshots immediately', () => { + cy.focused().then(function () { + const { lastLog } = this + + expect(lastLog.get('snapshots').length).to.eq(1) + + expect(lastLog.get('snapshots')[0]).to.be.an('object') + }) + }) + + it('passes in $el', () => { + cy.get('input:first').focused().then(function ($input) { + const { lastLog } = this + + expect(lastLog.get('$el')).to.eq($input) + }) + }) + + it('#consoleProps', () => { + cy.get('input:first').focused().then(function ($input) { + expect(this.lastLog.invoke('consoleProps')).to.deep.eq({ + Command: 'focused', + Yielded: $input.get(0), + Elements: 1, + }) + }) + }) + + it('#consoleProps with null element', () => { + const button = cy.$$('#button') + + button.get(0).focus() + button.get(0).blur() + + cy.focused().should('not.exist').then(function () { + expect(this.lastLog.invoke('consoleProps')).to.deep.eq({ + Command: 'focused', + Yielded: '--nothing--', + Elements: 0, + }) + }) + }) + }) + + describe('errors', { + defaultCommandTimeout: 100, + }, () => { + beforeEach(function () { + this.logs = [] + + cy.on('log:added', (attrs, log) => { + this.lastLog = log + + this.logs.push(log) + }) + + return null + }) + + it('fails waiting for the element to exist', (done) => { + const button = cy.$$('#button') + + button.get(0).focus() + button.get(0).blur() + + cy.on('fail', (err) => { + expect(err.message).to.include('Expected to find element: `focused`, but never found it.') + + done() + }) + + cy.focused() + }) + + it('fails waiting for the focused element not to exist', (done) => { + cy.$$('input:first').focus() + + cy.on('fail', (err) => { + expect(err.message).to.include('Expected not to exist in the DOM, but it was continuously found.') + + done() + }) + + cy.focused().should('not.exist') + }) + + it('eventually fails the assertion', function (done) { + cy.$$('input:first').focus() + + cy.on('fail', (err) => { + const { lastLog } = this + + expect(err.message).to.include(lastLog.get('error').message) + expect(err.message).not.to.include('undefined') + expect(lastLog.get('name')).to.eq('assert') + expect(lastLog.get('state')).to.eq('failed') + expect(lastLog.get('error')).to.be.an.instanceof(chai.AssertionError) + + done() + }) + + cy.focused().should('have.class', 'focused') + }) + + it('does not log an additional log on failure', function (done) { + cy.on('fail', () => { + assertLogLength(this.logs, 2) + + done() + }) + + cy.focused().should('have.class', 'focused') + }) + }) + }) +}) diff --git a/packages/driver/cypress/integration/commands/querying/querying_spec.js b/packages/driver/cypress/integration/commands/querying/querying_spec.js index 6882f42c8be4..151198bccd5e 100644 --- a/packages/driver/cypress/integration/commands/querying/querying_spec.js +++ b/packages/driver/cypress/integration/commands/querying/querying_spec.js @@ -7,331 +7,6 @@ describe('src/cy/commands/querying', () => { cy.visit('/fixtures/dom.html') }) - context('#focused', () => { - it('returns the activeElement', () => { - const $button = cy.$$('#button') - - $button.get(0).focus() - - expect(cy.state('document').activeElement).to.eq($button.get(0)) - - cy.focused().then(($focused) => { - expect($focused.get(0)).to.eq($button.get(0)) - }) - }) - - it('returns null if no activeElement', () => { - const $button = cy.$$('#button') - - $button.get(0).focus() - $button.get(0).blur() - - cy.focused().should('not.exist').then(($focused) => { - expect($focused).to.be.null - }) - }) - - describe('assertion verification', () => { - beforeEach(function () { - cy.on('log:added', (attrs, log) => { - if (log.get('name') === 'assert') { - this.lastLog = log - } - }) - - return null - }) - - it('eventually passes the assertion', () => { - cy.on('command:retry', _.after(2, () => { - cy.$$(':text:first').addClass('focused').focus() - })) - - cy.focused().should('have.class', 'focused').then(function () { - const { lastLog } = this - - expect(lastLog.get('name')).to.eq('assert') - expect(lastLog.get('state')).to.eq('passed') - - expect(lastLog.get('ended')).to.be.true - }) - }) - - // https://github.com/cypress-io/cypress/issues/409 - it('retries on an elements value', () => { - const $input = cy.$$('input:first') - - cy.on('command:retry', _.after(2, () => { - $input.val('1234') - - $input.get(0).focus() - })) - - cy.focused().should('have.value', '1234').then(function () { - const { lastLog } = this - - expect(lastLog.get('name')).to.eq('assert') - expect(lastLog.get('state')).to.eq('passed') - - expect(lastLog.get('ended')).to.be.true - }) - }) - }) - - describe('.log', () => { - beforeEach(function () { - cy.$$('input:first').get(0).focus() - - cy.on('log:added', (attrs, log) => { - if (log.get('name') === 'focused') { - this.lastLog = log - } - }) - - return null - }) - - it('is a parent command', () => { - cy.get('body').focused().then(function () { - const { lastLog } = this - - expect(lastLog.get('type')).to.eq('parent') - }) - }) - - it('ends immediately', () => { - cy.focused().then(function () { - const { lastLog } = this - - expect(lastLog.get('ended')).to.be.true - - expect(lastLog.get('state')).to.eq('passed') - }) - }) - - it('snapshots immediately', () => { - cy.focused().then(function () { - const { lastLog } = this - - expect(lastLog.get('snapshots').length).to.eq(1) - - expect(lastLog.get('snapshots')[0]).to.be.an('object') - }) - }) - - it('passes in $el', () => { - cy.get('input:first').focused().then(function ($input) { - const { lastLog } = this - - expect(lastLog.get('$el')).to.eq($input) - }) - }) - - it('#consoleProps', () => { - cy.get('input:first').focused().then(function ($input) { - expect(this.lastLog.invoke('consoleProps')).to.deep.eq({ - Command: 'focused', - Yielded: $input.get(0), - Elements: 1, - }) - }) - }) - - it('#consoleProps with null element', () => { - const button = cy.$$('#button') - - button.get(0).focus() - button.get(0).blur() - - cy.focused().should('not.exist').then(function () { - expect(this.lastLog.invoke('consoleProps')).to.deep.eq({ - Command: 'focused', - Yielded: '--nothing--', - Elements: 0, - }) - }) - }) - }) - - describe('errors', { - defaultCommandTimeout: 100, - }, () => { - beforeEach(function () { - this.logs = [] - - cy.on('log:added', (attrs, log) => { - this.lastLog = log - - this.logs.push(log) - }) - - return null - }) - - it('fails waiting for the element to exist', (done) => { - const button = cy.$$('#button') - - button.get(0).focus() - button.get(0).blur() - - cy.on('fail', (err) => { - expect(err.message).to.include('Expected to find element: `focused`, but never found it.') - - done() - }) - - cy.focused() - }) - - it('fails waiting for the focused element not to exist', (done) => { - cy.$$('input:first').focus() - - cy.on('fail', (err) => { - expect(err.message).to.include('Expected not to exist in the DOM, but it was continuously found.') - - done() - }) - - cy.focused().should('not.exist') - }) - - it('eventually fails the assertion', function (done) { - cy.$$('input:first').focus() - - cy.on('fail', (err) => { - const { lastLog } = this - - expect(err.message).to.include(lastLog.get('error').message) - expect(err.message).not.to.include('undefined') - expect(lastLog.get('name')).to.eq('assert') - expect(lastLog.get('state')).to.eq('failed') - expect(lastLog.get('error')).to.be.an.instanceof(chai.AssertionError) - - done() - }) - - cy.focused().should('have.class', 'focused') - }) - - it('does not log an additional log on failure', function (done) { - cy.on('fail', () => { - assertLogLength(this.logs, 2) - - done() - }) - - cy.focused().should('have.class', 'focused') - }) - }) - }) - - context('#root', () => { - it('returns html', () => { - const html = cy.$$('html') - - cy.root().then(($html) => { - expect($html.get(0)).to.eq(html.get(0)) - }) - }) - - it('returns withinSubject if exists', () => { - const form = cy.$$('form') - - cy.get('form').within(() => { - cy - .get('input') - .root().then(($root) => { - expect($root.get(0)).to.eq(form.get(0)) - }) - }) - }) - - it('eventually resolves', () => { - _.delay(() => { - cy.$$('html').addClass('foo').addClass('bar') - } - , 100) - - cy.root().should('have.class', 'foo').and('have.class', 'bar') - }) - - describe('.log', () => { - beforeEach(function () { - this.logs = [] - - cy.on('log:added', (attrs, log) => { - if (attrs.name === 'root') { - this.lastLog = log - - this.logs.push(log) - } - }) - - return null - }) - - it('can turn off logging', () => { - cy.root({ log: false }).then(function () { - expect(this.log).to.be.undefined - }) - }) - - it('logs immediately before resolving', (done) => { - cy.on('log:added', (attrs, log) => { - if (log.get('name') === 'root') { - expect(log.get('state')).to.eq('pending') - expect(log.get('message')).to.eq('') - - done() - } - }) - - cy.root() - }) - - it('snapshots after clicking', () => { - cy.root().then(function () { - const { lastLog } = this - - expect(lastLog.get('snapshots').length).to.eq(1) - - expect(lastLog.get('snapshots')[0]).to.be.an('object') - }) - }) - - it('sets $el to document', () => { - const html = cy.$$('html') - - cy.root().then(function () { - expect(this.lastLog.get('$el').get(0)).to.eq(html.get(0)) - }) - }) - - it('sets $el to withinSubject', () => { - const form = cy.$$('form') - - cy.get('form').within(() => { - cy - .get('input') - .root().then(function ($root) { - expect(this.lastLog.get('$el').get(0)).to.eq(form.get(0)) - }) - }) - }) - - it('consoleProps', () => { - cy.root().then(function ($root) { - const consoleProps = this.lastLog.invoke('consoleProps') - - expect(consoleProps).to.deep.eq({ - Command: 'root', - Yielded: $root.get(0), - }) - }) - }) - }) - }) - context('#get', { defaultCommandTimeout: 200, }, () => { diff --git a/packages/driver/cypress/integration/commands/querying/root_spec.js b/packages/driver/cypress/integration/commands/querying/root_spec.js new file mode 100644 index 000000000000..e01b4ea30f59 --- /dev/null +++ b/packages/driver/cypress/integration/commands/querying/root_spec.js @@ -0,0 +1,114 @@ +const { _ } = Cypress + +describe('src/cy/commands/querying', () => { + beforeEach(() => { + cy.visit('/fixtures/dom.html') + }) + + context('#root', () => { + it('returns html', () => { + const html = cy.$$('html') + + cy.root().then(($html) => { + expect($html.get(0)).to.eq(html.get(0)) + }) + }) + + it('returns withinSubject if exists', () => { + const form = cy.$$('form') + + cy.get('form').within(() => { + cy + .get('input') + .root().then(($root) => { + expect($root.get(0)).to.eq(form.get(0)) + }) + }) + }) + + it('eventually resolves', () => { + _.delay(() => { + cy.$$('html').addClass('foo').addClass('bar') + } + , 100) + + cy.root().should('have.class', 'foo').and('have.class', 'bar') + }) + + describe('.log', () => { + beforeEach(function () { + this.logs = [] + + cy.on('log:added', (attrs, log) => { + if (attrs.name === 'root') { + this.lastLog = log + + this.logs.push(log) + } + }) + + return null + }) + + it('can turn off logging', () => { + cy.root({ log: false }).then(function () { + expect(this.log).to.be.undefined + }) + }) + + it('logs immediately before resolving', (done) => { + cy.on('log:added', (attrs, log) => { + if (log.get('name') === 'root') { + expect(log.get('state')).to.eq('pending') + expect(log.get('message')).to.eq('') + + done() + } + }) + + cy.root() + }) + + it('snapshots after clicking', () => { + cy.root().then(function () { + const { lastLog } = this + + expect(lastLog.get('snapshots').length).to.eq(1) + + expect(lastLog.get('snapshots')[0]).to.be.an('object') + }) + }) + + it('sets $el to document', () => { + const html = cy.$$('html') + + cy.root().then(function () { + expect(this.lastLog.get('$el').get(0)).to.eq(html.get(0)) + }) + }) + + it('sets $el to withinSubject', () => { + const form = cy.$$('form') + + cy.get('form').within(() => { + cy + .get('input') + .root().then(function ($root) { + expect(this.lastLog.get('$el').get(0)).to.eq(form.get(0)) + }) + }) + }) + + it('consoleProps', () => { + cy.root().then(function ($root) { + const consoleProps = this.lastLog.invoke('consoleProps') + + expect(consoleProps).to.deep.eq({ + Command: 'root', + Yielded: $root.get(0), + }) + }) + }) + }) + }) +}) diff --git a/packages/driver/src/cy/commands/querying/focused.ts b/packages/driver/src/cy/commands/querying/focused.ts new file mode 100644 index 000000000000..45f67366ae20 --- /dev/null +++ b/packages/driver/src/cy/commands/querying/focused.ts @@ -0,0 +1,70 @@ +import _ from 'lodash' +import Promise from 'bluebird' + +import $dom from '../../../dom' + +export default (Commands, Cypress, cy, state) => { + Commands.addAll({ + // TODO: any -> Partial + focused (options: any = {}) { + const userOptions = options + + options = _.defaults({}, userOptions, { + verify: true, + log: true, + }) + + if (options.log) { + options._log = Cypress.log({ timeout: options.timeout }) + } + + const log = ($el) => { + if (options.log === false) { + return + } + + options._log.set({ + $el, + consoleProps () { + const ret = $el ? $dom.getElements($el) : '--nothing--' + + return { + Yielded: ret, + Elements: $el != null ? $el.length : 0, + } + }, + }) + } + + const getFocused = () => { + const focused = cy.getFocused() + + log(focused) + + return focused + } + + const resolveFocused = () => { + return Promise + .try(getFocused) + .then(($el) => { + if (options.verify === false) { + return $el + } + + if (!$el) { + $el = $dom.wrap(null) + $el.selector = 'focused' + } + + // pass in a null jquery object for assertions + return cy.verifyUpcomingAssertions($el, options, { + onRetry: resolveFocused, + }) + }) + } + + return resolveFocused() + }, + }) +} diff --git a/packages/driver/src/cy/commands/querying/index.ts b/packages/driver/src/cy/commands/querying/index.ts index 2574bc7fb66d..9985cbae492b 100644 --- a/packages/driver/src/cy/commands/querying/index.ts +++ b/packages/driver/src/cy/commands/querying/index.ts @@ -1,7 +1,11 @@ +import * as Focused from './focused' import * as Querying from './querying' +import * as Root from './root' import * as Within from './within' export { + Focused, Querying, + Root, Within, } diff --git a/packages/driver/src/cy/commands/querying/querying.ts b/packages/driver/src/cy/commands/querying/querying.ts index e372a9605b72..aa80eeb3c268 100644 --- a/packages/driver/src/cy/commands/querying/querying.ts +++ b/packages/driver/src/cy/commands/querying/querying.ts @@ -9,68 +9,6 @@ import { getAliasedRequests, isDynamicAliasingPossible } from '../../net-stubbin export default (Commands, Cypress, cy, state) => { Commands.addAll({ - // TODO: any -> Partial - focused (options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { - verify: true, - log: true, - }) - - if (options.log) { - options._log = Cypress.log({ timeout: options.timeout }) - } - - const log = ($el) => { - if (options.log === false) { - return - } - - options._log.set({ - $el, - consoleProps () { - const ret = $el ? $dom.getElements($el) : '--nothing--' - - return { - Yielded: ret, - Elements: $el != null ? $el.length : 0, - } - }, - }) - } - - const getFocused = () => { - const focused = cy.getFocused() - - log(focused) - - return focused - } - - const resolveFocused = () => { - return Promise - .try(getFocused) - .then(($el) => { - if (options.verify === false) { - return $el - } - - if (!$el) { - $el = $dom.wrap(null) - $el.selector = 'focused' - } - - // pass in a null jquery object for assertions - return cy.verifyUpcomingAssertions($el, options, { - onRetry: resolveFocused, - }) - }) - } - - return resolveFocused() - }, - // TODO: any -> Partial get (selector, options: any = {}) { const userOptions = options @@ -409,36 +347,6 @@ export default (Commands, Cypress, cy, state) => { return resolveElements() }, - - // TODO: any -> Partial - root (options: any = {}) { - const userOptions = options - - options = _.defaults({}, userOptions, { log: true }) - - if (options.log !== false) { - options._log = Cypress.log({ - message: '', - timeout: options.timeout, - }) - } - - const log = ($el) => { - if (options.log) { - options._log.set({ $el }) - } - - return $el - } - - const withinSubject = state('withinSubject') - - if (withinSubject) { - return log(withinSubject) - } - - return cy.now('get', 'html', { log: false }).then(log) - }, }) Commands.addAll({ prevSubject: ['optional', 'window', 'document', 'element'] }, { diff --git a/packages/driver/src/cy/commands/querying/root.ts b/packages/driver/src/cy/commands/querying/root.ts new file mode 100644 index 000000000000..a9e12fd16d66 --- /dev/null +++ b/packages/driver/src/cy/commands/querying/root.ts @@ -0,0 +1,35 @@ +import _ from 'lodash' + +export default (Commands, Cypress, cy, state) => { + Commands.addAll({ + // TODO: any -> Partial + root (options: any = {}) { + const userOptions = options + + options = _.defaults({}, userOptions, { log: true }) + + if (options.log !== false) { + options._log = Cypress.log({ + message: '', + timeout: options.timeout, + }) + } + + const log = ($el) => { + if (options.log) { + options._log.set({ $el }) + } + + return $el + } + + const withinSubject = state('withinSubject') + + if (withinSubject) { + return log(withinSubject) + } + + return cy.now('get', 'html', { log: false }).then(log) + }, + }) +} From a1e6d5cad1444e27791b344b2b311196620c1c73 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Fri, 11 Feb 2022 13:18:53 -0500 Subject: [PATCH 20/35] test: remove redundant "other projects" CI jobs (#20133) Co-authored-by: Emily Rohrbough --- __snapshots__/bump-spec.js | 25 ----------------- circle.yml | 55 +------------------------------------- scripts/binary/bump.js | 4 --- 3 files changed, 1 insertion(+), 83 deletions(-) diff --git a/__snapshots__/bump-spec.js b/__snapshots__/bump-spec.js index f004f1bfddfc..f9bd3d1682ce 100644 --- a/__snapshots__/bump-spec.js +++ b/__snapshots__/bump-spec.js @@ -1,19 +1,9 @@ exports['list of all projects'] = [ - { - "repo": "cypress-io/cypress-test-tiny", - "provider": "circle", - "platform": "win32" - }, { "repo": "cypress-io/cypress-test-example-repos", "provider": "circle", "platform": "win32" }, - { - "repo": "cypress-io/cypress-test-tiny", - "provider": "circle", - "platform": "linux" - }, { "repo": "cypress-io/cypress-test-module-api", "provider": "circle", @@ -24,11 +14,6 @@ exports['list of all projects'] = [ "provider": "circle", "platform": "linux" }, - { - "repo": "cypress-io/cypress-test-nested-projects", - "provider": "circle", - "platform": "linux" - }, { "repo": "cypress-io/cypress-test-ci-environments", "provider": "circle", @@ -39,11 +24,6 @@ exports['list of all projects'] = [ "provider": "circle", "platform": "linux" }, - { - "repo": "cypress-io/cypress-test-tiny", - "provider": "circle", - "platform": "darwin" - }, { "repo": "cypress-io/cypress-test-example-repos", "provider": "circle", @@ -52,11 +32,6 @@ exports['list of all projects'] = [ ] exports['should have just circle and darwin projects'] = [ - { - "repo": "cypress-io/cypress-test-tiny", - "provider": "circle", - "platform": "darwin" - }, { "repo": "cypress-io/cypress-test-example-repos", "provider": "circle", diff --git a/circle.yml b/circle.yml index ae81e412da23..c292c4913797 100644 --- a/circle.yml +++ b/circle.yml @@ -1940,33 +1940,6 @@ jobs: repo: cypress-example-todomvc browser: firefox - test-binary-against-conduit-chrome: - <<: *defaults - resource_class: medium - steps: - - test-binary-against-repo: - repo: cypress-example-conduit-app - browser: chrome - command: "npm run cypress:run" - wait-on: http://localhost:3000 - - test-binary-against-api-testing-firefox: - <<: *defaults - steps: - - test-binary-against-repo: - repo: cypress-example-api-testing - browser: firefox - command: "npm run cy:run" - - test-binary-against-piechopper-firefox: - <<: *defaults - resource_class: medium - steps: - - test-binary-against-repo: - repo: cypress-example-piechopper - browser: firefox - command: "npm run cypress:run" - test-binary-against-cypress-realworld-app: <<: *defaults resource_class: medium+ @@ -2254,12 +2227,7 @@ linux-workflow: &linux-workflow <<: *mainBuildFilters requires: - create-build-artifacts - # Re-enable when the cypress-example-conduit-app project is fixed. - # https://github.com/cypress-io/cypress-example-conduit-app/issues/346 - # - test-binary-against-conduit-chrome: - # <<: *mainBuildFilters - # requires: - # - create-build-artifacts + - test-binary-against-recipes-firefox: <<: *mainBuildFilters requires: @@ -2272,14 +2240,6 @@ linux-workflow: &linux-workflow <<: *mainBuildFilters requires: - create-build-artifacts - - test-binary-against-api-testing-firefox: - <<: *mainBuildFilters - requires: - - create-build-artifacts - - test-binary-against-piechopper-firefox: - <<: *mainBuildFilters - requires: - - create-build-artifacts - test-binary-against-cypress-realworld-app: <<: *mainBuildFilters requires: @@ -2335,19 +2295,6 @@ mac-workflow: &mac-workflow requires: - darwin-build - - test-binary-against-kitchensink: - name: darwin-test-binary-against-kitchensink - executor: mac - requires: - - darwin-create-build-artifacts - - - test-binary-against-staging: - context: test-runner:record-tests - name: darwin-test-binary-against-staging - executor: mac - requires: - - darwin-create-build-artifacts - - test-binary-and-npm-against-other-projects: context: test-runner:trigger-test-jobs name: darwin-test-binary-and-npm-against-other-projects diff --git a/scripts/binary/bump.js b/scripts/binary/bump.js index b7cc4dd8dd40..8a3cfa0befbc 100644 --- a/scripts/binary/bump.js +++ b/scripts/binary/bump.js @@ -16,19 +16,15 @@ const _PROVIDERS = { circle: { main: 'cypress-io/cypress', linux: [ - 'cypress-io/cypress-test-tiny', 'cypress-io/cypress-test-module-api', 'cypress-io/cypress-test-node-versions', - 'cypress-io/cypress-test-nested-projects', 'cypress-io/cypress-test-ci-environments', 'cypress-io/cypress-test-example-repos', ], darwin: [ - 'cypress-io/cypress-test-tiny', 'cypress-io/cypress-test-example-repos', ], win32: [ - 'cypress-io/cypress-test-tiny', 'cypress-io/cypress-test-example-repos', ], }, From 2c88f0c58ec3c1bd8421a05259fc2ab893191f99 Mon Sep 17 00:00:00 2001 From: Tyler Biethman Date: Sat, 12 Feb 2022 16:57:07 -0600 Subject: [PATCH 21/35] fix: Update `.type(' ')` to not emit clicks when the keyup event has been prevented (#20156) * fix: Update `.type(' ')` to not emit clicks when the keyup event has been prevented * cleanup test for click event not firing while preventing default Co-authored-by: Brian Mann --- .../cypress/fixtures/click-event-by-type.html | 4 +- .../integration/commands/actions/type_spec.js | 92 ++++++++++++++++--- .../driver/src/cy/commands/actions/type.ts | 4 +- 3 files changed, 82 insertions(+), 18 deletions(-) diff --git a/packages/driver/cypress/fixtures/click-event-by-type.html b/packages/driver/cypress/fixtures/click-event-by-type.html index 5999d152f00a..69a53b00c86a 100644 --- a/packages/driver/cypress/fixtures/click-event-by-type.html +++ b/packages/driver/cypress/fixtures/click-event-by-type.html @@ -66,10 +66,10 @@ target.addEventListener("click", () => { updateLog("click"); }); - target.addEventListener("keyup", () => { + target.addEventListener("keyup", (event) => { updateLog("keyup"); }); }); - \ No newline at end of file + diff --git a/packages/driver/cypress/integration/commands/actions/type_spec.js b/packages/driver/cypress/integration/commands/actions/type_spec.js index c63a0e954bb7..90e10798bb7a 100644 --- a/packages/driver/cypress/integration/commands/actions/type_spec.js +++ b/packages/driver/cypress/integration/commands/actions/type_spec.js @@ -574,8 +574,7 @@ describe('src/cy/commands/actions/type - #type', () => { targets.forEach((targetId) => { it(`${targetId}`, () => { - cy.get(`#target-${targetId}`).focus() - cy.get(`#target-${targetId}`).type('{enter}') + cy.get(`#target-${targetId}`).focus().type('{enter}') cy.get('li').eq(0).should('have.text', 'keydown') cy.get('li').eq(1).should('have.text', 'keypress') @@ -593,8 +592,7 @@ describe('src/cy/commands/actions/type - #type', () => { targets.forEach((targetId) => { it(`${targetId}`, () => { - cy.get(`#target-${targetId}`).focus() - cy.get(`#target-${targetId}`).type('{enter}') + cy.get(`#target-${targetId}`).focus().type('{enter}') cy.get('li').eq(0).should('have.text', 'keydown') cy.get('li').eq(1).should('have.text', 'keypress') @@ -610,17 +608,30 @@ describe('src/cy/commands/actions/type - #type', () => { }) const targets = [ - 'button-tag', - 'input-button', - 'input-image', - 'input-reset', - 'input-submit', + '#target-button-tag', + '#target-input-button', + '#target-input-image', + '#target-input-reset', + '#target-input-submit', ] describe(`triggers with single space`, () => { - targets.forEach((targetId) => { - it(targetId, () => { - cy.get(`#target-${targetId}`).focus().type(' ') + targets.forEach((target) => { + it(target, () => { + const events = [] + + $(target).on('keydown keypress keyup click', (evt) => { + events.push(evt.type) + }) + + cy.get(target).focus().type(' ').then(() => { + expect(events).to.deep.eq([ + 'keydown', + 'keypress', + 'keyup', + 'click', + ]) + }) cy.get('li').eq(0).should('have.text', 'keydown') cy.get('li').eq(1).should('have.text', 'keypress') @@ -630,10 +641,61 @@ describe('src/cy/commands/actions/type - #type', () => { }) }) + describe(`does not trigger if keyup prevented`, () => { + targets.forEach((target) => { + it(`${target} does not fire click event`, () => { + const events = [] + + $(target) + .on('keydown keypress keyup click', (evt) => { + events.push(evt.type) + }) + .on('keyup', (evt) => { + evt.preventDefault() + }) + + cy.get(target).focus().type(' ').then(() => { + expect(events).to.deep.eq([ + 'keydown', + 'keypress', + 'keyup', + ]) + }) + + cy.get('li').should('have.length', 3) + cy.get('li').eq(0).should('have.text', 'keydown') + cy.get('li').eq(1).should('have.text', 'keypress') + cy.get('li').eq(2).should('have.text', 'keyup') + }) + }) + }) + describe('triggers after other characters', () => { - targets.forEach((targetId) => { - it(targetId, () => { - cy.get(`#target-${targetId}`).focus().type('asd ') + targets.forEach((target) => { + it(target, () => { + const events = [] + + $(target).on('keydown keypress keyup click', (evt) => { + events.push(evt.type) + }) + + cy.get(target).focus().type('asd ').then(() => { + expect(events).to.deep.eq([ + 'keydown', + 'keypress', + 'keyup', + 'keydown', + 'keypress', + 'keyup', + 'keydown', + 'keypress', + 'keyup', + 'keydown', + 'keypress', + 'keyup', + 'click', + ]) + }) cy.get('li').eq(12).should('have.text', 'click') }) diff --git a/packages/driver/src/cy/commands/actions/type.ts b/packages/driver/src/cy/commands/actions/type.ts index 7d255a65d668..edeebb49186f 100644 --- a/packages/driver/src/cy/commands/actions/type.ts +++ b/packages/driver/src/cy/commands/actions/type.ts @@ -342,7 +342,9 @@ export default function (Commands, Cypress, cy, state, config) { // event.target is null when used with shadow DOM. (event.target && $elements.isButtonLike(event.target)) && // When a space key is pressed for input radio elements, the click event is only fired when it's not checked. - !(event.target.tagName === 'INPUT' && event.target.type === 'radio' && event.target.checked === true) + !(event.target.tagName === 'INPUT' && event.target.type === 'radio' && event.target.checked === true) && + // When event is prevented, the click event should not be emitted + !event.defaultPrevented ) { fireClickEvent(event.target) } From ce956dedb30c4c59134bc5a9077707c79c287967 Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Mon, 14 Feb 2022 08:21:15 -0800 Subject: [PATCH 22/35] Add span names, merge develop --- system-tests/lib/performance-reporter.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/system-tests/lib/performance-reporter.js b/system-tests/lib/performance-reporter.js index 22339fdd1cbb..234b1a2858e8 100644 --- a/system-tests/lib/performance-reporter.js +++ b/system-tests/lib/performance-reporter.js @@ -26,6 +26,7 @@ circleCiRootEvent.add({ buildUrl: process.env.CIRCLE_BUILD_URL, platform: process.platform, arch: process.arch, + name: 'ci_run', spanId, traceId: spanId, @@ -76,6 +77,7 @@ class HoneycombReporter { ...parent.data, suite: suite.title, specFile: suite.file && path.basename(suite.file), + name: 'spec_execution', spanId: uuidv4(), parentId: parent.data.spanId, @@ -97,6 +99,7 @@ class HoneycombReporter { ...test.parent.honeycombEvent.data, test: testTitle, browser, + name: 'test_execution', spanId: uuidv4(), parentId: test.parent.honeycombEvent.data.spanId, From a3f0d63387afbe5395b569ec03e8e3f5f2915918 Mon Sep 17 00:00:00 2001 From: Brian Mann Date: Mon, 14 Feb 2022 14:40:56 -0500 Subject: [PATCH 23/35] chore: enable volar.takeOverMode --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 934ee91ed0ce..4e770066c5e7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -37,5 +37,5 @@ // Volar is the main extension that powers Vue's language features. // "volar.autoCompleteRefs": false, - // "volar.takeOverMode.enabled": true + "volar.takeOverMode.enabled": true, } From 507b96f83445441a33f89b4c8143cb231d234fbe Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 15 Feb 2022 06:35:08 -0600 Subject: [PATCH 24/35] chore: Update Chrome (stable) to 98.0.4758.102 (#20192) 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 beec05263965..b2731c658fbd 100644 --- a/browser-versions.json +++ b/browser-versions.json @@ -1,4 +1,4 @@ { "chrome:beta": "99.0.4844.27", - "chrome:stable": "98.0.4758.80" + "chrome:stable": "98.0.4758.102" } From 1e6f51a3d1cf2a8ddc4855fbb903f7a84b49d24a Mon Sep 17 00:00:00 2001 From: BlueWinds Date: Tue, 15 Feb 2022 10:18:49 -0800 Subject: [PATCH 25/35] release 9.5.0 [skip ci] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3aba6632ac4d..48412f91ad3d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cypress", - "version": "9.4.1", + "version": "9.5.0", "description": "Cypress.io end to end testing tool", "private": true, "scripts": { From f84bac51d06b9bc0182974fca18dfef48dbe0f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=20Kire=C3=A7lig=C3=B6l?= Date: Wed, 16 Feb 2022 20:22:57 +0300 Subject: [PATCH 26/35] fix(driver): update wrapErr to ignore number and boolean values (#20172) Co-authored-by: Emily Rohrbough --- .../integration/cypress/error_utils_spec.ts | 14 ++++++++++++++ packages/driver/src/cypress/error_utils.ts | 8 +++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/driver/cypress/integration/cypress/error_utils_spec.ts b/packages/driver/cypress/integration/cypress/error_utils_spec.ts index 7a5078b5c50d..fcd5a0b81db5 100644 --- a/packages/driver/cypress/integration/cypress/error_utils_spec.ts +++ b/packages/driver/cypress/integration/cypress/error_utils_spec.ts @@ -622,4 +622,18 @@ describe('driver/src/cypress/error_utils', () => { expect(stack).not.to.include('removeMeAndAbove') }) }) + + context('.wrapErr', () => { + [ + { value: undefined, label: 'undefined' }, + { value: null, label: 'null' }, + { value: '', label: 'empty string' }, + { value: true, label: 'boolean' }, + { value: 1, label: 'number' }, + ].forEach((err) => { + it(`returns undefined if err is ${err.label}`, () => { + expect($errUtils.wrapErr(err.value)).to.be.undefined + }) + }) + }) }) diff --git a/packages/driver/src/cypress/error_utils.ts b/packages/driver/src/cypress/error_utils.ts index 9c58d6950aa8..3d001726ecff 100644 --- a/packages/driver/src/cypress/error_utils.ts +++ b/packages/driver/src/cypress/error_utils.ts @@ -52,8 +52,14 @@ const prepareErrorForSerialization = (err) => { return err } +// some errors, probably from user callbacks, might be boolean, number or falsy values +// which means serializing will not provide any useful context +const isSerializableError = (err) => { + return !!err && (typeof err === 'object' || typeof err === 'string') +} + const wrapErr = (err) => { - if (!err) return + if (!isSerializableError(err)) return prepareErrorForSerialization(err) From 42b0fce6dc4f4de5c8269f7abcea2822544401a5 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Wed, 16 Feb 2022 13:53:04 -0500 Subject: [PATCH 27/35] test: replace cypress-test-example-repos coverage + remove bump (#20186) --- CONTRIBUTING.md | 15 --------------- __snapshots__/bump-spec.js | 25 ++++++++++--------------- circle.yml | 32 ++++++++++++++++++++++++++------ scripts/binary/bump.js | 7 ------- scripts/unit/binary/bump-spec.js | 6 +++--- 5 files changed, 39 insertions(+), 46 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8de45c9f3d4d..5c122f5ef1e0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,7 +18,6 @@ Thanks for taking the time to contribute! :smile: ## Table of Contents -- [CI Status](#ci-status) - [Code of Conduct](#code-of-conduct) - [Opening Issues](#opening-issues) - [Triaging Issues](#triaging-issues) @@ -42,20 +41,6 @@ Thanks for taking the time to contribute! :smile: - [Code Review of Dependency Updates](#Code-Review-of-Dependency-Updates) - [Deployment](#deployment) -## CI status - -| Build status | Description | -| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------------------------- | -| [![CircleCI](https://circleci.com/gh/cypress-io/cypress-test-node-versions.svg?style=svg&circle-token=6a7c4e7e7ab427e11bea6c2af3df29c4491d2376)](https://circleci.com/gh/cypress-io/cypress-test-node-versions) | [cypress-test-node-versions](https://github.com/cypress-io/cypress-test-node-versions) | -| [![CircleCI](https://circleci.com/gh/cypress-io/cypress-test-ci-environments.svg?style=svg&circle-token=66a4d36c3966cbe476f13e7dfbe3af0693db3fb9)](https://circleci.com/gh/cypress-io/cypress-test-ci-environments) | [cypress-test-ci-environments](https://github.com/cypress-io/cypress-test-ci-environments) | -| [![CircleCI](https://circleci.com/gh/cypress-io/cypress-test-module-api.svg?style=svg&circle-token=317f79ae796e0ffd6cc7dd90859c0f67e5a306e7)](https://circleci.com/gh/cypress-io/cypress-test-module-api) | [cypress-test-module-api](https://github.com/cypress-io/cypress-test-module-api) | -| [![CircleCI](https://circleci.com/gh/cypress-io/cypress-test-nested-projects.svg?style=svg)](https://circleci.com/gh/cypress-io/cypress-test-nested-projects) | [cypress-test-nested-projects](https://github.com/cypress-io/cypress-test-nested-projects) | -| [![CircleCI](https://circleci.com/gh/cypress-io/cypress-on.svg?style=svg&circle-token=51ba85f5720654ee58212f45f6b9afc56d55d52a)](https://circleci.com/gh/cypress-io/cypress-on) | [cypress-on](https://github.com/cypress-io/cypress-on) | -| [![CircleCI](https://circleci.com/gh/cypress-io/cypress-test-node-versions.svg?style=svg&circle-token=6a7c4e7e7ab427e11bea6c2af3df29c4491d2376)](https://circleci.com/gh/cypress-io/cypress-test-node-versions) | [cypress-test-example-repos](https://github.com/cypress-io/cypress-test-example-repos) | -| [![CircleCI](https://circleci.com/gh/cypress-io/docsearch-scraper.svg?style=svg&circle-token=8087137233788ec1eab4f79d4451392ca53183b2)](https://circleci.com/gh/cypress-io/docsearch-scraper) | [docsearch-scraper](https://github.com/cypress-io/docsearch-scraper) | -| [![Docker Build Status](https://img.shields.io/docker/build/cypress/base.svg)](https://hub.docker.com/r/cypress/base/) | [cypress-docker-images](https://github.com/cypress-io/cypress-docker-images) | -| [![Build status](https://ci.appveyor.com/api/projects/status/ln8tg3dv42nk916c?svg=true)](https://ci.appveyor.com/project/cypress-io/cypress) | Windows CI | - ## Code of Conduct All contributors are expecting to abide by our [Code of Conduct](./CODE_OF_CONDUCT.md). diff --git a/__snapshots__/bump-spec.js b/__snapshots__/bump-spec.js index f9bd3d1682ce..2f4ab529a2f5 100644 --- a/__snapshots__/bump-spec.js +++ b/__snapshots__/bump-spec.js @@ -1,9 +1,4 @@ exports['list of all projects'] = [ - { - "repo": "cypress-io/cypress-test-example-repos", - "provider": "circle", - "platform": "win32" - }, { "repo": "cypress-io/cypress-test-module-api", "provider": "circle", @@ -18,23 +13,23 @@ exports['list of all projects'] = [ "repo": "cypress-io/cypress-test-ci-environments", "provider": "circle", "platform": "linux" - }, + } +] + +exports['should have just circle and linux projects'] = [ { - "repo": "cypress-io/cypress-test-example-repos", + "repo": "cypress-io/cypress-test-module-api", "provider": "circle", "platform": "linux" }, { - "repo": "cypress-io/cypress-test-example-repos", + "repo": "cypress-io/cypress-test-node-versions", "provider": "circle", - "platform": "darwin" - } -] - -exports['should have just circle and darwin projects'] = [ + "platform": "linux" + }, { - "repo": "cypress-io/cypress-test-example-repos", + "repo": "cypress-io/cypress-test-ci-environments", "provider": "circle", - "platform": "darwin" + "platform": "linux" } ] diff --git a/circle.yml b/circle.yml index 2796094e6765..5af9a4022b56 100644 --- a/circle.yml +++ b/circle.yml @@ -29,7 +29,7 @@ mainBuildFilters: &mainBuildFilters only: - develop - 10.0-release - - fix-ci-artifact-uploads + - other-projects-cleanup # usually we don't build Mac app - it takes a long time # but sometimes we want to really confirm we are doing the right thing @@ -1582,7 +1582,7 @@ jobs: - run: name: Check current branch to persist artifacts command: | - if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "fix-ci-artifact-uploads" ]]; then + if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "other-projects-cleanup" ]]; then echo "Not uploading artifacts or posting install comment for this branch." circleci-agent step halt fi @@ -1890,6 +1890,22 @@ jobs: repo: cypress-example-recipes command: npm run test:ci:firefox + test-binary-against-recipes-chrome: + <<: *defaults + parallelism: 3 + steps: + - test-binary-against-repo: + repo: cypress-example-recipes + command: npm run test:ci:chrome + + test-binary-against-recipes: + <<: *defaults + parallelism: 3 + steps: + - test-binary-against-repo: + repo: cypress-example-recipes + command: npm run test:ci + # This is a special job. It allows you to test the current # built test runner against a pull request in the repo # cypress-example-recipes. @@ -2226,16 +2242,22 @@ linux-workflow: &linux-workflow <<: *mainBuildFilters requires: - create-build-artifacts - - test-binary-against-kitchensink-chrome: <<: *mainBuildFilters requires: - create-build-artifacts - - test-binary-against-recipes-firefox: <<: *mainBuildFilters requires: - create-build-artifacts + - test-binary-against-recipes-chrome: + <<: *mainBuildFilters + requires: + - create-build-artifacts + - test-binary-against-recipes: + <<: *mainBuildFilters + requires: + - create-build-artifacts - test-binary-against-kitchensink-firefox: <<: *mainBuildFilters requires: @@ -2248,13 +2270,11 @@ linux-workflow: &linux-workflow <<: *mainBuildFilters requires: - create-build-artifacts - - test-binary-as-specific-user: name: "test binary as a non-root user" executor: non-root-docker-user requires: - create-build-artifacts - - test-binary-as-specific-user: name: "test binary as a root user" requires: diff --git a/scripts/binary/bump.js b/scripts/binary/bump.js index 8a3cfa0befbc..f9932db0ff34 100644 --- a/scripts/binary/bump.js +++ b/scripts/binary/bump.js @@ -19,13 +19,6 @@ const _PROVIDERS = { 'cypress-io/cypress-test-module-api', 'cypress-io/cypress-test-node-versions', 'cypress-io/cypress-test-ci-environments', - 'cypress-io/cypress-test-example-repos', - ], - darwin: [ - 'cypress-io/cypress-test-example-repos', - ], - win32: [ - 'cypress-io/cypress-test-example-repos', ], }, } diff --git a/scripts/unit/binary/bump-spec.js b/scripts/unit/binary/bump-spec.js index 4ebc06e0bf89..e5c6acb6dbc7 100644 --- a/scripts/unit/binary/bump-spec.js +++ b/scripts/unit/binary/bump-spec.js @@ -29,7 +29,7 @@ describe('bump', () => { ) }) - it('returns a filter function for circle and darwin', () => { + it('returns a filter function for circle and linux', () => { const projects = bump.remapProjects(bump._PROVIDERS) la( @@ -38,11 +38,11 @@ describe('bump', () => { projects, ) - const filter = bump.getFilterByProvider('circle', 'darwin') + const filter = bump.getFilterByProvider('circle', 'linux') const filtered = projects.filter(filter) la(filtered.length, 'there should be at least a few projects', filtered) - snapshot('should have just circle and darwin projects', filtered) + snapshot('should have just circle and linux projects', filtered) }) }) }) From 0d3e645359b19a7e6399666c4465324d20b94112 Mon Sep 17 00:00:00 2001 From: Marco Lauinger Date: Thu, 17 Feb 2022 19:20:33 +0100 Subject: [PATCH 28/35] fix: treat form-data bodies as binary (#20144) --- packages/net-stubbing/lib/server/util.ts | 4 ++++ packages/net-stubbing/test/unit/util-spec.ts | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/net-stubbing/lib/server/util.ts b/packages/net-stubbing/lib/server/util.ts index c33d4be1464f..68d31bc26f9d 100644 --- a/packages/net-stubbing/lib/server/util.ts +++ b/packages/net-stubbing/lib/server/util.ts @@ -251,6 +251,10 @@ export function getBodyEncoding (req: CyHttpMessages.IncomingRequest): BodyEncod if (contentType.includes('charset=utf-8') || contentType.includes('charset="utf-8"')) { return 'utf8' } + + if (contentType.includes('multipart/form-data')) { + return 'binary' + } } // with fallback to inspecting the buffer using diff --git a/packages/net-stubbing/test/unit/util-spec.ts b/packages/net-stubbing/test/unit/util-spec.ts index 3775f48ffa8d..f2e1db390975 100644 --- a/packages/net-stubbing/test/unit/util-spec.ts +++ b/packages/net-stubbing/test/unit/util-spec.ts @@ -69,5 +69,19 @@ describe('net-stubbing util', () => { expect(getBodyEncoding(req), 'image').to.equal('binary') }) + + it('returns binary for form-data bodies', () => { + const formDataRequest = { + body: Buffer.from('hello world'), + headers: { + 'content-type': 'multipart/form-data', + }, + method: 'POST', + url: 'somewhere', + httpVersion: '1.1', + } + + expect(getBodyEncoding(formDataRequest)).to.equal('binary') + }) }) }) From ad50062ca21aefbfe54142d4b76eec25c579b6de Mon Sep 17 00:00:00 2001 From: Johannes Ewald Date: Thu, 17 Feb 2022 19:21:08 +0100 Subject: [PATCH 29/35] fix: Wait for child process to be ready (#19792) Co-authored-by: Zach Bloomquist Co-authored-by: Zach Bloomquist --- .../server/lib/plugins/child/run_plugins.js | 2 ++ packages/server/lib/plugins/index.js | 4 +++- .../server/test/unit/plugins/index_spec.js | 18 +++++++++++------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/server/lib/plugins/child/run_plugins.js b/packages/server/lib/plugins/child/run_plugins.js index 63ba4fd62562..90672a20e6b5 100644 --- a/packages/server/lib/plugins/child/run_plugins.js +++ b/packages/server/lib/plugins/child/run_plugins.js @@ -212,6 +212,8 @@ const runPlugins = (ipc, pluginsFile, projectRoot) => { ipc.on('execute', (event, ids, args) => { execute(ipc, event, ids, args) }) + + ipc.send('ready') } // for testing purposes diff --git a/packages/server/lib/plugins/index.js b/packages/server/lib/plugins/index.js index e356a684763e..635f94487414 100644 --- a/packages/server/lib/plugins/index.js +++ b/packages/server/lib/plugins/index.js @@ -139,7 +139,9 @@ const init = (config, options) => { Object.keys(config).sort().forEach((key) => orderedConfig[key] = config[key]) config = orderedConfig - ipc.send('load', config) + ipc.on('ready', () => { + ipc.send('load', config) + }) ipc.on('loaded', (newCfg, registrations) => { _.omit(config, 'projectRoot', 'configFile') diff --git a/packages/server/test/unit/plugins/index_spec.js b/packages/server/test/unit/plugins/index_spec.js index 46469f4c2432..c5898c8e92c0 100644 --- a/packages/server/test/unit/plugins/index_spec.js +++ b/packages/server/test/unit/plugins/index_spec.js @@ -115,15 +115,19 @@ describe('lib/plugins/index', () => { }) }) - it('sends \'load\' event with config via ipc', () => { - ipc.on.withArgs('loaded').yields([]) + it('sends \'load\' event with config via ipc once it receives \'ready\'', () => { const config = { pluginsFile: 'cypress-plugin', testingType: 'e2e' } - return plugins.init(config, getOptions({ testingType: 'e2e' })).then(() => { - expect(ipc.send).to.be.calledWith('load', { - ...config, - ...configExtras, - }) + plugins.init(config, getOptions({ testingType: 'e2e' })) + + expect(ipc.send).to.not.be.called + + // simulate async ready event + ipc.on.withArgs('ready').firstCall.callback() + + expect(ipc.send).to.be.calledWith('load', { + ...config, + ...configExtras, }) }) From 8d282614990e35c024d935859a8e0bac8cb30069 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 18 Feb 2022 10:33:27 -0600 Subject: [PATCH 30/35] =?UTF-8?q?chore(deps):=20update=20dependency=20fs-e?= =?UTF-8?q?xtra=20to=20v9=20=F0=9F=8C=9F=20(#19939)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Renovate Bot Co-authored-by: Emily Rohrbough Co-authored-by: David Munechika --- npm/create-cypress-tests/package.json | 2 +- .../package.json | 2 +- npm/webpack-preprocessor/package.json | 2 +- package.json | 4 ++-- packages/electron/package.json | 2 +- packages/extension/package.json | 2 +- packages/https-proxy/package.json | 2 +- packages/launcher/package.json | 2 +- packages/network/package.json | 2 +- packages/resolve-dist/package.json | 2 +- packages/rewriter/package.json | 2 +- packages/runner/package.json | 2 +- packages/server/package.json | 2 +- system-tests/package.json | 2 +- yarn.lock | 22 +++++++++---------- 15 files changed, 26 insertions(+), 26 deletions(-) diff --git a/npm/create-cypress-tests/package.json b/npm/create-cypress-tests/package.json index 09f48045c209..dda6627a31f3 100644 --- a/npm/create-cypress-tests/package.json +++ b/npm/create-cypress-tests/package.json @@ -23,7 +23,7 @@ "commander": "6.1.0", "fast-glob": "3.2.7", "find-up": "5.0.0", - "fs-extra": "^9.0.1", + "fs-extra": "^9.1.0", "glob": "^7.1.6", "inquirer": "7.3.3", "ora": "^5.1.0" diff --git a/npm/webpack-batteries-included-preprocessor/package.json b/npm/webpack-batteries-included-preprocessor/package.json index 11b198f730b7..0d7f17f02c64 100644 --- a/npm/webpack-batteries-included-preprocessor/package.json +++ b/npm/webpack-batteries-included-preprocessor/package.json @@ -37,7 +37,7 @@ "eslint-plugin-json-format": "^2.0.1", "eslint-plugin-mocha": "^8.1.0", "eslint-plugin-react": "^7.22.0", - "fs-extra": "^9.0.1", + "fs-extra": "^9.1.0", "graphql": "14.0.0", "mocha": "^8.1.1", "react": "^16.13.1", diff --git a/npm/webpack-preprocessor/package.json b/npm/webpack-preprocessor/package.json index 125cb37601e3..81d9b558daac 100644 --- a/npm/webpack-preprocessor/package.json +++ b/npm/webpack-preprocessor/package.json @@ -46,7 +46,7 @@ "eslint-plugin-mocha": "8.1.0", "fast-glob": "3.1.1", "find-webpack": "1.5.0", - "fs-extra": "8.1.0", + "fs-extra": "9.1.0", "mocha": "^7.1.0", "mockery": "2.1.0", "proxyquire": "2.1.3", diff --git a/package.json b/package.json index 48412f91ad3d..f6dcda649938 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "@types/debug": "4.1.5", "@types/enzyme-adapter-react-16": "1.0.5", "@types/execa": "0.9.0", - "@types/fs-extra": "^8.0.1", + "@types/fs-extra": "^9.0.13", "@types/glob": "7.1.1", "@types/lodash": "^4.14.168", "@types/markdown-it": "0.0.9", @@ -134,7 +134,7 @@ "execa-wrap": "1.4.0", "filesize": "4.1.2", "find-package-json": "1.2.0", - "fs-extra": "8.1.0", + "fs-extra": "9.1.0", "gift": "0.10.2", "glob": "7.1.6", "gulp": "4.0.2", diff --git a/packages/electron/package.json b/packages/electron/package.json index bf431cfa6dbd..8e507ddc14ff 100644 --- a/packages/electron/package.json +++ b/packages/electron/package.json @@ -18,7 +18,7 @@ "@cypress/icons": "0.7.0", "bluebird": "3.5.3", "debug": "^4.3.2", - "fs-extra": "8.1.0", + "fs-extra": "9.1.0", "lodash": "^4.17.21", "minimist": "1.2.5" }, diff --git a/packages/extension/package.json b/packages/extension/package.json index 61038a021614..8dc10fc6256f 100644 --- a/packages/extension/package.json +++ b/packages/extension/package.json @@ -26,7 +26,7 @@ "coffeescript": "1.12.7", "cross-env": "6.0.3", "eol": "0.9.1", - "fs-extra": "8.1.0", + "fs-extra": "9.1.0", "gulp": "4.0.2", "gulp-clean": "0.4.0", "gulp-rename": "1.4.0", diff --git a/packages/https-proxy/package.json b/packages/https-proxy/package.json index 4a898947e106..2ac7d4767c20 100644 --- a/packages/https-proxy/package.json +++ b/packages/https-proxy/package.json @@ -16,7 +16,7 @@ "dependencies": { "bluebird": "3.5.3", "debug": "^4.3.2", - "fs-extra": "8.1.0", + "fs-extra": "9.1.0", "lodash": "^4.17.21", "node-forge": "1.0.0", "semaphore": "1.1.0" diff --git a/packages/launcher/package.json b/packages/launcher/package.json index 4686478286fb..313daf60aa3a 100644 --- a/packages/launcher/package.json +++ b/packages/launcher/package.json @@ -15,7 +15,7 @@ "bluebird": "3.5.3", "debug": "^4.3.2", "execa": "4.0.0", - "fs-extra": "8.1.0", + "fs-extra": "9.1.0", "lodash": "^4.17.21", "plist": "3.0.1", "semver": "7.3.5" diff --git a/packages/network/package.json b/packages/network/package.json index 96fde1583b3b..e2fa897ab9b8 100644 --- a/packages/network/package.json +++ b/packages/network/package.json @@ -17,7 +17,7 @@ "bluebird": "3.5.3", "concat-stream": "1.6.2", "debug": "^4.3.2", - "fs-extra": "8.1.0", + "fs-extra": "9.1.0", "lodash": "^4.17.21", "node-forge": "1.0.0", "proxy-from-env": "1.0.0" diff --git a/packages/resolve-dist/package.json b/packages/resolve-dist/package.json index 01347e9d6539..ee0f5b15ac42 100644 --- a/packages/resolve-dist/package.json +++ b/packages/resolve-dist/package.json @@ -13,7 +13,7 @@ "test-watch": "yarn test-unit --watch" }, "dependencies": { - "fs-extra": "8.1.0" + "fs-extra": "9.1.0" }, "devDependencies": { "@packages/ts": "0.0.0-development" diff --git a/packages/rewriter/package.json b/packages/rewriter/package.json index b130d523e49c..0c0a5a7a2655 100644 --- a/packages/rewriter/package.json +++ b/packages/rewriter/package.json @@ -22,7 +22,7 @@ "devDependencies": { "@cypress/request-promise": "4.2.6", "@types/parse5-html-rewriting-stream": "5.1.1", - "fs-extra": "9.0.0", + "fs-extra": "9.1.0", "nock": "12.0.3", "sinon": "9.0.2", "sinon-chai": "3.5.0", diff --git a/packages/runner/package.json b/packages/runner/package.json index a1d7e4ca429c..f94cd80cd246 100644 --- a/packages/runner/package.json +++ b/packages/runner/package.json @@ -17,7 +17,7 @@ "watch": "webpack --watch --progress" }, "dependencies": { - "fs-extra": "8.1.0" + "fs-extra": "9.1.0" }, "devDependencies": { "@cypress/design-system": "0.0.0-development", diff --git a/packages/server/package.json b/packages/server/package.json index d7c95a7e2759..06bda7b2e370 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -61,7 +61,7 @@ "firefox-profile": "4.0.0", "fix-path": "3.0.0", "fluent-ffmpeg": "2.1.2", - "fs-extra": "8.1.0", + "fs-extra": "9.1.0", "get-port": "5.1.1", "getos": "3.2.1", "glob": "7.1.3", diff --git a/system-tests/package.json b/system-tests/package.json index 08a7e4b0ae25..5c99c7d9ff23 100644 --- a/system-tests/package.json +++ b/system-tests/package.json @@ -48,7 +48,7 @@ "express-session": "1.16.1", "express-useragent": "1.0.15", "fluent-ffmpeg": "2.1.2", - "fs-extra": "8.1.0", + "fs-extra": "9.1.0", "glob": "7.2.0", "https-proxy-agent": "3.0.1", "human-interval": "1.0.0", diff --git a/yarn.lock b/yarn.lock index 3ee0c7ff014a..f10fbad4601d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7938,7 +7938,7 @@ dependencies: "@types/node" "*" -"@types/fs-extra@^9.0.11": +"@types/fs-extra@^9.0.11", "@types/fs-extra@^9.0.13": version "9.0.13" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.13.tgz#7594fbae04fe7f1918ce8b3d213f74ff44ac1f45" integrity sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA== @@ -20104,6 +20104,16 @@ fs-extra@9.0.0: jsonfile "^6.0.1" universalify "^1.0.0" +fs-extra@9.1.0, fs-extra@^9.0.0, fs-extra@^9.0.1, fs-extra@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs-extra@^0.30.0: version "0.30.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" @@ -20151,16 +20161,6 @@ fs-extra@^6.0.1: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.0.0, fs-extra@^9.0.1, fs-extra@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - fs-minipass@^1.2.5: version "1.2.7" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" From 75c87502a2ca88fa76c8c5bb5f52626e0f70b08f Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Fri, 18 Feb 2022 12:54:26 -0600 Subject: [PATCH 31/35] chore: fix system-test-firefox screenshots_spec flake (#20268) --- .../projects/e2e/cypress/integration/screenshots_spec.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system-tests/projects/e2e/cypress/integration/screenshots_spec.js b/system-tests/projects/e2e/cypress/integration/screenshots_spec.js index 2858c235882e..4f622da0919f 100644 --- a/system-tests/projects/e2e/cypress/integration/screenshots_spec.js +++ b/system-tests/projects/e2e/cypress/integration/screenshots_spec.js @@ -308,6 +308,7 @@ describe('taking screenshots', () => { cy.visit('http://localhost:3322/color/yellow') cy.screenshot('overwrite-test', { overwrite: false, + capture: 'viewport', clip: { x: 10, y: 10, width: 160, height: 80 }, }) @@ -320,6 +321,7 @@ describe('taking screenshots', () => { cy.screenshot('overwrite-test', { overwrite: true, + capture: 'viewport', clip: { x: 10, y: 10, width: 100, height: 50 }, }) @@ -342,6 +344,7 @@ describe('taking screenshots', () => { cy.viewport(600, 200) cy.visit('http://localhost:3322/color/yellow') cy.screenshot('overwrite-test', { + capture: 'viewport', clip: { x: 10, y: 10, width: 160, height: 80 }, }) @@ -353,6 +356,7 @@ describe('taking screenshots', () => { }) cy.screenshot('overwrite-test', { + capture: 'viewport', clip: { x: 10, y: 10, width: 100, height: 50 }, }) From ad2f4de84412f675021d02409d30e1c5722a988d Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Fri, 18 Feb 2022 18:37:22 -0500 Subject: [PATCH 32/35] test(system-tests): support docker-based tests against built binary (#20250) Co-authored-by: Ryan Manuel --- __snapshots__/bump-spec.js | 20 --- circle.yml | 77 ++++++--- guides/release-process.md | 9 -- scripts/binary/bump.js | 2 - system-tests/README.md | 32 +++- system-tests/lib/docker.ts | 151 ++++++++++++++++++ system-tests/lib/fixtures.ts | 3 +- system-tests/lib/system-tests.ts | 149 +++++++++-------- system-tests/package.json | 3 +- .../scripts/bootstrap-docker-container.sh | 53 ++++++ .../test-binary/ci_environments_spec.ts | 41 +++++ .../test-binary/node_versions_spec.ts | 21 +++ yarn.lock | 71 ++++++-- 13 files changed, 504 insertions(+), 128 deletions(-) create mode 100644 system-tests/lib/docker.ts create mode 100755 system-tests/scripts/bootstrap-docker-container.sh create mode 100644 system-tests/test-binary/ci_environments_spec.ts create mode 100644 system-tests/test-binary/node_versions_spec.ts diff --git a/__snapshots__/bump-spec.js b/__snapshots__/bump-spec.js index 2f4ab529a2f5..73a99a47b3bd 100644 --- a/__snapshots__/bump-spec.js +++ b/__snapshots__/bump-spec.js @@ -3,16 +3,6 @@ exports['list of all projects'] = [ "repo": "cypress-io/cypress-test-module-api", "provider": "circle", "platform": "linux" - }, - { - "repo": "cypress-io/cypress-test-node-versions", - "provider": "circle", - "platform": "linux" - }, - { - "repo": "cypress-io/cypress-test-ci-environments", - "provider": "circle", - "platform": "linux" } ] @@ -21,15 +11,5 @@ exports['should have just circle and linux projects'] = [ "repo": "cypress-io/cypress-test-module-api", "provider": "circle", "platform": "linux" - }, - { - "repo": "cypress-io/cypress-test-node-versions", - "provider": "circle", - "platform": "linux" - }, - { - "repo": "cypress-io/cypress-test-ci-environments", - "provider": "circle", - "platform": "linux" } ] diff --git a/circle.yml b/circle.yml index 5af9a4022b56..3287cfc3a775 100644 --- a/circle.yml +++ b/circle.yml @@ -11,7 +11,7 @@ defaults: &defaults type: boolean default: false executor: <> - environment: + environment: &defaultsEnvironment ## set specific timezone TZ: "/usr/share/zoneinfo/America/New_York" @@ -169,7 +169,7 @@ commands: command: node scripts/circle-cache.js --action cacheKey > circle_cache_key - restore_cache: name: Restore cache state, to check for known modules cache existence - key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-test2-node-modules-cache-{{ checksum "circle_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-node-modules-cache-{{ checksum "circle_cache_key" }} - run: name: Move node_modules back from /tmp command: | @@ -193,8 +193,8 @@ commands: - restore_cache: name: Restore system tests node_modules cache keys: - - v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} - - v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache- + - v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} + - v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache- update_cached_system_tests_deps: description: 'Update the cached node_modules for projects in "system-tests/projects/**"' @@ -205,36 +205,36 @@ commands: - restore_cache: name: Restore cache state, to check for known modules cache existence keys: - - v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }} + - v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }} - run: name: Send root honeycomb event for this CI build command: cd system-tests/scripts && node ./send-root-honecomb-event.js - run: name: Bail if specific cache exists command: | - if [[ -f "system_tests_node_modules_installed" ]]; then + if [[ -f "/tmp/system_tests_node_modules_installed" ]]; then echo "No updates to system tests node modules, exiting" circleci-agent step halt fi - restore_cache: name: Restore system tests node_modules cache keys: - - v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} - - v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache- + - v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} + - v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache- - run: name: Update system-tests node_modules cache command: yarn workspace @tooling/system-tests projects:yarn:install - save_cache: name: Save system tests node_modules cache - key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} paths: - ~/.cache/cy-system-tests-node-modules - - run: touch system_tests_node_modules_installed + - run: touch /tmp/system_tests_node_modules_installed - save_cache: name: Save system tests node_modules cache state key - key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }} paths: - - system_tests_node_modules_installed + - /tmp/system_tests_node_modules_installed caching-dependency-installer: description: 'Installs & caches the dependencies based on yarn lock & package json dependencies' @@ -249,11 +249,11 @@ commands: command: node scripts/circle-cache.js --action cacheKey > circle_cache_key - restore_cache: name: Restore cache state, to check for known modules cache existence - key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-test2-node-modules-cache-state-{{ checksum "circle_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-node-modules-cache-state-{{ checksum "circle_cache_key" }} - run: name: Bail if cache exists command: | - if [[ -f "node_modules_installed" ]]; then + if [[ -f "/tmp/node_modules_installed" ]]; then echo "Node modules already cached for dependencies, exiting" circleci-agent step halt fi @@ -261,7 +261,7 @@ commands: - restore_cache: name: Restore weekly yarn cache keys: - - v{{ .Environment.CACHE_VERSION }}-{{ arch }}-test2-deps-root-weekly-{{ checksum "cache_date" }} + - v{{ .Environment.CACHE_VERSION }}-deps-root-weekly-{{ checksum "cache_date" }} - run: name: Install Node Modules command: | @@ -274,7 +274,7 @@ commands: steps: - save_cache: name: Saving node modules for root, cli, and all globbed workspace packages - key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-test2-node-modules-cache-{{ checksum "circle_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-node-modules-cache-{{ checksum "circle_cache_key" }} paths: - node_modules - cli/node_modules @@ -285,18 +285,18 @@ commands: steps: - save_cache: name: Saving node modules for root, cli, and all globbed workspace packages - key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-test2-node-modules-cache-{{ checksum "circle_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-node-modules-cache-{{ checksum "circle_cache_key" }} paths: - /tmp/node_modules_cache - - run: touch node_modules_installed + - run: touch /tmp/node_modules_installed - save_cache: name: Saving node-modules cache state key - key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-test2-node-modules-cache-state-{{ checksum "circle_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-node-modules-cache-state-{{ checksum "circle_cache_key" }} paths: - - node_modules_installed + - /tmp/node_modules_installed - save_cache: name: Save weekly yarn cache - key: v{{ .Environment.CACHE_VERSION }}-{{ arch }}-test2-deps-root-weekly-{{ checksum "cache_date" }} + key: v{{ .Environment.CACHE_VERSION }}-deps-root-weekly-{{ checksum "cache_date" }} paths: - ~/.yarn @@ -519,6 +519,24 @@ commands: path: /tmp/artifacts - store-npm-logs + run-binary-system-tests: + steps: + - restore_cached_workspace + - restore_cached_system_tests_deps + - run: + name: Run system tests + command: | + ALL_SPECS=`circleci tests glob "$HOME/cypress/system-tests/test-binary/*spec*"` + SPECS=`echo $ALL_SPECS | xargs -n 1 | circleci tests split --split-by=timings` + echo SPECS=$SPECS + yarn workspace @tooling/system-tests test:ci $SPECS + - verify-mocha-results + - store_test_results: + path: /tmp/cypress + - store_artifacts: + path: /tmp/artifacts + - store-npm-logs + store-npm-logs: description: Saves any NPM debug logs as artifacts in case there is a problem steps: @@ -1162,6 +1180,19 @@ jobs: - restore_cached_workspace - update_cached_system_tests_deps + binary-system-tests: + parallelism: 2 + working_directory: ~/cypress + environment: + <<: *defaultsEnvironment + machine: + # using `machine` gives us a Linux VM that can run Docker + image: ubuntu-2004:202111-02 + docker_layer_caching: true + resource_class: medium + steps: + - run-binary-system-tests + system-tests-chrome: <<: *defaults resource_class: medium @@ -2279,6 +2310,10 @@ linux-workflow: &linux-workflow name: "test binary as a root user" requires: - create-build-artifacts + - binary-system-tests: + requires: + - create-build-artifacts + - system-tests-node-modules-install mac-workflow: &mac-workflow jobs: diff --git a/guides/release-process.md b/guides/release-process.md index ce2c0e8e5392..44a8b0c1b678 100644 --- a/guides/release-process.md +++ b/guides/release-process.md @@ -197,10 +197,8 @@ In the following instructions, "X.Y.Z" is used to denote the [next version of Cy - [cypress-example-todomvc-redux](https://github.com/cypress-io/cypress-example-todomvc-redux/issues/1) - [cypress-example-realworld](https://github.com/cypress-io/cypress-example-realworld/issues/2) - [cypress-example-recipes](https://github.com/cypress-io/cypress-example-recipes/issues/225) - - [cypress-example-api-testing](https://github.com/cypress-io/cypress-example-api-testing/issues/15) - [angular-pizza-creator](https://github.com/cypress-io/angular-pizza-creator/issues/5) - [cypress-fiddle](https://github.com/cypress-io/cypress-fiddle/issues/5) - - [cypress-example-piechopper](https://github.com/cypress-io/cypress-example-piechopper/issues/75) - [cypress-documentation](https://github.com/cypress-io/cypress-documentation/issues/1313) - [cypress-example-docker-compose](https://github.com/cypress-io/cypress-example-docker-compose) - Doesn't have a Renovate issue, but will auto-create and auto-merge non-major Cypress updates as long as the tests pass. @@ -209,11 +207,6 @@ In the following instructions, "X.Y.Z" is used to denote the [next version of Cy **Test Repos** - [cypress-test-tiny](https://github.com/cypress-io/cypress-test-tiny) - - [cypress-test-nested-projects](https://github.com/cypress-io/cypress-test-nested-projects) - - [cypress-test-example-repos](https://github.com/cypress-io/cypress-test-example-repos) - - [cypress-test-node-versions](https://github.com/cypress-io/cypress-test-node-versions) - - [cypress-test-module-api](https://github.com/cypress-io/cypress-test-module-api) - - [cypress-test-ci-environments](https://github.com/cypress-io/cypress-test-ci-environments) **Example Repos** @@ -222,8 +215,6 @@ In the following instructions, "X.Y.Z" is used to denote the [next version of Cy - [cypress-example-realworld](https://github.com/cypress-io/cypress-example-realworld) - [cypress-example-recipes](https://github.com/cypress-io/cypress-example-recipes) - [cypress-example-docker-compose](https://github.com/cypress-io/cypress-example-docker-compose) - - [cypress-example-api-testing](https://github.com/cypress-io/cypress-example-api-testing) - - [cypress-example-piechopper](https://github.com/cypress-io/cypress-example-piechopper) - [cypress-documentation](https://github.com/cypress-io/cypress-documentation) Take a break, you deserve it! :sunglasses: diff --git a/scripts/binary/bump.js b/scripts/binary/bump.js index f9932db0ff34..f368f9aadc2a 100644 --- a/scripts/binary/bump.js +++ b/scripts/binary/bump.js @@ -17,8 +17,6 @@ const _PROVIDERS = { main: 'cypress-io/cypress', linux: [ 'cypress-io/cypress-test-module-api', - 'cypress-io/cypress-test-node-versions', - 'cypress-io/cypress-test-ci-environments', ], }, } diff --git a/system-tests/README.md b/system-tests/README.md index 2a3ad47b4b70..a3504765de02 100644 --- a/system-tests/README.md +++ b/system-tests/README.md @@ -49,7 +49,7 @@ describe('my new project', () => { systemTests.setup() systemTests.it('fails as expected', { - project: Fixtures.projectPath('my-new-project'), + project: 'my-new-project', snapshot: true, spec: '*', expectedExitCode: 2 @@ -61,6 +61,36 @@ From here, you could run this test with `yarn test my-new-project`. There are many more options available for `systemTests.it` and `systemTests.setup`. You can massage the stdout, do pre-run tasks, set up HTTP/S servers, and more. Explore the typedocs in [`./lib/system-tests`](./lib/system-tests) for more information. +These tests run in the `system-tests-*` CI jobs. + +### Developing Docker-based tests against built binary + +Specs in the [`./test`](./test) directory are run against an unbuilt Cypress App. They don't test `cypress` NPM package installation or other prod app behavior. This is done so that they can run as fast as possible in CI, without waiting for a full build of the Cypress App. + +Specs in [`./test-binary`](./test-binary) are run against the *built Cypress App*. They also run inside of their own Docker containers to give a blank slate environment for Cypress to run in. Before each test, the prod CLI is `npm install`ed along with the built Cypress `.zip`, and real `cypress run` commands are used to run the tests. There should be no functional difference between running a project in these tests and running real prod Cypress inside of Docker in CI. + +The purpose of these tests is to test things that we normally can't inside of regular `system-tests`, such as testing Cypress with different Node versions, with/without Xvfb, or inside of different operating system versions. + +An example of using `dockerImage` and `withBinary` to write a binary system test: + +```ts +// ./test-binary/node-versions.spec.ts +import systemTests from '../lib/system-tests' +import Fixtures from '../lib/fixtures' + +describe('node versions', () => { + systemTests.it('runs in node 12', { + dockerImage: 'cypress:node/12', + project: 'todos', + withBinary: true, + }) +}) +``` + +Running `yarn test node-versions` would spin up a local Docker container for `cypress:node/12`, install Cypress from `../cypress.zip` and `../cli/build`, and then call the regular `cypress run` command within the container. Other options for `systemTests.it` such as `onRun` and `expectedExitCode` still function normally. + +These tests run in the `binary-system-tests` CI job. + ### Updating Snaphots Prepend `SNAPSHOT_UPDATE=1` to any test command. See [`snap-shot-it` instructions](https://github.com/bahmutov/snap-shot-it#advanced-use) for more info. diff --git a/system-tests/lib/docker.ts b/system-tests/lib/docker.ts new file mode 100644 index 000000000000..9d82af21d81b --- /dev/null +++ b/system-tests/lib/docker.ts @@ -0,0 +1,151 @@ +import type { SpawnerResult, Spawner } from './system-tests' +import Docker from 'dockerode' +import stream from 'stream' +import EventEmitter from 'events' +import path from 'path' +import { promises as fs } from 'fs' +import execa from 'execa' +import Fixtures from './fixtures' +import { nock } from './spec_helper' + +let docker: Docker | null = null + +const getDocker = () => { + return docker || (docker = new Docker()) +} + +const log = (...args) => { + console.error('🐋', ...args) +} + +class DockerProcess extends EventEmitter implements SpawnerResult { + stdout = new stream.PassThrough() + stderr = new stream.PassThrough() + + constructor (private dockerImage: string) { + super() + } + + pull () { + return new Promise((resolve, reject) => { + log('Pulling image', this.dockerImage) + getDocker().pull(this.dockerImage, null, (err, stream) => { + if (err) return reject(err) + + const onFinished = (err) => { + log('Pull complete', { err }) + if (err) return reject(err) + + resolve() + } + + const onProgress = (event) => { + log('Pull progress', JSON.stringify(event)) + } + + docker.modem.followProgress(stream, onFinished, onProgress) + }, null) + }) + } + + run (opts: { + cmd: string + args: string[] + env: Record + }) { + const containerCreateEnv = [] + + for (const k in opts.env) { + // skip problematic env vars that we don't wanna preserve from `process.env` + if (['DISPLAY', 'USER', 'HOME', 'USERNAME', 'PATH'].includes(k)) continue + + containerCreateEnv.push([k, opts.env[k]].join('=')) + } + + log('Running image', this.dockerImage) + + const cmd = [opts.cmd, ...opts.args] + + log('Running cmd', cmd.join(' ')) + + getDocker().run( + this.dockerImage, + cmd, + [this.stdout, this.stderr], + // option docs: https://docs.docker.com/engine/api/v1.37/#operation/ContainerCreate + { + AutoRemove: true, + Entrypoint: 'bash', + Tty: false, // so we can use stdout and stderr + Env: containerCreateEnv, + Binds: [ + [path.join(__dirname, '..', '..'), '/cypress'], + // map tmpDir to the same absolute path on the container to make it easier to reason about paths in tests + [Fixtures.cyTmpDir, Fixtures.cyTmpDir], + ].map((a) => a.join(':')), + }, + // option docs: https://docs.docker.com/engine/api/v1.37/#operation/ContainerStart + {}, + (err, data) => { + if (err) { + log('Docker run errored:', { err, data }) + + return this.emit('error', err) + } + + log('Docker run exited:', { err, data }) + this.emit('exit', data.StatusCode) + }, + ) + } +} + +const checkBuiltBinary = async () => { + try { + await fs.stat(path.join(__dirname, '..', '..', 'cypress.zip')) + } catch (err) { + throw new Error('Expected built cypress.zip at project root. Run `yarn binary-build` and `yarn binary-zip`.') + } + + try { + await fs.stat(path.join(__dirname, '..', '..', 'cli/build/package.json')) + } catch (err) { + throw new Error('Expected built CLI in /cli/build. Run `yarn build` in `cli`.') + } +} + +export const dockerSpawner: Spawner = async (cmd, args, env, options) => { + await checkBuiltBinary() + + const projectPath = Fixtures.projectPath(options.project) + + log('Running chmod 0777 on', projectPath, 'to avoid Docker permissions issues.') + await execa('chmod', `-R 0777 ${projectPath}`.split(' ')) + + const proc = new DockerProcess(options.dockerImage) + + nock.enableNetConnect('localhost') + + await proc.pull() + + if (options.withBinary) { + args = [cmd, ...args] + cmd = `/cypress/system-tests/scripts/bootstrap-docker-container.sh` + } else { + throw new Error('Docker testing is only supported with built binaries (withBinary: true)') + } + + env = { + ...env, + TEST_PROJECT_DIR: projectPath, + REPO_DIR: '/cypress', + } + + proc.run({ + cmd, + args, + env, + }) + + return proc +} diff --git a/system-tests/lib/fixtures.ts b/system-tests/lib/fixtures.ts index 5f7d7725be66..4d7f96a73476 100644 --- a/system-tests/lib/fixtures.ts +++ b/system-tests/lib/fixtures.ts @@ -9,7 +9,8 @@ const root = _path.join(__dirname, '..') const serverRoot = _path.join(__dirname, '../../packages/server/') const projects = _path.join(root, 'projects') -const cyTmpDir = _path.join(tempDir, 'cy-projects') + +export const cyTmpDir = _path.join(tempDir, 'cy-projects') // copy contents instead of deleting+creating new file, which can cause // filewatchers to lose track of toFile. diff --git a/system-tests/lib/system-tests.ts b/system-tests/lib/system-tests.ts index 16d8ab2161f3..aa90d2bb6bb9 100644 --- a/system-tests/lib/system-tests.ts +++ b/system-tests/lib/system-tests.ts @@ -1,7 +1,9 @@ const snapshot = require('snap-shot-it') import { SpawnOptions } from 'child_process' +import stream from 'stream' import { expect } from './spec_helper' +import { dockerSpawner } from './docker' require('mocha-banner').register() const chalk = require('chalk').default @@ -11,7 +13,6 @@ const path = require('path') const http = require('http') const human = require('human-interval') const morgan = require('morgan') -const stream = require('stream') const express = require('express') const Bluebird = require('bluebird') const debug = require('debug')('cypress:system-tests') @@ -19,7 +20,6 @@ const httpsProxy = require('@packages/https-proxy') const Fixtures = require('./fixtures') const { allowDestroy } = require(`@packages/server/lib/util/server_destroy`) -const cypress = require(`@packages/server/lib/cypress`) const screenshots = require(`@packages/server/lib/screenshots`) const videoCapture = require(`@packages/server/lib/video_capture`) const settings = require(`@packages/server/lib/util/settings`) @@ -40,7 +40,7 @@ type ExecResult = { type ExecFn = (options?: ExecOptions) => Promise -type ItOptions = ExecOptions & { +export type ItOptions = ExecOptions & { /** * If a function is supplied, it will be executed instead of running the `systemTests.exec` function immediately. */ @@ -58,6 +58,14 @@ type ItOptions = ExecOptions & { } type ExecOptions = { + /** + * If set, `docker exec` will be used to run this test. Requires Docker. + */ + dockerImage?: string + /* + * If set, test using the built Cypress CLI and binary. Expects a built CLI in `/cli/build` and packed binary in `/cypress.zip`. + */ + withBinary?: boolean /** * Deprecated. Use `--cypress-inspect-brk` from command line instead. * @deprecated @@ -84,6 +92,10 @@ type ExecOptions = { * The spec argument to pass to Cypress. */ spec?: string + /** + * If set, use a non-default spec dir. + */ + specDir?: string /** * The project fixture to scaffold and pass to Cypress. */ @@ -244,11 +256,31 @@ type SetupOptions = { settings?: CypressConfig } +export type Spawner = (cmd, args, env, options: ExecOptions) => SpawnerResult | Promise + +export type SpawnerResult = { + stdout: stream.Readable + stderr: stream.Readable + on(event: 'error', cb: (err: Error) => void): void + on(event: 'exit', cb: (exitCode: number) => void): void +} + +const cpSpawner: Spawner = (cmd, args, env, options) => { + if (options.withBinary) { + throw new Error('withBinary is not supported without the use of dockerImage') + } + + return cp.spawn(cmd, args, { + env, + ...options.spawnOpts, + }) +} + const serverPath = path.dirname(require.resolve('@packages/server')) cp = Bluebird.promisifyAll(cp) -const env = _.clone(process.env) +const processEnvCache = _.clone(process.env) Bluebird.config({ longStackTraces: true, @@ -689,7 +721,7 @@ const systemTests = { }) afterEach(async function () { - process.env = _.clone(env) + process.env = _.clone(processEnvCache) this.timeout(human('2 minutes')) @@ -748,9 +780,10 @@ const systemTests = { return spec } - const specDir = options.testingType === 'component' ? 'component' : 'integration' + const specDir = options.specDir + || (options.testingType === 'component' ? 'cypress/component' : 'cypress/integration') - return path.join(projectPath, 'cypress', specDir, spec) + return path.join(projectPath, specDir, spec) }) // normalize the path to the spec @@ -763,10 +796,15 @@ const systemTests = { args (options: ExecOptions) { debug('converting options to args %o', { options }) - const args = [ + const projectPath = Fixtures.projectPath(options.project) + const args = options.withBinary ? [ + `run`, + `--project=${projectPath}`, + ] : [ + require.resolve('@packages/server'), // hides a user warning to go through NPM module `--cwd=${serverPath}`, - `--run-project=${Fixtures.projectPath(options.project)}`, + `--run-project=${projectPath}`, `--testingType=${options.testingType || 'e2e'}`, ] @@ -862,20 +900,6 @@ const systemTests = { return args }, - start (ctx, options: ExecOptions) { - options = this.options(ctx, options) - const args = this.args(options) - - return cypress.start(args) - .then(() => { - const { expectedExitCode } = options - - maybeVerifyExitCode(expectedExitCode, () => { - expect(process.exit).to.be.calledWith(expectedExitCode) - }) - }) - }, - /** * Executes a given project and optionally sanitizes and checks output. * @example @@ -896,7 +920,7 @@ const systemTests = { debug('systemTests.exec options %o', options) options = this.options(ctx, options) debug('processed options %o', options) - let args = this.args(options) + const args = options.args || this.args(options) const specifiedBrowser = process.env.BROWSER @@ -905,7 +929,8 @@ const systemTests = { } if (!options.skipScaffold) { - await Fixtures.scaffoldCommonNodeModules() + // symlinks won't work via docker + options.dockerImage || await Fixtures.scaffoldCommonNodeModules() Fixtures.scaffoldProject(options.project) await Fixtures.scaffoldProjectNodeModules(options.project) } @@ -918,10 +943,6 @@ const systemTests = { await settings.write(e2ePath, ctx.settings) } - const serverEntryFile = require.resolve('@packages/server') - - args = options.args || [serverEntryFile].concat(args) - let stdout = '' let stderr = '' @@ -997,41 +1018,43 @@ const systemTests = { } debug('spawning Cypress %o', { args }) - const cmd = options.command || 'node' - const sp = cp.spawn(cmd, args, { - env: _.chain(process.env) - .omit('CYPRESS_DEBUG') - .extend({ - // FYI: color will be disabled - // because we are piping the child process - COLUMNS: 100, - LINES: 24, - }) - .defaults({ - // match CircleCI's filesystem limits, so screenshot names in snapshots match - CYPRESS_MAX_SAFE_FILENAME_BYTES: 242, - FAKE_CWD_PATH: '/XXX/XXX/XXX', - DEBUG_COLORS: '1', - // prevent any Compression progress - // messages from showing up - VIDEO_COMPRESSION_THROTTLE: 120000, - - // don't fail our own tests running from forked PR's - CYPRESS_INTERNAL_SYSTEM_TESTS: '1', - - // Emulate no typescript environment - CYPRESS_INTERNAL_NO_TYPESCRIPT: options.noTypeScript ? '1' : '0', - - // disable frame skipping to make quick Chromium tests have matching snapshots/working video - CYPRESS_EVERY_NTH_FRAME: 1, - - // force file watching for use with --no-exit - ...(options.noExit ? { CYPRESS_INTERNAL_FORCE_FILEWATCH: '1' } : {}), - }) - .extend(options.processEnv) - .value(), - ...options.spawnOpts, + + const cmd = options.command || (options.withBinary ? 'cypress' : 'node') + + const env = _.chain(process.env) + .omit('CYPRESS_DEBUG') + .extend({ + // FYI: color will be disabled + // because we are piping the child process + COLUMNS: 100, + LINES: 24, + }) + .defaults({ + // match CircleCI's filesystem limits, so screenshot names in snapshots match + CYPRESS_MAX_SAFE_FILENAME_BYTES: 242, + FAKE_CWD_PATH: '/XXX/XXX/XXX', + DEBUG_COLORS: '1', + // prevent any Compression progress + // messages from showing up + VIDEO_COMPRESSION_THROTTLE: 120000, + + // don't fail our own tests running from forked PR's + CYPRESS_INTERNAL_SYSTEM_TESTS: '1', + + // Emulate no typescript environment + CYPRESS_INTERNAL_NO_TYPESCRIPT: options.noTypeScript ? '1' : '0', + + // disable frame skipping to make quick Chromium tests have matching snapshots/working video + CYPRESS_EVERY_NTH_FRAME: 1, + + // force file watching for use with --no-exit + ...(options.noExit ? { CYPRESS_INTERNAL_FORCE_FILEWATCH: '1' } : {}), }) + .extend(options.processEnv) + .value() + + const spawnerFn: Spawner = options.dockerImage ? dockerSpawner : cpSpawner + const sp: SpawnerResult = await spawnerFn(cmd, args, env, options) const ColorOutput = function () { const colorOutput = new stream.Transform() diff --git a/system-tests/package.json b/system-tests/package.json index 5c99c7d9ff23..68fcd25150ac 100644 --- a/system-tests/package.json +++ b/system-tests/package.json @@ -6,7 +6,7 @@ "main": "index.js", "scripts": { "projects:yarn:install": "node ./scripts/projects-yarn-install.js", - "test": "node ./scripts/run.js --glob-in-dir=test", + "test": "node ./scripts/run.js --glob-in-dir='{test,test-binary}'", "test:ci": "node ./scripts/run.js" }, "devDependencies": { @@ -43,6 +43,7 @@ "cors": "2.8.5", "dayjs": "^1.9.3", "debug": "^4.3.2", + "dockerode": "3.3.1", "execa": "1.0.0", "express": "4.17.1", "express-session": "1.16.1", diff --git a/system-tests/scripts/bootstrap-docker-container.sh b/system-tests/scripts/bootstrap-docker-container.sh new file mode 100755 index 000000000000..058f215c5489 --- /dev/null +++ b/system-tests/scripts/bootstrap-docker-container.sh @@ -0,0 +1,53 @@ +#!/bin/bash +set -e # exit on error + +echo "$0 running as $(whoami)" +echo "Node version: $(node -v)" + +if [ ! -d "$TEST_PROJECT_DIR" ]; then + echo "Missing TEST_PROJECT_DIR=$TEST_PROJECT_DIR. Check Docker Bind+Env config" + exit 1 +fi + +if [ ! -d "$REPO_DIR" ]; then + echo "Missing REPO_DIR=$REPO_DIR. Check Docker Bind+Env config" + exit 1 +fi + +ZIP_PATH=$REPO_DIR/cypress.zip +CLI_PATH=$REPO_DIR/cli/build + +if [ ! -f "$ZIP_PATH" ]; then + echo "Missing $ZIP_PATH. Check Docker Bind config" + exit 1 +fi + +if [ ! -d "$CLI_PATH" ]; then + echo "Missing $CLI_PATH. Check Docker Bind config" + exit 1 +fi + +set -x # log commands + +cd $TEST_PROJECT_DIR + +export CYPRESS_INSTALL_BINARY=$ZIP_PATH +export CYPRESS_CACHE_FOLDER=/tmp/CYPRESS_CACHE_FOLDER/ + +npm install --save-dev --unsafe-perm --allow-root $CLI_PATH + +PATH=$PATH:./node_modules/.bin + +cypress install + +# run command passed in argv and store exit code +set +e +$@ +EXIT_CODE=$? +set -e + +# delete tmp to avoid permissions issues on the host +cd - +rm -rf $TEST_PROJECT_DIR + +exit $EXIT_CODE \ No newline at end of file diff --git a/system-tests/test-binary/ci_environments_spec.ts b/system-tests/test-binary/ci_environments_spec.ts new file mode 100644 index 000000000000..39d15c1d3fbb --- /dev/null +++ b/system-tests/test-binary/ci_environments_spec.ts @@ -0,0 +1,41 @@ +import systemTests, { ItOptions } from '../lib/system-tests' + +function smokeTestDockerImage (title: string, dockerImage: string, expectedExitCode: number, onRun?: ItOptions['onRun']) { + systemTests.it(title, { + withBinary: true, + browser: 'electron', + dockerImage, + spec: 'test1.js', + specDir: 'tests', + project: 'todos', + expectedExitCode, + onRun, + }) +} + +describe('e2e binary CI environments', () => { + smokeTestDockerImage( + 'bare node image fails (lacks xvfb)', + 'node:12', 1, + async (exec) => { + const { stdout } = await exec() + + expect(stdout).to.include('Your system is missing the dependency: Xvfb') + }, + ) + + smokeTestDockerImage( + 'bare xvfb image fails', + 'cypressinternal/xvfb:12.13.0', 1, + ) + + smokeTestDockerImage( + 'ubuntu 16 passes', + 'cypress/base:ubuntu16-12.13.1', 0, + ) + + smokeTestDockerImage( + 'ubuntu 19 passes', + 'cypress/base:ubuntu19-node12.14.1', 0, + ) +}) diff --git a/system-tests/test-binary/node_versions_spec.ts b/system-tests/test-binary/node_versions_spec.ts new file mode 100644 index 000000000000..8d1483ab410c --- /dev/null +++ b/system-tests/test-binary/node_versions_spec.ts @@ -0,0 +1,21 @@ +import systemTests from '../lib/system-tests' + +function smokeTestDockerImage (dockerImage: string) { + systemTests.it(`can run in ${dockerImage}`, { + withBinary: true, + browser: 'electron', + dockerImage, + spec: 'test1.js', + specDir: 'tests', + project: 'todos', + }) +} + +describe('e2e binary node versions', () => { + [ + 'cypress/base:12', + 'cypress/base:14', + 'cypress/base:16.5.0', + 'cypress/base:17.3.0', + ].forEach(smokeTestDockerImage) +}) diff --git a/yarn.lock b/yarn.lock index f10fbad4601d..2a43b75ebe3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10849,10 +10849,10 @@ asn1.js@^5.2.0: minimalistic-assert "^1.0.0" safer-buffer "^2.1.0" -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== +asn1@^0.2.4, asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== dependencies: safer-buffer "~2.1.0" @@ -12388,7 +12388,7 @@ batch@0.6.1: resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= -bcrypt-pbkdf@^1.0.0: +bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= @@ -15207,6 +15207,13 @@ cp-file@^7.0.0: nested-error-stacks "^2.0.0" p-event "^4.1.0" +cpu-features@0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.2.tgz#9f636156f1155fd04bdbaa028bb3c2fbef3cea7a" + integrity sha512-/2yieBqvMcRj8McNzkycjW2v3OIUOibBfd2dLEJ0nWts8NobAxwiyw9phVNS6oDL8x8tz9F7uNVFEVpJncQpeA== + dependencies: + nan "^2.14.1" + cpy@^8.1.1: version "8.1.2" resolved "https://registry.yarnpkg.com/cpy/-/cpy-8.1.2.tgz#e339ea54797ad23f8e3919a5cffd37bfc3f25935" @@ -17037,6 +17044,24 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" +docker-modem@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/docker-modem/-/docker-modem-3.0.3.tgz#ac4bb1f32f81ac2e7120c5e99a068fab2458a32f" + integrity sha512-Tgkn2a+yiNP9FoZgMa/D9Wk+D2Db///0KOyKSYZRJa8w4+DzKyzQMkczKSdR/adQ0x46BOpeNkoyEOKjPhCzjw== + dependencies: + debug "^4.1.1" + readable-stream "^3.5.0" + split-ca "^1.0.1" + ssh2 "^1.4.0" + +dockerode@3.3.1: + version "3.3.1" + resolved "https://registry.npmjs.org/dockerode/-/dockerode-3.3.1.tgz#74f66e239e092e7910e2beae6322d35c44b08cdc" + integrity sha512-AS2mr8Lp122aa5n6d99HkuTNdRV1wkkhHwBdcnY6V0+28D3DSYwhxAk85/mM9XwD3RMliTxyr63iuvn5ZblFYQ== + dependencies: + docker-modem "^3.0.0" + tar-fs "~2.0.1" + doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" @@ -28084,10 +28109,10 @@ mz@^2.4.0, mz@^2.5.0: object-assign "^4.0.1" thenify-all "^1.0.0" -nan@^2.10.0, nan@^2.12.1: - version "2.14.2" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" - integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== +nan@^2.10.0, nan@^2.12.1, nan@^2.14.1, nan@^2.15.0: + version "2.15.0" + resolved "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" + integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== nanoid@3.1.20: version "3.1.20" @@ -36535,6 +36560,11 @@ spin.js@2.x: resolved "https://registry.yarnpkg.com/spin.js/-/spin.js-2.3.2.tgz#6caa56d520673450fd5cfbc6971e6d0772c37a1a" integrity sha1-bKpW1SBnNFD9XPvGlx5tB3LDeho= +split-ca@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6" + integrity sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY= + split-on-first@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" @@ -36602,6 +36632,17 @@ ssestream@1.0.1: resolved "https://registry.yarnpkg.com/ssestream/-/ssestream-1.0.1.tgz#351551b12c00e91e7550f38d558323f3f47b54c2" integrity sha1-NRVRsSwA6R51UPONVYMj8/R7VMI= +ssh2@^1.4.0: + version "1.6.0" + resolved "https://registry.npmjs.org/ssh2/-/ssh2-1.6.0.tgz#61aebc3a6910fe488f9c85cd8355bdf8d4724e05" + integrity sha512-lxc+uvXqOxyQ99N2M7k5o4pkYDO5GptOTYduWw7hIM41icxvoBcCNHcj+LTKrjkL0vFcAl+qfZekthoSFRJn2Q== + dependencies: + asn1 "^0.2.4" + bcrypt-pbkdf "^1.0.2" + optionalDependencies: + cpu-features "0.0.2" + nan "^2.15.0" + sshpk@^1.14.1, sshpk@^1.7.0: version "1.16.1" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" @@ -37630,7 +37671,17 @@ tar-fs@^2.0.0: pump "^3.0.0" tar-stream "^2.1.4" -tar-stream@^2.1.4: +tar-fs@~2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2" + integrity sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.0.0" + +tar-stream@^2.0.0, tar-stream@^2.1.4: version "2.2.0" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== From 65ea8f73e459f9708827ed7dcfa980564022eb2f Mon Sep 17 00:00:00 2001 From: Ryan Manuel Date: Fri, 18 Feb 2022 17:57:34 -0600 Subject: [PATCH 33/35] chore: fix server performance flake (#20271) --- packages/server/lib/environment.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/server/lib/environment.js b/packages/server/lib/environment.js index c9e7c59e9e9f..4a20b9df2443 100644 --- a/packages/server/lib/environment.js +++ b/packages/server/lib/environment.js @@ -62,6 +62,10 @@ try { // https://github.com/cypress-io/cypress/issues/15814 app.commandLine.appendSwitch('disable-dev-shm-usage') + // prevent navigation throttling when navigating in the browser rapid fire + // https://github.com/cypress-io/cypress/pull/20271 + app.commandLine.appendSwitch('disable-ipc-flooding-protection') + if (os.platform() === 'linux') { app.disableHardwareAcceleration() } From 1fb16b0c56c23c91d64bd8a26d056e350c5cc61e Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Sun, 20 Feb 2022 16:22:08 -0500 Subject: [PATCH 34/35] chore: fix cache keys to include PLATFORM (#20279) * chore: fix cache keys to include PLATFORM * build this branch * try using platform_key --- circle.yml | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/circle.yml b/circle.yml index 3287cfc3a775..2edd9135a6af 100644 --- a/circle.yml +++ b/circle.yml @@ -29,7 +29,7 @@ mainBuildFilters: &mainBuildFilters only: - develop - 10.0-release - - other-projects-cleanup + - fix-darwin-win32-node-modules-install # usually we don't build Mac app - it takes a long time # but sometimes we want to really confirm we are doing the right thing @@ -38,7 +38,7 @@ macWorkflowFilters: &mac-workflow-filters when: or: - equal: [ develop, << pipeline.git.branch >> ] - - equal: [ renovate/cypress-request-2.x, << pipeline.git.branch >> ] + - equal: [ fix-darwin-win32-node-modules-install, << pipeline.git.branch >> ] - matches: pattern: "-release$" value: << pipeline.git.branch >> @@ -48,7 +48,7 @@ windowsWorkflowFilters: &windows-workflow-filters or: - equal: [ master, << pipeline.git.branch >> ] - equal: [ develop, << pipeline.git.branch >> ] - - equal: [ test-binary-downstream-windows, << pipeline.git.branch >> ] + - equal: [ fix-darwin-win32-node-modules-install, << pipeline.git.branch >> ] - matches: pattern: "-release$" value: << pipeline.git.branch >> @@ -167,9 +167,12 @@ commands: - run: name: Generate Circle Cache Key command: node scripts/circle-cache.js --action cacheKey > circle_cache_key + - run: + name: Generate platform key + command: echo $PLATFORM > platform_key - restore_cache: name: Restore cache state, to check for known modules cache existence - key: v{{ .Environment.CACHE_VERSION }}-node-modules-cache-{{ checksum "circle_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-node-modules-cache-{{ checksum "circle_cache_key" }} - run: name: Move node_modules back from /tmp command: | @@ -190,11 +193,14 @@ commands: - run: name: Generate Circle Cache key for system tests command: ./system-tests/scripts/cache-key.sh > system_tests_cache_key + - run: + name: Generate platform key + command: echo $PLATFORM > platform_key - restore_cache: name: Restore system tests node_modules cache keys: - - v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} - - v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache- + - v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} + - v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-system-tests-projects-node-modules-cache- update_cached_system_tests_deps: description: 'Update the cached node_modules for projects in "system-tests/projects/**"' @@ -202,10 +208,13 @@ commands: - run: name: Generate Circle Cache key for system tests command: ./system-tests/scripts/cache-key.sh > system_tests_cache_key + - run: + name: Generate platform key + command: echo $PLATFORM > platform_key - restore_cache: name: Restore cache state, to check for known modules cache existence keys: - - v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }} + - v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }} - run: name: Send root honeycomb event for this CI build command: cd system-tests/scripts && node ./send-root-honecomb-event.js @@ -219,20 +228,20 @@ commands: - restore_cache: name: Restore system tests node_modules cache keys: - - v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} - - v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache- + - v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} + - v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-system-tests-projects-node-modules-cache- - run: name: Update system-tests node_modules cache command: yarn workspace @tooling/system-tests projects:yarn:install - save_cache: name: Save system tests node_modules cache - key: v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-system-tests-projects-node-modules-cache-{{ checksum "system_tests_cache_key" }} paths: - ~/.cache/cy-system-tests-node-modules - run: touch /tmp/system_tests_node_modules_installed - save_cache: name: Save system tests node_modules cache state key - key: v{{ .Environment.CACHE_VERSION }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-system-tests-projects-node-modules-cache-state-{{ checksum "system_tests_cache_key" }} paths: - /tmp/system_tests_node_modules_installed @@ -247,9 +256,12 @@ commands: - run: name: Generate Circle Cache Key command: node scripts/circle-cache.js --action cacheKey > circle_cache_key + - run: + name: Generate platform key + command: echo $PLATFORM > platform_key - restore_cache: name: Restore cache state, to check for known modules cache existence - key: v{{ .Environment.CACHE_VERSION }}-node-modules-cache-state-{{ checksum "circle_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-node-modules-cache-state-{{ checksum "circle_cache_key" }} - run: name: Bail if cache exists command: | @@ -261,7 +273,7 @@ commands: - restore_cache: name: Restore weekly yarn cache keys: - - v{{ .Environment.CACHE_VERSION }}-deps-root-weekly-{{ checksum "cache_date" }} + - v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-deps-root-weekly-{{ checksum "cache_date" }} - run: name: Install Node Modules command: | @@ -274,7 +286,7 @@ commands: steps: - save_cache: name: Saving node modules for root, cli, and all globbed workspace packages - key: v{{ .Environment.CACHE_VERSION }}-node-modules-cache-{{ checksum "circle_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-node-modules-cache-{{ checksum "circle_cache_key" }} paths: - node_modules - cli/node_modules @@ -285,18 +297,18 @@ commands: steps: - save_cache: name: Saving node modules for root, cli, and all globbed workspace packages - key: v{{ .Environment.CACHE_VERSION }}-node-modules-cache-{{ checksum "circle_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-node-modules-cache-{{ checksum "circle_cache_key" }} paths: - /tmp/node_modules_cache - run: touch /tmp/node_modules_installed - save_cache: name: Saving node-modules cache state key - key: v{{ .Environment.CACHE_VERSION }}-node-modules-cache-state-{{ checksum "circle_cache_key" }} + key: v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-node-modules-cache-state-{{ checksum "circle_cache_key" }} paths: - /tmp/node_modules_installed - save_cache: name: Save weekly yarn cache - key: v{{ .Environment.CACHE_VERSION }}-deps-root-weekly-{{ checksum "cache_date" }} + key: v{{ .Environment.CACHE_VERSION }}-{{ checksum "platform_key" }}-deps-root-weekly-{{ checksum "cache_date" }} paths: - ~/.yarn @@ -1185,6 +1197,7 @@ jobs: working_directory: ~/cypress environment: <<: *defaultsEnvironment + PLATFORM: linux machine: # using `machine` gives us a Linux VM that can run Docker image: ubuntu-2004:202111-02 @@ -1613,7 +1626,7 @@ jobs: - run: name: Check current branch to persist artifacts command: | - if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "other-projects-cleanup" ]]; then + if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "fix-darwin-win32-node-modules-install" ]]; then echo "Not uploading artifacts or posting install comment for this branch." circleci-agent step halt fi From 0143e1338869f54809f9dfa97f21131728e5be32 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 21 Feb 2022 23:01:35 +0000 Subject: [PATCH 35/35] fix(deps): update dependency url-parse to v1.5.6 [security] (#20270) Co-authored-by: Renovate Bot --- packages/driver/package.json | 2 +- packages/server/package.json | 2 +- yarn.lock | 10 +++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/driver/package.json b/packages/driver/package.json index 946964e6c388..464e617c5736 100644 --- a/packages/driver/package.json +++ b/packages/driver/package.json @@ -80,7 +80,7 @@ "text-mask-addons": "3.8.0", "underscore.string": "3.3.5", "unfetch": "4.1.0", - "url-parse": "1.5.2", + "url-parse": "1.5.6", "vanilla-text-mask": "5.1.1", "vite": "^2.4.4", "webpack": "4.41.2", diff --git a/packages/server/package.json b/packages/server/package.json index 06bda7b2e370..de8fc69c5d96 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -116,7 +116,7 @@ "tsconfig-paths": "3.10.1", "tslib": "2.3.0", "underscore.string": "3.3.5", - "url-parse": "1.5.2", + "url-parse": "1.5.6", "uuid": "8.3.2", "which": "2.0.2", "widest-line": "3.1.0", diff --git a/yarn.lock b/yarn.lock index 2a43b75ebe3b..47234a495f32 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39397,7 +39397,15 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" -url-parse@1.5.2, url-parse@^1.4.3, url-parse@^1.4.7: +url-parse@1.5.6: + version "1.5.6" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.6.tgz#b2a41d5a233645f3c31204cc8be60e76a15230a2" + integrity sha512-xj3QdUJ1DttD1LeSfvJlU1eiF1RvBSBfUu8GplFGdUzSO28y5yUtEl7wb//PI4Af6qh0o/K8545vUmucRrfWsw== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +url-parse@^1.4.3, url-parse@^1.4.7: version "1.5.2" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.2.tgz#a4eff6fd5ff9fe6ab98ac1f79641819d13247cda" integrity sha512-6bTUPERy1muxxYClbzoRo5qtQuyoGEbzbQvi0SW4/8U8UyVkAQhWFBlnigqJkRm4su4x1zDQfNbEzWkt+vchcg==