From cd4a16420971511b45a252fd688d0cd3f283e2e3 Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Mon, 3 Dec 2018 11:38:37 -0500 Subject: [PATCH 01/37] start of 4.0 From bb43e6f7954636a2213d0884197cd8fae32a0f58 Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Mon, 3 Dec 2018 12:08:09 -0500 Subject: [PATCH 02/37] Rename plugins to background (#2408) * rename plugins to background * rename missed directories named plugins * fix snapshot * fix plugins references in driver * error when pluginsFile is used * throw error when backgroundFile is default but plugins/index.js exists * fix wrong usage of fs.pathExists * update desktop-gui pluginsFIle use * fix e2e spec * background-guide -> background-process * fix desktop-gui spec * rename plugins to background --- .eslintignore | 2 +- cli/schema/cypress.schema.json | 6 +- cli/test/lib/tasks/download_spec.js | 25 +- packages/desktop-gui/cypress.json | 2 +- .../desktop-gui/cypress/fixtures/config.json | 2 +- .../integration/specs_list_spec.coffee | 2 +- .../src/settings/configuration.jsx | 4 +- .../desktop-gui/src/settings/settings.scss | 6 +- .../cypress/{plugins => background}/index.js | 5 +- .../integration/commands/task_spec.coffee | 4 +- .../cypress/{plugins => background}/index.js | 9 +- packages/runner/lib/test-setup.js | 8 +- .../2_controllers_spec.coffee.js | 2 +- ....js => 3_background_events_spec.coffee.js} | 51 ++- .../5_task_not_registered_spec.coffee.js | 12 +- .../__snapshots__/6_task_spec.coffee.js | 4 +- ...offee.js => run_background_spec.coffee.js} | 18 +- .../__snapshots__/scaffold_spec.coffee.js | 397 +++++++++--------- .../{plugins => background}/child/index.js | 4 +- .../child/preprocessor.js | 0 .../child/run_background.js} | 49 ++- .../lib/{plugins => background}/child/task.js | 13 +- .../lib/{plugins => background}/index.coffee | 48 +-- .../preprocessor.coffee | 12 +- .../lib/{plugins => background}/util.coffee | 2 +- packages/server/lib/browsers/chrome.coffee | 10 +- packages/server/lib/browsers/electron.coffee | 8 +- packages/server/lib/config.coffee | 93 ++-- packages/server/lib/controllers/spec.coffee | 2 +- packages/server/lib/errors.coffee | 31 +- packages/server/lib/open_project.coffee | 2 +- packages/server/lib/project.coffee | 50 +-- packages/server/lib/scaffold.coffee | 14 +- .../scaffold/{plugins => background}/index.js | 7 +- packages/server/lib/screenshots.coffee | 6 +- packages/server/lib/socket.coffee | 4 +- packages/server/lib/task.coffee | 20 +- packages/server/lib/util/path_helpers.js | 1 - packages/server/lib/util/random.js | 1 - packages/server/lib/util/saved_state.js | 1 - packages/server/lib/util/security.js | 2 - packages/server/lib/util/shell.js | 1 - packages/server/lib/util/specs.js | 2 - packages/server/lib/util/system.js | 1 - packages/server/lib/util/terminal.js | 4 - .../server/test/e2e/2_controllers_spec.coffee | 2 +- .../test/e2e/3_background_events_spec.coffee | 87 ++++ .../server/test/e2e/3_plugins_spec.coffee | 71 ---- packages/server/test/e2e/6_task_spec.coffee | 4 +- .../test/integration/cypress_spec.coffee | 28 +- .../integration/http_requests_spec.coffee | 2 +- .../cypress.json | 0 .../cypress/background}/index.js | 0 .../cypress/integration/absolute_spec.coffee | 2 +- .../cypress.json | 0 .../cypress/background}/index.js | 0 .../integration/after_screenshot_spec.coffee | 0 .../screenshot-replacement.png | Bin .../cypress.json | 0 .../cypress/background}/index.js | 2 +- .../cypress/integration/app_spec.coffee | 0 .../cypress.json | 0 .../cypress/background}/index.coffee | 0 .../cypress/integration/app_spec.coffee | 0 .../cypress.json | 0 .../cypress/background}/index.js | 0 .../cypress/integration/app_spec.coffee | 4 +- .../cypress.json | 0 .../cypress/background}/index.coffee | 0 .../cypress/integration/app_spec.coffee | 0 .../ext/background.js | 0 .../ext/manifest.json | 0 .../index.html | 0 .../background-plugins-file/cypress.json | 1 + .../background_plugins_file.coffee | 1 + .../cypress/plugins/index.js | 1 + .../cypress/{plugins => background}/index.js | 5 + .../cypress/{plugins => background}/.gitkeep | 0 .../cypress/background/index.js | 19 + .../cypress/plugins/index.js | 11 - .../cypress/{plugins => background}/index.js | 0 .../task_not_registered_spec.coffee | 2 +- .../fixtures/projects/todos/cypress.json | 2 +- .../cypress/{plugins => background}/index.js | 0 .../fixtures/server/throws_error.coffee | 2 +- .../child/preprocessor_spec.coffee | 6 +- .../child/run_background_spec.coffee} | 115 ++--- .../child/task_spec.coffee | 6 +- .../{plugins => background}/index_spec.coffee | 110 ++--- .../preprocessor_spec.coffee | 16 +- .../{plugins => background}/util_spec.coffee | 4 +- .../test/unit/browsers/chrome_spec.coffee | 26 +- .../test/unit/browsers/electron_spec.coffee | 14 +- packages/server/test/unit/config_spec.coffee | 56 +-- .../server/test/unit/open_project_spec.coffee | 2 +- packages/server/test/unit/project_spec.coffee | 74 ++-- .../server/test/unit/scaffold_spec.coffee | 44 +- .../server/test/unit/screenshots_spec.coffee | 18 +- packages/server/test/unit/socket_spec.coffee | 2 +- packages/server/test/unit/spec_spec.coffee | 2 +- packages/server/test/unit/task_spec.coffee | 56 +-- 101 files changed, 934 insertions(+), 810 deletions(-) rename packages/driver/test/cypress/{plugins => background}/index.js (85%) rename packages/example/cypress/{plugins => background}/index.js (71%) rename packages/server/__snapshots__/{3_plugins_spec.coffee.js => 3_background_events_spec.coffee.js} (91%) rename packages/server/__snapshots__/{run_plugins_spec.coffee.js => run_background_spec.coffee.js} (73%) rename packages/server/lib/{plugins => background}/child/index.js (76%) rename packages/server/lib/{plugins => background}/child/preprocessor.js (100%) rename packages/server/lib/{plugins/child/run_plugins.js => background/child/run_background.js} (77%) rename packages/server/lib/{plugins => background}/child/task.js (92%) rename packages/server/lib/{plugins => background}/index.coffee (53%) rename packages/server/lib/{plugins => background}/preprocessor.coffee (92%) rename packages/server/lib/{plugins => background}/util.coffee (97%) rename packages/server/lib/scaffold/{plugins => background}/index.js (69%) create mode 100644 packages/server/test/e2e/3_background_events_spec.coffee delete mode 100644 packages/server/test/e2e/3_plugins_spec.coffee rename packages/server/test/support/fixtures/projects/{plugin-after-screenshot => background-absolute-path}/cypress.json (100%) rename packages/server/test/support/fixtures/projects/{plugins-absolute-path/cypress/plugins => background-absolute-path/cypress/background}/index.js (100%) rename packages/server/test/support/fixtures/projects/{plugins-absolute-path => background-absolute-path}/cypress/integration/absolute_spec.coffee (61%) rename packages/server/test/support/fixtures/projects/{plugin-browser => background-after-screenshot}/cypress.json (100%) rename packages/server/test/support/fixtures/projects/{plugin-after-screenshot/cypress/plugins => background-after-screenshot/cypress/background}/index.js (100%) rename packages/server/test/support/fixtures/projects/{plugin-after-screenshot => background-after-screenshot}/cypress/integration/after_screenshot_spec.coffee (100%) rename packages/server/test/support/fixtures/projects/{plugin-after-screenshot => background-after-screenshot}/screenshot-replacement.png (100%) rename packages/server/test/support/fixtures/projects/{plugin-config => background-async-error}/cypress.json (100%) rename packages/server/test/support/fixtures/projects/{plugins-async-error/cypress/plugins => background-async-error/cypress/background}/index.js (73%) rename packages/server/test/support/fixtures/projects/{plugins-async-error => background-async-error}/cypress/integration/app_spec.coffee (100%) rename packages/server/test/support/fixtures/projects/{plugin-extension => background-browser}/cypress.json (100%) rename packages/server/test/support/fixtures/projects/{plugin-browser/cypress/plugins => background-browser/cypress/background}/index.coffee (100%) rename packages/server/test/support/fixtures/projects/{plugin-browser => background-browser}/cypress/integration/app_spec.coffee (100%) rename packages/server/test/support/fixtures/projects/{plugins-absolute-path => background-config}/cypress.json (100%) rename packages/server/test/support/fixtures/projects/{plugin-config/cypress/plugins => background-config/cypress/background}/index.js (100%) rename packages/server/test/support/fixtures/projects/{plugin-config => background-config}/cypress/integration/app_spec.coffee (81%) rename packages/server/test/support/fixtures/projects/{plugins-async-error => background-extension}/cypress.json (100%) rename packages/server/test/support/fixtures/projects/{plugin-extension/cypress/plugins => background-extension/cypress/background}/index.coffee (100%) rename packages/server/test/support/fixtures/projects/{plugin-extension => background-extension}/cypress/integration/app_spec.coffee (100%) rename packages/server/test/support/fixtures/projects/{plugin-extension => background-extension}/ext/background.js (100%) rename packages/server/test/support/fixtures/projects/{plugin-extension => background-extension}/ext/manifest.json (100%) rename packages/server/test/support/fixtures/projects/{plugin-extension => background-extension}/index.html (100%) create mode 100644 packages/server/test/support/fixtures/projects/background-plugins-file/cypress.json create mode 100644 packages/server/test/support/fixtures/projects/background-plugins-file/cypress/integration/background_plugins_file.coffee create mode 100644 packages/server/test/support/fixtures/projects/background-plugins-file/cypress/plugins/index.js rename packages/server/test/support/fixtures/projects/e2e/cypress/{plugins => background}/index.js (99%) rename packages/server/test/support/fixtures/projects/empty-folders/cypress/{plugins => background}/.gitkeep (100%) create mode 100644 packages/server/test/support/fixtures/projects/multiple-task-registrations/cypress/background/index.js delete mode 100644 packages/server/test/support/fixtures/projects/multiple-task-registrations/cypress/plugins/index.js rename packages/server/test/support/fixtures/projects/non-existent-spec/cypress/{plugins => background}/index.js (100%) rename packages/server/test/support/fixtures/projects/working-preprocessor/cypress/{plugins => background}/index.js (100%) rename packages/server/test/unit/{plugins => background}/child/preprocessor_spec.coffee (94%) rename packages/server/test/unit/{plugins/child/run_plugins_spec.coffee => background/child/run_background_spec.coffee} (59%) rename packages/server/test/unit/{plugins => background}/child/task_spec.coffee (93%) rename packages/server/test/unit/{plugins => background}/index_spec.coffee (52%) rename packages/server/test/unit/{plugins => background}/preprocessor_spec.coffee (93%) rename packages/server/test/unit/{plugins => background}/util_spec.coffee (98%) diff --git a/.eslintignore b/.eslintignore index 1e654ae4c95e..07b52e352103 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,5 @@ __snapshots__ -packages/server/lib/scaffold/plugins/index.js +packages/server/lib/scaffold/background/index.js packages/server/lib/scaffold/support/index.js packages/server/lib/scaffold/support/commands.js packages/server/test/fixtures diff --git a/cli/schema/cypress.schema.json b/cli/schema/cypress.schema.json index e76d3a223444..9ed7e5bdb3e8 100644 --- a/cli/schema/cypress.schema.json +++ b/cli/schema/cypress.schema.json @@ -84,10 +84,10 @@ "default": "cypress/integration", "description": "Path to folder containing integration test files" }, - "pluginsFile": { + "backgroundFile": { "type": ["string", "boolean"], - "default": "cypress/plugins/index.js", - "description": "Path to plugins file. (Pass false to disable)" + "default": "cypress/background/index.js", + "description": "Path to background file. (Pass false to disable)" }, "screenshotsFolder": { "type": "string", diff --git a/cli/test/lib/tasks/download_spec.js b/cli/test/lib/tasks/download_spec.js index 46bb20e65ec7..c8231f708744 100644 --- a/cli/test/lib/tasks/download_spec.js +++ b/cli/test/lib/tasks/download_spec.js @@ -45,28 +45,33 @@ describe('lib/tasks/download', function () { context('download url', () => { it('returns url', () => { const url = download.getUrl() + la(is.url(url), url) }) it('returns latest desktop url', () => { const url = download.getUrl() + snapshot('latest desktop url', normalize(url)) }) it('returns specific desktop version url', () => { const url = download.getUrl('0.20.2') + snapshot('specific version desktop url', normalize(url)) }) it('returns input if it is already an https link', () => { const url = 'https://somewhere.com' const result = download.getUrl(url) + expect(result).to.equal(url) }) it('returns input if it is already an http link', () => { const url = 'http://local.com' const result = download.getUrl(url) + expect(result).to.equal(url) }) }) @@ -75,24 +80,28 @@ describe('lib/tasks/download', function () { it('env var', () => { process.env.CYPRESS_DOWNLOAD_MIRROR = 'https://cypress.example.com' const url = download.getUrl('0.20.2') + snapshot('base url from CYPRESS_DOWNLOAD_MIRROR', normalize(url)) }) it('env var with trailing slash', () => { process.env.CYPRESS_DOWNLOAD_MIRROR = 'https://cypress.example.com/' const url = download.getUrl('0.20.2') + snapshot('base url from CYPRESS_DOWNLOAD_MIRROR with trailing slash', normalize(url)) }) it('env var with subdirectory', () => { process.env.CYPRESS_DOWNLOAD_MIRROR = 'https://cypress.example.com/example' const url = download.getUrl('0.20.2') + snapshot('base url from CYPRESS_DOWNLOAD_MIRROR with subdirectory', normalize(url)) }) it('env var with subdirectory and trailing slash', () => { process.env.CYPRESS_DOWNLOAD_MIRROR = 'https://cypress.example.com/example/' const url = download.getUrl('0.20.2') + snapshot('base url from CYPRESS_DOWNLOAD_MIRROR with subdirectory and trailing slash', normalize(url)) }) }) @@ -100,7 +109,9 @@ describe('lib/tasks/download', function () { it('saves example.zip to options.downloadDestination', function () { nock('https://aws.amazon.com') .get('/some.zip') - .reply(200, () => fs.createReadStream('test/fixture/example.zip')) + .reply(200, () => { + return fs.createReadStream('test/fixture/example.zip') + }) nock('https://download.cypress.io') .get('/desktop/1.2.3') @@ -110,7 +121,6 @@ describe('lib/tasks/download', function () { 'x-version': '0.11.1', }) - const onProgress = sinon.stub().returns(undefined) return download.start({ @@ -120,6 +130,7 @@ describe('lib/tasks/download', function () { }) .then((responseVersion) => { expect(responseVersion).to.eq('0.11.1') + return fs.statAsync(downloadDestination) }) }) @@ -127,7 +138,9 @@ describe('lib/tasks/download', function () { it('resolves with response x-version if present', function () { nock('https://aws.amazon.com') .get('/some.zip') - .reply(200, () => fs.createReadStream('test/fixture/example.zip')) + .reply(200, () => { + return fs.createReadStream('test/fixture/example.zip') + }) nock('https://download.cypress.io') .get('/desktop/1.2.3') @@ -147,7 +160,9 @@ describe('lib/tasks/download', function () { nock('https://aws.amazon.com') .get('/some.zip') - .reply(200, () => fs.createReadStream('test/fixture/example.zip')) + .reply(200, () => { + return fs.createReadStream('test/fixture/example.zip') + }) nock('https://download.cypress.io') .get('/desktop/0.13.0') @@ -159,6 +174,7 @@ describe('lib/tasks/download', function () { return download.start(this.options).then((responseVersion) => { expect(responseVersion).to.eq('0.13.0') + return fs.statAsync(downloadDestination) }) }) @@ -167,6 +183,7 @@ describe('lib/tasks/download', function () { const ctx = this const err = new Error() + err.statusCode = 404 err.statusMessage = 'Not Found' this.options.version = null diff --git a/packages/desktop-gui/cypress.json b/packages/desktop-gui/cypress.json index 4822cf18ffd1..250ec141ee81 100644 --- a/packages/desktop-gui/cypress.json +++ b/packages/desktop-gui/cypress.json @@ -1,6 +1,6 @@ { "projectId": "ypt4pf", - "pluginsFile": false, + "backgroundFile": false, "viewportWidth": 800, "viewportHeight": 550 } diff --git a/packages/desktop-gui/cypress/fixtures/config.json b/packages/desktop-gui/cypress/fixtures/config.json index 094ab3703432..2635c4438595 100644 --- a/packages/desktop-gui/cypress/fixtures/config.json +++ b/packages/desktop-gui/cypress/fixtures/config.json @@ -153,7 +153,7 @@ ] }, { - "name": "plugins", + "name": "background", "children": [ { "name": "index.js" diff --git a/packages/desktop-gui/cypress/integration/specs_list_spec.coffee b/packages/desktop-gui/cypress/integration/specs_list_spec.coffee index f84fc4abd963..450fa6d7e2f3 100644 --- a/packages/desktop-gui/cypress/integration/specs_list_spec.coffee +++ b/packages/desktop-gui/cypress/integration/specs_list_spec.coffee @@ -63,7 +63,7 @@ describe "Specs List", -> cy.contains("commands.js") cy.contains("defaults.js") cy.contains("index.js") - cy.contains("span", "plugins").siblings("ul").within -> + cy.contains("span", "background").siblings("ul").within -> cy.contains("index.js") it "lists folders and files alphabetically", -> diff --git a/packages/desktop-gui/src/settings/configuration.jsx b/packages/desktop-gui/src/settings/configuration.jsx index 16a2479560b7..d9922ce54268 100644 --- a/packages/desktop-gui/src/settings/configuration.jsx +++ b/packages/desktop-gui/src/settings/configuration.jsx @@ -145,8 +145,8 @@ const Configuration = observer(({ project }) => ( set from CLI arguments - plugin - set from plugin file + background + set from background file diff --git a/packages/desktop-gui/src/settings/settings.scss b/packages/desktop-gui/src/settings/settings.scss index d350ddcf6b98..3f87ed8d3003 100644 --- a/packages/desktop-gui/src/settings/settings.scss +++ b/packages/desktop-gui/src/settings/settings.scss @@ -53,7 +53,7 @@ padding: 10px; font-family: $font-mono; - .envFile:hover, .env:hover, .config:hover, .cli:hover, .plugin:hover, .default:hover { + .envFile:hover, .env:hover, .config:hover, .cli:hover, .background:hover, .default:hover { border-bottom: 1px dotted #777; } @@ -83,7 +83,7 @@ } } - .envFile, .env, .config, .cli, .plugin, .default { + .envFile, .env, .config, .cli, .background, .default { font-family: $font-mono; padding: 2px; @@ -109,7 +109,7 @@ color: #A21313; } - .plugin { + .background { background-color: #f0e7fc; color: #134aa2; } diff --git a/packages/driver/test/cypress/plugins/index.js b/packages/driver/test/cypress/background/index.js similarity index 85% rename from packages/driver/test/cypress/plugins/index.js rename to packages/driver/test/cypress/background/index.js index f053bb92b8e0..39e528dcbf5a 100644 --- a/packages/driver/test/cypress/plugins/index.js +++ b/packages/driver/test/cypress/background/index.js @@ -14,10 +14,13 @@ module.exports = (on) => { 'create:long:file' () { const filePath = path.join(__dirname, '..', '_test-output', 'longtext.txt') const longText = _.times(2000).map(() => { - return _.times(20).map(() => Math.random()).join(' ') + return _.times(20).map(() => { + return Math.random() + }).join(' ') }).join('\n\n') fs.outputFileSync(filePath, longText) + return null }, }) diff --git a/packages/driver/test/cypress/integration/commands/task_spec.coffee b/packages/driver/test/cypress/integration/commands/task_spec.coffee index b69c9a1748ac..119ff1638a63 100644 --- a/packages/driver/test/cypress/integration/commands/task_spec.coffee +++ b/packages/driver/test/cypress/integration/commands/task_spec.coffee @@ -153,7 +153,7 @@ describe "src/cy/commands/task", -> cy.task("foo") - it "throws when task is not registered by plugin", (done) -> + it "throws when task is not registered", (done) -> cy.on "fail", (err) => lastLog = @lastLog @@ -161,7 +161,7 @@ describe "src/cy/commands/task", -> expect(lastLog.get("error")).to.eq(err) expect(lastLog.get("state")).to.eq("failed") - expect(err.message).to.eq("cy.task('bar') failed with the following error:\n\nThe task 'bar' was not handled in the plugins file. The following tasks are registered: return:arg, wait, create:long:file\n\nFix this in your plugins file here:\n#{Cypress.config('pluginsFile')}\n\nhttps://on.cypress.io/api/task") + expect(err.message).to.eq("cy.task('bar') failed with the following error:\n\nThe task 'bar' was not handled in the background file. The following tasks are registered: return:arg, wait, create:long:file\n\nFix this in your background file here:\n#{Cypress.config('backgroundFile')}\n\nhttps://on.cypress.io/api/task") done() cy.task("bar") diff --git a/packages/example/cypress/plugins/index.js b/packages/example/cypress/background/index.js similarity index 71% rename from packages/example/cypress/plugins/index.js rename to packages/example/cypress/background/index.js index 401ea221e531..2a6b2bb52ac1 100644 --- a/packages/example/cypress/plugins/index.js +++ b/packages/example/cypress/background/index.js @@ -1,11 +1,12 @@ // *********************************************************** -// This example plugins/index.js can be used to load plugins -// +// This example background/index.js can be used to load plugins +// in the background process + // You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. +// the background file with the 'backgroundFile' configuration option. // // You can read more here: -// https://on.cypress.io/plugins-guide +// https://on.cypress.io/background-guide // *********************************************************** // This function is called when a project is opened or re-opened (e.g. due to diff --git a/packages/runner/lib/test-setup.js b/packages/runner/lib/test-setup.js index 59ef3e286feb..8d1a1b4359b2 100644 --- a/packages/runner/lib/test-setup.js +++ b/packages/runner/lib/test-setup.js @@ -22,7 +22,9 @@ Object.keys(document.defaultView).forEach((property) => { global.navigator = { userAgent: 'node.js', } -global.requestAnimationFrame = (fn) => fn() +global.requestAnimationFrame = (fn) => { + return fn() +} global.cancelAnimationFrame = () => {} // enzyme, and therefore chai-enzyme, needs to be required after @@ -48,4 +50,6 @@ class Runner { global.Mocha = { Runnable, Runner } $Cypress.create = () => {} -io.connect = () => { return { emit: () => {}, on: () => {} } } +io.connect = () => { + return { emit: () => {}, on: () => {} } +} diff --git a/packages/server/__snapshots__/2_controllers_spec.coffee.js b/packages/server/__snapshots__/2_controllers_spec.coffee.js index 2fa9234c53b6..3be054c27eff 100644 --- a/packages/server/__snapshots__/2_controllers_spec.coffee.js +++ b/packages/server/__snapshots__/2_controllers_spec.coffee.js @@ -1,4 +1,4 @@ -exports['e2e plugins fails when spec does not exist 1'] = ` +exports['e2e controllers fails when spec does not exist 1'] = ` ==================================================================================================== diff --git a/packages/server/__snapshots__/3_plugins_spec.coffee.js b/packages/server/__snapshots__/3_background_events_spec.coffee.js similarity index 91% rename from packages/server/__snapshots__/3_plugins_spec.coffee.js rename to packages/server/__snapshots__/3_background_events_spec.coffee.js index 3d1401eec3b7..eaaf85db7615 100644 --- a/packages/server/__snapshots__/3_plugins_spec.coffee.js +++ b/packages/server/__snapshots__/3_background_events_spec.coffee.js @@ -1,4 +1,4 @@ -exports['e2e plugins fails 1'] = ` +exports['e2e background events fails 1'] = ` ==================================================================================================== @@ -16,9 +16,9 @@ exports['e2e plugins fails 1'] = ` Running: app_spec.coffee... (1 of 1) -Error: The following error was thrown by a plugin. We've stopped running your tests because a plugin crashed. +Error: The following error was thrown by a plugin in the background process. We've stopped running your tests because the background process crashed. -Error: Async error from plugins file +Error: Async error from background file at stack trace line at stack trace line at stack trace line @@ -53,7 +53,7 @@ Error: Async error from plugins file (Video) - Started processing: Compressing to 32 CRF - - Finished processing: /foo/bar/.projects/plugins-async-error/cypress/videos/abc123.mp4 (X seconds) + - Finished processing: /foo/bar/.projects/background-async-error/cypress/videos/abc123.mp4 (X seconds) ==================================================================================================== @@ -70,7 +70,7 @@ Error: Async error from plugins file ` -exports['e2e plugins passes 1'] = ` +exports['e2e background events passes 1'] = ` ==================================================================================================== @@ -130,7 +130,7 @@ exports['e2e plugins passes 1'] = ` ` -exports['e2e plugins can modify config from plugins 1'] = ` +exports['e2e background events can modify config from background 1'] = ` ==================================================================================================== @@ -173,7 +173,7 @@ exports['e2e plugins can modify config from plugins 1'] = ` (Video) - Started processing: Compressing to 20 CRF - - Finished processing: /foo/bar/.projects/plugin-config/cypress/videos/abc123.mp4 (X seconds) + - Finished processing: /foo/bar/.projects/background-config/cypress/videos/abc123.mp4 (X seconds) ==================================================================================================== @@ -190,7 +190,7 @@ exports['e2e plugins can modify config from plugins 1'] = ` ` -exports['e2e plugins works with user extensions 1'] = ` +exports['e2e background events works with user extensions 1'] = ` ==================================================================================================== @@ -249,7 +249,7 @@ A video will not be recorded when using this browser. ` -exports['e2e plugins handles absolute path to pluginsFile 1'] = ` +exports['e2e background events handles absolute path to backgroundFile 1'] = ` ==================================================================================================== @@ -268,7 +268,7 @@ exports['e2e plugins handles absolute path to pluginsFile 1'] = ` Running: absolute_spec.coffee... (1 of 1) - ✓ uses the plugins file + ✓ uses the background file 1 passing @@ -291,7 +291,7 @@ exports['e2e plugins handles absolute path to pluginsFile 1'] = ` (Video) - Started processing: Compressing to 32 CRF - - Finished processing: /foo/bar/.projects/plugins-absolute-path/cypress/videos/abc123.mp4 (X seconds) + - Finished processing: /foo/bar/.projects/background-absolute-path/cypress/videos/abc123.mp4 (X seconds) ==================================================================================================== @@ -308,7 +308,7 @@ exports['e2e plugins handles absolute path to pluginsFile 1'] = ` ` -exports['e2e plugins calls after:screenshot for cy.screenshot() and failure screenshots 1'] = ` +exports['e2e background events calls after:screenshot for cy.screenshot() and failure screenshots 1'] = ` ==================================================================================================== @@ -359,16 +359,16 @@ exports['e2e plugins calls after:screenshot for cy.screenshot() and failure scre (Screenshots) - - /foo/bar/.projects/plugin-after-screenshot/screenshot-replacement.png (2x2) - - /foo/bar/.projects/plugin-after-screenshot/cypress/screenshots/after_screenshot_spec.coffee/ignored-values.png (1280x720) - - /foo/bar/.projects/plugin-after-screenshot/cypress/screenshots/after_screenshot_spec.coffee/invalid-return.png (1280x720) - - /foo/bar/.projects/plugin-after-screenshot/screenshot-replacement.png (1x1) + - /foo/bar/.projects/background-after-screenshot/screenshot-replacement.png (2x2) + - /foo/bar/.projects/background-after-screenshot/cypress/screenshots/after_screenshot_spec.coffee/ignored-values.png (1280x720) + - /foo/bar/.projects/background-after-screenshot/cypress/screenshots/after_screenshot_spec.coffee/invalid-return.png (1280x720) + - /foo/bar/.projects/background-after-screenshot/screenshot-replacement.png (1x1) (Video) - Started processing: Compressing to 32 CRF - - Finished processing: /foo/bar/.projects/plugin-after-screenshot/cypress/videos/abc123.mp4 (X seconds) + - Finished processing: /foo/bar/.projects/background-after-screenshot/cypress/videos/abc123.mp4 (X seconds) ==================================================================================================== @@ -384,3 +384,20 @@ exports['e2e plugins calls after:screenshot for cy.screenshot() and failure scre ` + +exports['e2e background events errors when pluginsFile is used in config 1'] = ` +A configuration option you have supplied has been renamed. + +Please rename pluginsFile to backgroundFile + +` + +exports['e2e background events errors when backgroundFile path is default and plugins/index.js exists 1'] = ` +The "plugins file" has been renamed to the "background file" and has a new default path. + +Please rename + cypress/plugins/index.js +to + cypress/background/index.js + +` diff --git a/packages/server/__snapshots__/5_task_not_registered_spec.coffee.js b/packages/server/__snapshots__/5_task_not_registered_spec.coffee.js index b68763ebe728..3c21851db72a 100644 --- a/packages/server/__snapshots__/5_task_not_registered_spec.coffee.js +++ b/packages/server/__snapshots__/5_task_not_registered_spec.coffee.js @@ -17,18 +17,18 @@ exports['e2e task fails 1'] = ` Running: task_not_registered_spec.coffee... (1 of 1) - 1) fails because the 'task' event is not registered in plugins file + 1) fails because the 'task' event is not registered in background file 0 passing 1 failing - 1) fails because the 'task' event is not registered in plugins file: + 1) fails because the 'task' event is not registered in background file: CypressError: cy.task('some:task') failed with the following error: -The 'task' event has not been registered in the plugins file. You must register it before using cy.task() +The 'task' event has not been registered in the background file. You must register it before using cy.task() -Fix this in your plugins file here: -/foo/bar/.projects/task-not-registered/cypress/plugins/index.js +Fix this in your background file here: +/foo/bar/.projects/task-not-registered/cypress/background/index.js https://on.cypress.io/api/task at stack trace line @@ -65,7 +65,7 @@ https://on.cypress.io/api/task (Screenshots) - - /foo/bar/.projects/task-not-registered/cypress/screenshots/task_not_registered_spec.coffee/fails because the task event is not registered in plugins file (failed).png (1280x720) + - /foo/bar/.projects/task-not-registered/cypress/screenshots/task_not_registered_spec.coffee/fails because the task event is not registered in background file (failed).png (1280x720) (Video) diff --git a/packages/server/__snapshots__/6_task_spec.coffee.js b/packages/server/__snapshots__/6_task_spec.coffee.js index 87373537a423..394c5a191de0 100644 --- a/packages/server/__snapshots__/6_task_spec.coffee.js +++ b/packages/server/__snapshots__/6_task_spec.coffee.js @@ -92,8 +92,8 @@ The task handler was: returns:undefined() {} -Fix this in your plugins file here: -/foo/bar/.projects/e2e/cypress/plugins/index.js +Fix this in your background file here: +/foo/bar/.projects/e2e/cypress/background/index.js https://on.cypress.io/api/task at stack trace line diff --git a/packages/server/__snapshots__/run_plugins_spec.coffee.js b/packages/server/__snapshots__/run_background_spec.coffee.js similarity index 73% rename from packages/server/__snapshots__/run_plugins_spec.coffee.js rename to packages/server/__snapshots__/run_background_spec.coffee.js index 091c350559b2..6825108489b6 100644 --- a/packages/server/__snapshots__/run_plugins_spec.coffee.js +++ b/packages/server/__snapshots__/run_background_spec.coffee.js @@ -1,12 +1,12 @@ -exports['lib/plugins/child/run_plugins sends error message if pluginsFile is missing 1'] = ` +exports['lib/background/child/run_background sends error message if backgroundFile is missing 1'] = ` Error: Cannot find module '/does/not/exist.coffee' at Function.Module._resolveFilename module.js at Module._load module.js at Function.hookedLoader [as _load] mockery.js at Module.require module.js at require module.js - at module.exports run_plugins.js - at Context. run_plugins_spec.coffee + at module.exports run_background.js + at Context. run_background_spec.coffee at callFn runnable.js at Test.Runnable.run runnable.js at Runner.runTest runner.js @@ -26,8 +26,8 @@ Error: Cannot find module '/does/not/exist.coffee' ` -exports['lib/plugins/child/run_plugins sends error message if requiring pluginsFile errors 1'] = ` -Error: error thrown by pluginsFile +exports['lib/background/child/run_background sends error message if requiring backgroundFile errors 1'] = ` +Error: error thrown by backgroundFile at Object. throws_error.coffee at Object. throws_error.coffee at Module._compile module.js @@ -38,8 +38,8 @@ Error: error thrown by pluginsFile at Function.hookedLoader [as _load] mockery.js at Module.require module.js at require module.js - at module.exports run_plugins.js - at Context. run_plugins_spec.coffee + at module.exports run_background.js + at Context. run_background_spec.coffee at callFn runnable.js at Test.Runnable.run runnable.js at Runner.runTest runner.js @@ -59,12 +59,12 @@ Error: error thrown by pluginsFile ` -exports['lib/plugins/child/run_plugins sends error message if pluginsFile has syntax error 1'] = ` +exports['lib/background/child/run_background sends error message if backgroundFile has syntax error 1'] = ` syntax_error.coffee) error: missing } { ^ ` -exports['lib/plugins/child/run_plugins sends error message if pluginsFile does not export a function 1'] = ` +exports['lib/background/child/run_background sends error message if backgroundFile does not export a function 1'] = ` null ` diff --git a/packages/server/__snapshots__/scaffold_spec.coffee.js b/packages/server/__snapshots__/scaffold_spec.coffee.js index 07b5c3e7a849..6e0b097e58a8 100644 --- a/packages/server/__snapshots__/scaffold_spec.coffee.js +++ b/packages/server/__snapshots__/scaffold_spec.coffee.js @@ -1,288 +1,288 @@ exports['lib/scaffold .fileTree returns tree-like structure of scaffolded 1'] = [ { - "name": "tests", - "children": [ + 'name': 'tests', + 'children': [ { - "name": "examples", - "children": [ + 'name': 'examples', + 'children': [ { - "name": "actions.spec.js" + 'name': 'actions.spec.js', }, { - "name": "aliasing.spec.js" + 'name': 'aliasing.spec.js', }, { - "name": "assertions.spec.js" + 'name': 'assertions.spec.js', }, { - "name": "connectors.spec.js" + 'name': 'connectors.spec.js', }, { - "name": "cookies.spec.js" + 'name': 'cookies.spec.js', }, { - "name": "cypress_api.spec.js" + 'name': 'cypress_api.spec.js', }, { - "name": "files.spec.js" + 'name': 'files.spec.js', }, { - "name": "local_storage.spec.js" + 'name': 'local_storage.spec.js', }, { - "name": "location.spec.js" + 'name': 'location.spec.js', }, { - "name": "misc.spec.js" + 'name': 'misc.spec.js', }, { - "name": "navigation.spec.js" + 'name': 'navigation.spec.js', }, { - "name": "network_requests.spec.js" + 'name': 'network_requests.spec.js', }, { - "name": "querying.spec.js" + 'name': 'querying.spec.js', }, { - "name": "spies_stubs_clocks.spec.js" + 'name': 'spies_stubs_clocks.spec.js', }, { - "name": "traversal.spec.js" + 'name': 'traversal.spec.js', }, { - "name": "utilities.spec.js" + 'name': 'utilities.spec.js', }, { - "name": "viewport.spec.js" + 'name': 'viewport.spec.js', }, { - "name": "waiting.spec.js" + 'name': 'waiting.spec.js', }, { - "name": "window.spec.js" - } - ] + 'name': 'window.spec.js', + }, + ], }, { - "name": "_fixtures", - "children": [ + 'name': '_fixtures', + 'children': [ { - "name": "example.json" - } - ] + 'name': 'example.json', + }, + ], }, { - "name": "_support", - "children": [ + 'name': '_support', + 'children': [ { - "name": "commands.js" + 'name': 'commands.js', }, { - "name": "index.js" - } - ] - } - ] + 'name': 'index.js', + }, + ], + }, + ], }, { - "name": "cypress", - "children": [ + 'name': 'cypress', + 'children': [ { - "name": "plugins", - "children": [ - { - "name": "index.js" - } - ] - } - ] - } + 'name': 'background', + 'children': [ + { + 'name': 'index.js', + }, + ], + }, + ], + }, ] exports['lib/scaffold .fileTree leaves out fixtures if configured to false 1'] = [ { - "name": "tests", - "children": [ + 'name': 'tests', + 'children': [ { - "name": "examples", - "children": [ + 'name': 'examples', + 'children': [ { - "name": "actions.spec.js" + 'name': 'actions.spec.js', }, { - "name": "aliasing.spec.js" + 'name': 'aliasing.spec.js', }, { - "name": "assertions.spec.js" + 'name': 'assertions.spec.js', }, { - "name": "connectors.spec.js" + 'name': 'connectors.spec.js', }, { - "name": "cookies.spec.js" + 'name': 'cookies.spec.js', }, { - "name": "cypress_api.spec.js" + 'name': 'cypress_api.spec.js', }, { - "name": "files.spec.js" + 'name': 'files.spec.js', }, { - "name": "local_storage.spec.js" + 'name': 'local_storage.spec.js', }, { - "name": "location.spec.js" + 'name': 'location.spec.js', }, { - "name": "misc.spec.js" + 'name': 'misc.spec.js', }, { - "name": "navigation.spec.js" + 'name': 'navigation.spec.js', }, { - "name": "network_requests.spec.js" + 'name': 'network_requests.spec.js', }, { - "name": "querying.spec.js" + 'name': 'querying.spec.js', }, { - "name": "spies_stubs_clocks.spec.js" + 'name': 'spies_stubs_clocks.spec.js', }, { - "name": "traversal.spec.js" + 'name': 'traversal.spec.js', }, { - "name": "utilities.spec.js" + 'name': 'utilities.spec.js', }, { - "name": "viewport.spec.js" + 'name': 'viewport.spec.js', }, { - "name": "waiting.spec.js" + 'name': 'waiting.spec.js', }, { - "name": "window.spec.js" - } - ] + 'name': 'window.spec.js', + }, + ], }, { - "name": "_support", - "children": [ + 'name': '_support', + 'children': [ { - "name": "commands.js" + 'name': 'commands.js', }, { - "name": "index.js" - } - ] - } - ] + 'name': 'index.js', + }, + ], + }, + ], }, { - "name": "cypress", - "children": [ + 'name': 'cypress', + 'children': [ { - "name": "plugins", - "children": [ - { - "name": "index.js" - } - ] - } - ] - } + 'name': 'background', + 'children': [ + { + 'name': 'index.js', + }, + ], + }, + ], + }, ] exports['lib/scaffold .fileTree leaves out support if configured to false 1'] = [ { - "name": "tests", - "children": [ + 'name': 'tests', + 'children': [ { - "name": "examples", - "children": [ + 'name': 'examples', + 'children': [ { - "name": "actions.spec.js" + 'name': 'actions.spec.js', }, { - "name": "aliasing.spec.js" + 'name': 'aliasing.spec.js', }, { - "name": "assertions.spec.js" + 'name': 'assertions.spec.js', }, { - "name": "connectors.spec.js" + 'name': 'connectors.spec.js', }, { - "name": "cookies.spec.js" + 'name': 'cookies.spec.js', }, { - "name": "cypress_api.spec.js" + 'name': 'cypress_api.spec.js', }, { - "name": "files.spec.js" + 'name': 'files.spec.js', }, { - "name": "local_storage.spec.js" + 'name': 'local_storage.spec.js', }, { - "name": "location.spec.js" + 'name': 'location.spec.js', }, { - "name": "misc.spec.js" + 'name': 'misc.spec.js', }, { - "name": "navigation.spec.js" + 'name': 'navigation.spec.js', }, { - "name": "network_requests.spec.js" + 'name': 'network_requests.spec.js', }, { - "name": "querying.spec.js" + 'name': 'querying.spec.js', }, { - "name": "spies_stubs_clocks.spec.js" + 'name': 'spies_stubs_clocks.spec.js', }, { - "name": "traversal.spec.js" + 'name': 'traversal.spec.js', }, { - "name": "utilities.spec.js" + 'name': 'utilities.spec.js', }, { - "name": "viewport.spec.js" + 'name': 'viewport.spec.js', }, { - "name": "waiting.spec.js" + 'name': 'waiting.spec.js', }, { - "name": "window.spec.js" - } - ] + 'name': 'window.spec.js', + }, + ], }, { - "name": "_fixtures", - "children": [ - { - "name": "example.json" - } - ] - } - ] + 'name': '_fixtures', + 'children': [ + { + 'name': 'example.json', + }, + ], + }, + ], }, { - "name": "cypress", - "children": [ + 'name': 'cypress', + 'children': [ { - "name": "plugins", - "children": [ - { - "name": "index.js" - } - ] - } - ] - } + 'name': 'background', + 'children': [ + { + 'name': 'index.js', + }, + ], + }, + ], + }, ] exports['lib/scaffold .support creates supportFolder and commands.js and index.js when supportFolder does not exist 1'] = ` @@ -338,112 +338,113 @@ import './commands' ` -exports['lib/scaffold .fileTree leaves out plugins if configured to false 1'] = [ +exports['lib/scaffold .background creates backgroundFile when backgroundFolder does not exist 1'] = ` +// *********************************************************** +// This example background/index.js can be used to load plugins +// in the background process +// +// You can change the location of this file or turn off loading +// the background file with the 'backgroundFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/background-process +// *********************************************************** + +// This function is called when a project is opened or re-opened (e.g. due to +// the project's config changing) + +module.exports = (on, config) => { + // on is used to hook into various events Cypress emits + // config is the resolved Cypress config +} + +` + +exports['lib/scaffold .fileTree leaves out background if configured to false 1'] = [ { - "name": "tests", - "children": [ + 'name': 'tests', + 'children': [ { - "name": "examples", - "children": [ + 'name': 'examples', + 'children': [ { - "name": "actions.spec.js" + 'name': 'actions.spec.js', }, { - "name": "aliasing.spec.js" + 'name': 'aliasing.spec.js', }, { - "name": "assertions.spec.js" + 'name': 'assertions.spec.js', }, { - "name": "connectors.spec.js" + 'name': 'connectors.spec.js', }, { - "name": "cookies.spec.js" + 'name': 'cookies.spec.js', }, { - "name": "cypress_api.spec.js" + 'name': 'cypress_api.spec.js', }, { - "name": "files.spec.js" + 'name': 'files.spec.js', }, { - "name": "local_storage.spec.js" + 'name': 'local_storage.spec.js', }, { - "name": "location.spec.js" + 'name': 'location.spec.js', }, { - "name": "misc.spec.js" + 'name': 'misc.spec.js', }, { - "name": "navigation.spec.js" + 'name': 'navigation.spec.js', }, { - "name": "network_requests.spec.js" + 'name': 'network_requests.spec.js', }, { - "name": "querying.spec.js" + 'name': 'querying.spec.js', }, { - "name": "spies_stubs_clocks.spec.js" + 'name': 'spies_stubs_clocks.spec.js', }, { - "name": "traversal.spec.js" + 'name': 'traversal.spec.js', }, { - "name": "utilities.spec.js" + 'name': 'utilities.spec.js', }, { - "name": "viewport.spec.js" + 'name': 'viewport.spec.js', }, { - "name": "waiting.spec.js" + 'name': 'waiting.spec.js', }, { - "name": "window.spec.js" - } - ] + 'name': 'window.spec.js', + }, + ], }, { - "name": "_fixtures", - "children": [ + 'name': '_fixtures', + 'children': [ { - "name": "example.json" - } - ] + 'name': 'example.json', + }, + ], }, { - "name": "_support", - "children": [ + 'name': '_support', + 'children': [ { - "name": "commands.js" + 'name': 'commands.js', }, { - "name": "index.js" - } - ] - } - ] - } + 'name': 'index.js', + }, + ], + }, + ], + }, ] - -exports['lib/scaffold .plugins creates pluginsFile when pluginsFolder does not exist 1'] = ` -// *********************************************************** -// This example plugins/index.js can be used to load plugins -// -// You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/plugins-guide -// *********************************************************** - -// This function is called when a project is opened or re-opened (e.g. due to -// the project's config changing) - -module.exports = (on, config) => { - // on is used to hook into various events Cypress emits - // config is the resolved Cypress config -} - -` diff --git a/packages/server/lib/plugins/child/index.js b/packages/server/lib/background/child/index.js similarity index 76% rename from packages/server/lib/plugins/child/index.js rename to packages/server/lib/background/child/index.js index 6de9649b0b4d..d4e5406a43c2 100644 --- a/packages/server/lib/plugins/child/index.js +++ b/packages/server/lib/background/child/index.js @@ -9,6 +9,6 @@ require && require.extensions && delete require.extensions['.litcoffee'] require && require.extensions && delete require.extensions['.coffee.md'] const ipc = require('../util').wrapIpc(process) -const pluginsFile = require('minimist')(process.argv.slice(2)).file +const backgroundFile = require('minimist')(process.argv.slice(2)).file -require('./run_plugins')(ipc, pluginsFile) +require('./run_background')(process, ipc, backgroundFile) diff --git a/packages/server/lib/plugins/child/preprocessor.js b/packages/server/lib/background/child/preprocessor.js similarity index 100% rename from packages/server/lib/plugins/child/preprocessor.js rename to packages/server/lib/background/child/preprocessor.js diff --git a/packages/server/lib/plugins/child/run_plugins.js b/packages/server/lib/background/child/run_background.js similarity index 77% rename from packages/server/lib/plugins/child/run_plugins.js rename to packages/server/lib/background/child/run_background.js index 3da1fa9a0200..f30488387e9f 100644 --- a/packages/server/lib/plugins/child/run_plugins.js +++ b/packages/server/lib/background/child/run_background.js @@ -1,5 +1,5 @@ const _ = require('lodash') -const debug = require('debug')('cypress:server:plugins:child') +const debug = require('debug')('cypress:server:background:child') const Promise = require('bluebird') const preprocessor = require('./preprocessor') const task = require('./task') @@ -9,8 +9,10 @@ const registeredEvents = {} const invoke = (eventId, args = []) => { const event = registeredEvents[eventId] + if (!event) { sendError(new Error(`No handler registered for event id ${eventId}`)) + return } @@ -21,10 +23,10 @@ const sendError = (ipc, err) => { ipc.send('error', util.serializeError(err)) } -let plugins +let background -const load = (ipc, config, pluginsFile) => { - debug('run plugins function') +const load = (ipc, config, backgroundFile) => { + debug('run background function') let eventIdCount = 0 const registrations = [] @@ -34,15 +36,18 @@ const load = (ipc, config, pluginsFile) => { const register = (event, handler) => { if (event === 'task') { const existingEventId = _.findKey(registeredEvents, { event: 'task' }) + if (existingEventId) { handler = task.merge(registeredEvents[existingEventId].handler, handler) registeredEvents[existingEventId] = { event, handler } debug('extend task events with id', existingEventId) + return } } const eventId = eventIdCount++ + registeredEvents[eventId] = { event, handler } debug('register event', event, 'with id', eventId) @@ -59,77 +64,89 @@ const load = (ipc, config, pluginsFile) => { Promise .try(() => { - return plugins(register, config) + return background(register, config) }) .then((modifiedCfg) => { ipc.send('loaded', modifiedCfg, registrations) }) .catch((err) => { - ipc.send('load:error', 'PLUGINS_FUNCTION_ERROR', pluginsFile, err.stack) + ipc.send('load:error', 'BACKGROUND_FUNCTION_ERROR', backgroundFile, err.stack) }) } const execute = (ipc, event, ids, args = []) => { - debug(`execute plugin event: ${event} (%o)`, ids) + debug(`execute background event: ${event} (%o)`, ids) switch (event) { case 'after:screenshot': util.wrapChildPromise(ipc, invoke, ids, args) + return case 'file:preprocessor': preprocessor.wrap(ipc, invoke, ids, args) + return case 'before:browser:launch': util.wrapChildPromise(ipc, invoke, ids, args) + return case 'task': task.wrap(ipc, registeredEvents, ids, args) + return case '_get:task:keys': task.getKeys(ipc, registeredEvents, ids) + return case '_get:task:body': task.getBody(ipc, registeredEvents, ids, args) + return default: debug('unexpected execute message:', event, args) + return } } -module.exports = (ipc, pluginsFile) => { - debug('pluginsFile:', pluginsFile) +module.exports = (process, ipc, backgroundFile) => { + debug('backgroundFile:', backgroundFile) process.on('uncaughtException', (err) => { debug('uncaught exception:', util.serializeError(err)) ipc.send('error', util.serializeError(err)) + return false }) process.on('unhandledRejection', (event) => { const err = (event && event.reason) || event + debug('unhandled rejection:', util.serializeError(err)) ipc.send('error', util.serializeError(err)) + return false }) try { - debug('require pluginsFile') - plugins = require(pluginsFile) + debug('require backgroundFile') + background = require(backgroundFile) } catch (err) { - debug('failed to require pluginsFile:\n%s', err.stack) - ipc.send('load:error', 'PLUGINS_FILE_ERROR', pluginsFile, err.stack) + debug('failed to require backgroundFile:\n%s', err.stack) + ipc.send('load:error', 'BACKGROUND_FILE_ERROR', backgroundFile, err.stack) + return } - if (typeof plugins !== 'function') { + if (typeof background !== 'function') { debug('not a function') - ipc.send('load:error', 'PLUGINS_DIDNT_EXPORT_FUNCTION', pluginsFile, plugins) + ipc.send('load:error', 'BACKGROUND_DIDNT_EXPORT_FUNCTION', backgroundFile, background) + return } ipc.on('load', (config) => { - load(ipc, config, pluginsFile) + load(ipc, config, backgroundFile) }) ipc.on('execute', (event, ids, args) => { diff --git a/packages/server/lib/plugins/child/task.js b/packages/server/lib/background/child/task.js similarity index 92% rename from packages/server/lib/plugins/child/task.js rename to packages/server/lib/background/child/task.js index 04665cf09d3d..835d6411b8b4 100644 --- a/packages/server/lib/plugins/child/task.js +++ b/packages/server/lib/background/child/task.js @@ -6,6 +6,7 @@ const getBody = (ipc, events, ids, [event]) => { const taskEvent = _.find(events, { event: 'task' }).handler const invoke = () => { const fn = taskEvent[event] + return _.isFunction(fn) ? fn.toString() : '' } @@ -14,16 +15,20 @@ const getBody = (ipc, events, ids, [event]) => { const getKeys = (ipc, events, ids) => { const taskEvent = _.find(events, { event: 'task' }).handler - const invoke = () => _.keys(taskEvent) + const invoke = () => { + return _.keys(taskEvent) + } util.wrapChildPromise(ipc, invoke, ids) } const merge = (prevEvents, events) => { const duplicates = _.intersection(_.keys(prevEvents), _.keys(events)) + if (duplicates.length) { errors.warning('DUPLICATE_TASK_KEY', duplicates.join(', ')) } + return _.extend(prevEvents, events) } @@ -33,11 +38,13 @@ const wrap = (ipc, events, ids, args) => { const invoke = (eventId, args = []) => { const handler = _.get(events, `${eventId}.handler.${task}`) + if (_.isFunction(handler)) { return handler(...args) - } else { - return '__cypress_unhandled__' } + + return '__cypress_unhandled__' + } util.wrapChildPromise(ipc, invoke, ids, [arg]) diff --git a/packages/server/lib/plugins/index.coffee b/packages/server/lib/background/index.coffee similarity index 53% rename from packages/server/lib/plugins/index.coffee rename to packages/server/lib/background/index.coffee index 78e77b6a33c1..adda66ecaddf 100644 --- a/packages/server/lib/plugins/index.coffee +++ b/packages/server/lib/background/index.coffee @@ -1,12 +1,12 @@ _ = require("lodash") cp = require("child_process") path = require("path") -debug = require("debug")("cypress:server:plugins") +debug = require("debug")("cypress:server:background") Promise = require("bluebird") errors = require("../errors") util = require("./util") -pluginsProcess = null +backgroundProcess = null registeredEvents = {} handlers = [] @@ -14,10 +14,10 @@ register = (event, callback) -> debug("register event '#{event}'") if not _.isString(event) - throw new Error("The plugin register function must be called with an event as its 1st argument. You passed '#{event}'.") + throw new Error("The background register function must be called with an event as its 1st argument. You passed '#{event}'.") if not _.isFunction(callback) - throw new Error("The plugin register function must be called with a callback function as its 2nd argument. You passed '#{callback}'.") + throw new Error("The background register function must be called with a callback function as its 2nd argument. You passed '#{callback}'.") registeredEvents[event] = callback @@ -26,19 +26,19 @@ module.exports = { handlers.push(handler) init: (config, options) -> - debug("plugins.init", config.pluginsFile) + debug("background.init", config.backgroundFile) new Promise (resolve, reject) -> - return resolve() if not config.pluginsFile + return resolve() if not config.backgroundFile - if pluginsProcess - debug("kill existing plugins process") - pluginsProcess.kill() + if backgroundProcess + debug("kill existing background process") + backgroundProcess.kill() registeredEvents = {} - pluginsProcess = cp.fork(path.join(__dirname, "child", "index.js"), ["--file", config.pluginsFile], { stdio: "inherit" }) - ipc = util.wrapIpc(pluginsProcess) + backgroundProcess = cp.fork(path.join(__dirname, "child", "index.js"), ["--file", config.backgroundFile], { stdio: "inherit" }) + ipc = util.wrapIpc(backgroundProcess) handler(ipc) for handler in handlers @@ -46,7 +46,7 @@ module.exports = { ipc.on "loaded", (newCfg, registrations) -> _.each registrations, (registration) -> - debug("register plugins process event", registration.event, "with id", registration.eventId) + debug("register background process event", registration.event, "with id", registration.eventId) register registration.event, (args...) -> util.wrapParentPromise ipc, registration.eventId, (invocationId) -> @@ -62,29 +62,29 @@ module.exports = { ipc.on "load:error", (type, args...) -> reject(errors.get(type, args...)) - killPluginsProcess = -> - pluginsProcess and pluginsProcess.kill() - pluginsProcess = null + killbackgroundProcess = -> + backgroundProcess and backgroundProcess.kill() + backgroundProcess = null handleError = (err) -> - debug("plugins process error:", err.stack) - killPluginsProcess() - err = errors.get("PLUGINS_ERROR", err.annotated or err.stack or err.message) - err.title = "Error running plugin" + debug("background process error:", err.stack) + killbackgroundProcess() + err = errors.get("BACKGROUND_ERROR", err.annotated or err.stack or err.message) + err.title = "Error running background plugin" options.onError(err) - pluginsProcess.on("error", handleError) + backgroundProcess.on("error", handleError) ipc.on("error", handleError) ## see timers/parent.js line #93 for why this is necessary - process.on("exit", killPluginsProcess) + process.on("exit", killbackgroundProcess) register: register - has: (event) -> + isRegistered: (event) -> isRegistered = !!registeredEvents[event] - debug("plugin event registered? %o", { + debug("background event registered? %o", { event, isRegistered }) @@ -92,7 +92,7 @@ module.exports = { isRegistered execute: (event, args...) -> - debug("execute plugin event '#{event}' with args: %o %o %o", args...) + debug("execute background event '#{event}' with args: %o %o %o", args...) registeredEvents[event](args...) ## for testing purposes diff --git a/packages/server/lib/plugins/preprocessor.coffee b/packages/server/lib/background/preprocessor.coffee similarity index 92% rename from packages/server/lib/plugins/preprocessor.coffee rename to packages/server/lib/background/preprocessor.coffee index 6d07c25a2ae9..55265b22ae32 100644 --- a/packages/server/lib/plugins/preprocessor.coffee +++ b/packages/server/lib/background/preprocessor.coffee @@ -5,7 +5,7 @@ debug = require("debug")("cypress:server:preprocessor") Promise = require("bluebird") appData = require("../util/app_data") cwd = require("../cwd") -plugins = require("../plugins") +background = require("../background") savedState = require("../util/saved_state") errorMessage = (err = {}) -> @@ -46,15 +46,15 @@ setDefaultPreprocessor = -> debug("set default preprocessor") browserify = require("@cypress/browserify-preprocessor") - plugins.register("file:preprocessor", browserify()) + background.register("file:preprocessor", browserify()) -plugins.registerHandler (ipc) -> +background.registerHandler (ipc) -> ipc.on "preprocessor:rerun", (filePath) -> debug("ipc preprocessor:rerun event") baseEmitter.emit("file:updated", filePath) baseEmitter.on "close", (filePath) -> - debug("base emitter plugin close event") + debug("base emitter background close event") ipc.send("preprocessor:close", filePath) module.exports = { @@ -94,7 +94,7 @@ module.exports = { debug("base emitter native close event") fileObject.emit("close")   - if not plugins.has("file:preprocessor") + if not background.isRegistered("file:preprocessor") setDefaultPreprocessor(config) if config.isTextTerminal and fileProcessor = fileProcessors[filePath] @@ -102,7 +102,7 @@ module.exports = { return fileProcessor preprocessor = fileProcessors[filePath] = Promise.try -> - plugins.execute("file:preprocessor", fileObject) + background.execute("file:preprocessor", fileObject) return preprocessor diff --git a/packages/server/lib/plugins/util.coffee b/packages/server/lib/background/util.coffee similarity index 97% rename from packages/server/lib/plugins/util.coffee rename to packages/server/lib/background/util.coffee index f72ecf5d44ca..37df8907588c 100644 --- a/packages/server/lib/plugins/util.coffee +++ b/packages/server/lib/background/util.coffee @@ -1,6 +1,6 @@ _ = require("lodash") EE = require("events") -debug = require("debug")("cypress:server:plugins") +debug = require("debug")("cypress:server:background") Promise = require("bluebird") UNDEFINED_SERIALIZED = "__cypress_undefined__" diff --git a/packages/server/lib/browsers/chrome.coffee b/packages/server/lib/browsers/chrome.coffee index 5e41ce0e1aaa..f7385d35e490 100644 --- a/packages/server/lib/browsers/chrome.coffee +++ b/packages/server/lib/browsers/chrome.coffee @@ -4,7 +4,7 @@ path = require("path") Promise = require("bluebird") extension = require("@packages/extension") debug = require("debug")("cypress:server:browsers") -plugins = require("../plugins") +background = require("../background") fs = require("../util/fs") appData = require("../util/app_data") utils = require("./utils") @@ -65,11 +65,11 @@ defaultArgs = [ "--disable-default-apps" ] -pluginsBeforeBrowserLaunch = (browser, args) -> +backgroundBeforeBrowserLaunch = (browser, args) -> ## bail if we're not registered to this event - return args if not plugins.has("before:browser:launch") + return args if not background.isRegistered("before:browser:launch") - plugins.execute("before:browser:launch", browser, args) + background.execute("before:browser:launch", browser, args) .then (newArgs) -> debug("got user args for 'before:browser:launch'", newArgs) @@ -161,7 +161,7 @@ module.exports = { ## before launching the browser every time utils.ensureCleanCache(browserName, isTextTerminal), - pluginsBeforeBrowserLaunch(options.browser, args) + backgroundBeforeBrowserLaunch(options.browser, args) ]) .spread (cacheDir, args) => Promise.all([ diff --git a/packages/server/lib/browsers/electron.coffee b/packages/server/lib/browsers/electron.coffee index 475453d1f84b..2cda3e6f48e6 100644 --- a/packages/server/lib/browsers/electron.coffee +++ b/packages/server/lib/browsers/electron.coffee @@ -5,7 +5,7 @@ debug = require("debug")("cypress:server:browsers:electron") menu = require("../gui/menu") Windows = require("../gui/windows") appData = require("../util/app_data") -plugins = require("../plugins") +background = require("../background") savedState = require("../saved_state") profileCleaner = require("../util/profile_cleaner") @@ -172,12 +172,12 @@ module.exports = { Promise .try => ## bail if we're not registered to this event - return options if not plugins.has("before:browser:launch") + return options if not background.isRegistered("before:browser:launch") - plugins.execute("before:browser:launch", options.browser, options) + background.execute("before:browser:launch", options.browser, options) .then (newOptions) -> if newOptions - debug("received new options from plugin event %o", newOptions) + debug("received new options from background event %o", newOptions) _.extend(options, newOptions) return options diff --git a/packages/server/lib/config.coffee b/packages/server/lib/config.coffee index e46ef822b41a..3de5d2dc61a8 100644 --- a/packages/server/lib/config.coffee +++ b/packages/server/lib/config.coffee @@ -9,8 +9,9 @@ origin = require("./util/origin") coerce = require("./util/coerce") settings = require("./util/settings") v = require("./util/validation") -debug = require("debug")("cypress:server:config") +debug = require("debug")("cypress:server:config") pathHelpers = require("./util/path_helpers") +util = require("./util/config") ## cypress followed by _ cypressEnvRe = /^(cypress_)/i @@ -25,7 +26,7 @@ isCypressEnvLike = (key) -> cypressEnvRe.test(key) and key isnt "CYPRESS_ENV" folders = toWords """ - fileServerFolder fixturesFolder integrationFolder pluginsFile + fileServerFolder fixturesFolder integrationFolder backgroundFile screenshotsFolder supportFile supportFolder unitFolder videosFolder """ @@ -35,7 +36,7 @@ configKeys = toWords """ baseUrl fixturesFolder chromeWebSecurity modifyObstructiveCode integrationFolder - env pluginsFile + env backgroundFile hosts screenshotsFolder numTestsKeptInMemory supportFile port supportFolder @@ -58,6 +59,7 @@ breakingConfigKeys = toWords """ videoRecording screenshotOnHeadlessFailure trashAssetsBeforeHeadlessRuns + pluginsFile """ defaults = { @@ -104,7 +106,7 @@ defaults = { integrationFolder: "cypress/integration" screenshotsFolder: "cypress/screenshots" namespace: "__cypress" - pluginsFile: "cypress/plugins" + backgroundFile: "cypress/background" ## deprecated javascripts: [] @@ -125,7 +127,7 @@ validationRules = { integrationFolder: v.isString numTestsKeptInMemory: v.isNumber pageLoadTimeout: v.isNumber - pluginsFile: v.isStringOrFalse + backgroundFile: v.isStringOrFalse port: v.isNumber reporter: v.isString requestTimeout: v.isNumber @@ -163,6 +165,8 @@ validateNoBreakingConfig = (cfg) -> errors.throw("RENAMED_CONFIG_OPTION", key, "trashAssetsBeforeRuns") when "videoRecording" errors.throw("RENAMED_CONFIG_OPTION", key, "video") + when "pluginsFile" + errors.throw("RENAMED_CONFIG_OPTION", key, "backgroundFile") validate = (cfg, onErr) -> _.each cfg, (value, key) -> @@ -179,6 +183,24 @@ validateFile = (file) -> validate settings, (errMsg) -> errors.throw("SETTINGS_VALIDATION_ERROR", file, errMsg) +validateBackgroundFile = (config) -> + return if not util.isDefault(config, "backgroundFile") + + ## if the backgroundFile is default and the file exists at the old + ## path (plugins/index.js), throw to let the user know to rename the file + oldPath = config.backgroundFile.replace( + "#{path.sep}background#{path.sep}index", + "#{path.sep}plugins#{path.sep}index" + ) + + shortOldPath = oldPath.replace("#{config.projectRoot}#{path.sep}", "") + shortNewPath = config.backgroundFile.replace("#{config.projectRoot}#{path.sep}", "") + + fs.pathExists(oldPath) + .then (found) -> + if found + errors.throw("REPATHED_BACKGROUND_FILE", shortOldPath, shortNewPath) + module.exports = { getConfigKeys: -> configKeys @@ -268,8 +290,9 @@ module.exports = { validateNoBreakingConfig(config) @setSupportFileAndFolder(config) - .then(@setPluginsFile) + .then(@setBackgroundFile) .then(@setScaffoldPaths) + .tap(validateBackgroundFile) setResolvedConfigValues: (config, defaults, resolved) -> obj = _.clone(config) @@ -278,7 +301,7 @@ module.exports = { return obj - updateWithPluginValues: (cfg, overrides = {}) -> + updateWithBackgroundValues: (cfg, overrides = {}) -> ## diff the overrides with cfg ## including nested objects (env) diffs = deepDiff(cfg, overrides, true) @@ -293,12 +316,12 @@ module.exports = { ## override the resolved value resolvedObj[key] = { value: val - from: "plugin" + from: "background" } ## for each override go through ## and change the resolved values of cfg - ## to point to the plugin + ## to point to the background file setResolvedOn(cfg.resolved, diffs) ## merge cfg into overrides @@ -398,54 +421,54 @@ module.exports = { debug("set support folder #{obj.supportFolder}") obj - ## set pluginsFile to an absolute path with the following rules: - ## - do nothing if pluginsFile is falsey - ## - look up the absolute path via node, so 'cypress/plugins' can resolve - ## to 'cypress/plugins/index.js' or 'cypress/plugins/index.coffee' + ## set backgroundFile to an absolute path with the following rules: + ## - do nothing if backgroundFile is falsey + ## - look up the absolute path via node, so 'cypress/background' can resolve + ## to 'cypress/background/index.js' or 'cypress/background/index.coffee' ## - if not found - ## * and the pluginsFile is set to the default - ## - and the path to the pluginsFile directory exists - ## * assume the user doesn't need a pluginsFile, set it to false + ## * and the backgroundFile is set to the default + ## - and the path to the backgroundFile directory exists + ## * assume the user doesn't need a backgroundFile, set it to false ## so it's ignored down the pipeline - ## - and the path to the pluginsFile directory does not exist - ## * set it to cypress/plugins/index.js, it will get scaffolded - ## * and the pluginsFile is NOT set to the default + ## - and the path to the backgroundFile directory does not exist + ## * set it to cypress/background/index.js, it will get scaffolded + ## * and the backgroundFile is NOT set to the default ## - throw an error, because it should be there if the user ## explicitly set it - setPluginsFile: (obj) -> - return Promise.resolve(obj) if not obj.pluginsFile + setBackgroundFile: (obj) -> + return Promise.resolve(obj) if not obj.backgroundFile obj = _.clone(obj) - pluginsFile = obj.pluginsFile + backgroundFile = obj.backgroundFile - debug("setting plugins file #{pluginsFile}") + debug("setting background file #{backgroundFile}") debug("for project root #{obj.projectRoot}") Promise .try -> ## resolve full path with extension - obj.pluginsFile = require.resolve(pluginsFile) - debug("set pluginsFile to #{obj.pluginsFile}") + obj.backgroundFile = require.resolve(backgroundFile) + debug("set backgroundFile to #{obj.backgroundFile}") .catch {code: "MODULE_NOT_FOUND"}, -> - debug("plugins file does not exist") - if pluginsFile is path.resolve(obj.projectRoot, defaults.pluginsFile) - debug("plugins file is default, check if #{path.dirname(pluginsFile)} exists") - fs.pathExists(pluginsFile) + debug("background file does not exist") + if backgroundFile is path.resolve(obj.projectRoot, defaults.backgroundFile) + debug("background file is default, check if #{path.dirname(backgroundFile)} exists") + fs.pathExists(backgroundFile) .then (found) -> if found - debug("plugins folder exists, set pluginsFile to false") + debug("background folder exists, set backgroundFile to false") ## if the directory exists, set it to false so it's ignored - obj.pluginsFile = false + obj.backgroundFile = false else - debug("plugins folder does not exist, set to default index.js") + debug("background folder does not exist, set to default index.js") ## otherwise, set it up to be scaffolded later - obj.pluginsFile = path.join(pluginsFile, "index.js") + obj.backgroundFile = path.join(backgroundFile, "index.js") return obj else - debug("plugins file is not default") + debug("background file is not default") ## they have it explicitly set, so it should be there - errors.throw("PLUGINS_FILE_ERROR", path.resolve(obj.projectRoot, pluginsFile)) + errors.throw("BACKGROUND_FILE_ERROR", path.resolve(obj.projectRoot, backgroundFile)) .return(obj) setParentTestsPaths: (obj) -> diff --git a/packages/server/lib/controllers/spec.coffee b/packages/server/lib/controllers/spec.coffee index 7ea59be2b140..80b431bbeb89 100644 --- a/packages/server/lib/controllers/spec.coffee +++ b/packages/server/lib/controllers/spec.coffee @@ -1,7 +1,7 @@ debug = require("debug")("cypress:server:controllers:spec") Promise = require("bluebird") errors = require("../errors") -preprocessor = require("../plugins/preprocessor") +preprocessor = require("../background/preprocessor") module.exports = { handle: (spec, req, res, config, next, project) -> diff --git a/packages/server/lib/errors.coffee b/packages/server/lib/errors.coffee index 74872bcba0a4..522d8532efc4 100644 --- a/packages/server/lib/errors.coffee +++ b/packages/server/lib/errors.coffee @@ -525,31 +525,31 @@ getMsgByType = (type, arg1 = {}, arg2) -> Learn more at https://on.cypress.io/support-file-missing-or-invalid """ - when "PLUGINS_FILE_ERROR" + when "BACKGROUND_FILE_ERROR" """ - The plugins file is missing or invalid. + The background file is missing or invalid. - Your pluginsFile is set to '#{arg1}', but either the file is missing, it contains a syntax error, or threw an error when required. The pluginsFile must be a .js or .coffee file. + Your backgroundFile is set to '#{arg1}', but either the file is missing, it contains a syntax error, or threw an error when required. The backgroundFile must be a .js or .coffee file. - Please fix this, or set 'pluginsFile' to 'false' if a plugins file is not necessary for your project. + Please fix this, or set 'backgroundFile' to 'false' if a background file is not necessary for your project. #{if arg2 then "The following error was thrown:" else ""} #{if arg2 then chalk.yellow(arg2) else ""} """.trim() - when "PLUGINS_DIDNT_EXPORT_FUNCTION" + when "BACKGROUND_DIDNT_EXPORT_FUNCTION" """ - The pluginsFile must export a function. + The backgroundFile must export a function. - We loaded the pluginsFile from: #{arg1} + We loaded the backgroundFile from: #{arg1} It exported: #{JSON.stringify(arg2)} """ - when "PLUGINS_FUNCTION_ERROR" + when "BACKGROUND_FUNCTION_ERROR" """ - The function exported by the plugins file threw an error. + The function exported by the background file threw an error. We invoked the function exported by '#{arg1}', but it threw an error. @@ -557,9 +557,9 @@ getMsgByType = (type, arg1 = {}, arg2) -> #{chalk.yellow(arg2)} """.trim() - when "PLUGINS_ERROR" + when "BACKGROUND_ERROR" """ - The following error was thrown by a plugin. We've stopped running your tests because a plugin crashed. + The following error was thrown by a plugin in the background process. We've stopped running your tests because the background process crashed. #{chalk.yellow(arg1)} """.trim() @@ -651,6 +651,15 @@ getMsgByType = (type, arg1 = {}, arg2) -> We looked but did not find a #{chalk.blue('cypress.json')} file in this folder: #{chalk.blue(arg1)} """ + when "REPATHED_BACKGROUND_FILE" + """ + The "plugins file" has been renamed to the "background file" and has a new default path. + + Please rename + #{chalk.yellow(arg1)} + to + #{chalk.blue(arg2)} + """ when "DUPLICATE_TASK_KEY" """ Warning: Multiple attempts to register the following task(s): #{chalk.blue(arg1)}. Only the last attempt will be registered. diff --git a/packages/server/lib/open_project.coffee b/packages/server/lib/open_project.coffee index 79a5cae2869c..39e48346cc6f 100644 --- a/packages/server/lib/open_project.coffee +++ b/packages/server/lib/open_project.coffee @@ -7,7 +7,7 @@ config = require("./config") Project = require("./project") browsers = require("./browsers") specsUtil = require("./util/specs") -preprocessor = require("./plugins/preprocessor") +preprocessor = require("./background/preprocessor") create = -> openProject = null diff --git a/packages/server/lib/project.coffee b/packages/server/lib/project.coffee index b062a0776bc1..12f2167e0dd2 100644 --- a/packages/server/lib/project.coffee +++ b/packages/server/lib/project.coffee @@ -16,14 +16,14 @@ config = require("./config") logger = require("./logger") errors = require("./errors") Server = require("./server") -plugins = require("./plugins") +background = require("./background") scaffold = require("./scaffold") Watchers = require("./watchers") Reporter = require("./reporter") browsers = require("./browsers") savedState = require("./saved_state") Automation = require("./automation") -preprocessor = require("./plugins/preprocessor") +preprocessor = require("./background/preprocessor") fs = require("./util/fs") settings = require("./util/settings") specsUtil = require("./util/specs") @@ -75,18 +75,18 @@ class Project extends EE .tap (cfg) => process.chdir(@projectRoot) - ## TODO: we currently always scaffold the plugins file + ## TODO: we currently always scaffold the background file ## even when headlessly or else it will cause an error when ## we try to load it and it's not there. We must do this here - ## else initialing the plugins will instantly fail. - if cfg.pluginsFile - scaffold.plugins(path.dirname(cfg.pluginsFile), cfg) + ## else initializing the background file will instantly fail. + if cfg.backgroundFile + scaffold.background(path.dirname(cfg.backgroundFile), cfg) .then (cfg) => - @_initPlugins(cfg, options) + @_initbackground(cfg, options) .then (modifiedCfg) -> - debug("plugin config yielded:", modifiedCfg) + debug("background config yielded:", modifiedCfg) - return config.updateWithPluginValues(cfg, modifiedCfg) + return config.updateWithBackgroundValues(cfg, modifiedCfg) .then (cfg) => @server.open(cfg, @) .spread (port, warning) => @@ -118,22 +118,22 @@ class Project extends EE .then => Promise.join( @checkSupportFile(cfg) - @watchPluginsFile(cfg, options) + @watchBackgroundFile(cfg, options) ) # return our project instance .return(@) - _initPlugins: (cfg, options) -> - ## only init plugins with the + _initbackground: (cfg, options) -> + ## only init background with the ## whitelisted config values to ## prevent tampering with the ## internals and breaking cypress cfg = config.whitelist(cfg) - plugins.init(cfg, { + background.init(cfg, { onError: (err) -> - debug('got plugins error', err.stack) + debug('got background error', err.stack) browsers.close() options.onError(err) @@ -179,24 +179,24 @@ class Project extends EE if not found errors.throw("SUPPORT_FILE_NOT_FOUND", supportFile) - watchPluginsFile: (cfg, options) -> - debug("attempt watch plugins file: #{cfg.pluginsFile}") - if not cfg.pluginsFile + watchBackgroundFile: (cfg, options) -> + debug("attempt watch background file: #{cfg.backgroundFile}") + if not cfg.backgroundFile return Promise.resolve() - fs.pathExists(cfg.pluginsFile) + fs.pathExists(cfg.backgroundFile) .then (found) => - debug("plugins file found? #{found}") - ## ignore if not found. plugins#init will throw the right error + debug("background file found? #{found}") + ## ignore if not found. background#init will throw the right error return if not found - debug("watch plugins file") - @watchers.watchTree(cfg.pluginsFile, { + debug("watch background file") + @watchers.watchTree(cfg.backgroundFile, { onChange: => ## TODO: completely re-open project instead? - debug("plugins file changed") - ## re-init plugins after a change - @_initPlugins(cfg, options) + debug("background file changed") + ## re-init background after a change + @_initbackground(cfg, options) .catch (err) -> options.onError(err) }) diff --git a/packages/server/lib/scaffold.coffee b/packages/server/lib/scaffold.coffee index a2d4f8f8df96..efcd452e4225 100644 --- a/packages/server/lib/scaffold.coffee +++ b/packages/server/lib/scaffold.coffee @@ -127,16 +127,16 @@ module.exports = { ) ) - plugins: (folder, config) -> - debug("plugins folder #{folder}") + background: (folder, config) -> + debug("background folder #{folder}") - ## skip if user has explicitly set pluginsFile - if not config.pluginsFile or not isDefault(config, "pluginsFile") + ## skip if user has explicitly set backgroundFile + if not config.backgroundFile or not isDefault(config, "backgroundFile") return Promise.resolve() @verifyScaffolding folder, => debug("copying index.js into #{folder}") - @_copy("plugins/index.js", folder, config) + @_copy("background/index.js", folder, config) _copy: (file, folder, config) -> ## allow file to be relative or absolute @@ -192,9 +192,9 @@ module.exports = { getFilePath(config.supportFolder, "index.js") ]) - if config.pluginsFile + if config.backgroundFile files = files.concat([ - getFilePath(path.dirname(config.pluginsFile), "index.js") + getFilePath(path.dirname(config.backgroundFile), "index.js") ]) debug("scaffolded files %j", files) diff --git a/packages/server/lib/scaffold/plugins/index.js b/packages/server/lib/scaffold/background/index.js similarity index 69% rename from packages/server/lib/scaffold/plugins/index.js rename to packages/server/lib/scaffold/background/index.js index fd170fba6912..c24345ace6c9 100644 --- a/packages/server/lib/scaffold/plugins/index.js +++ b/packages/server/lib/scaffold/background/index.js @@ -1,11 +1,12 @@ // *********************************************************** -// This example plugins/index.js can be used to load plugins +// This example background/index.js can be used to load plugins +// in the background process // // You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. +// the background file with the 'backgroundFile' configuration option. // // You can read more here: -// https://on.cypress.io/plugins-guide +// https://on.cypress.io/background-process // *********************************************************** // This function is called when a project is opened or re-opened (e.g. due to diff --git a/packages/server/lib/screenshots.coffee b/packages/server/lib/screenshots.coffee index 2a0b2897b96b..2a2566aa120a 100644 --- a/packages/server/lib/screenshots.coffee +++ b/packages/server/lib/screenshots.coffee @@ -7,7 +7,7 @@ Jimp = require("jimp") sizeOf = require("image-size") colorString = require("color-string") debug = require("debug")("cypress:server:screenshot") -plugins = require("./plugins") +background = require("./background") fs = require("./util/fs") glob = require("./util/glob") pathHelpers = require("./util/path_helpers") @@ -453,10 +453,10 @@ module.exports = { details = _.extend({}, data, details, { duration }) details = _.pick(details, "size", "takenAt", "dimensions", "multipart", "pixelRatio", "name", "specName", "testFailure", "path", "scaled", "blackout", "duration") - if not plugins.has("after:screenshot") + if not background.isRegistered("after:screenshot") return Promise.resolve(details) - plugins.execute("after:screenshot", details) + background.execute("after:screenshot", details) .then (updates) => if not _.isPlainObject(updates) return details diff --git a/packages/server/lib/socket.coffee b/packages/server/lib/socket.coffee index 6a35607f5b0a..0fa4945e4a19 100644 --- a/packages/server/lib/socket.coffee +++ b/packages/server/lib/socket.coffee @@ -14,7 +14,7 @@ files = require("./files") fixture = require("./fixture") errors = require("./errors") automation = require("./automation") -preprocessor = require("./plugins/preprocessor") +preprocessor = require("./background/preprocessor") runnerEvents = [ "reporter:restart:test:run" @@ -307,7 +307,7 @@ class Socket when "exec" exec.run(config.projectRoot, args[0]) when "task" - task.run(config.pluginsFile, args[0]) + task.run(config.backgroundFile, args[0]) else throw new Error( "You requested a backend event we cannot handle: #{eventName}" diff --git a/packages/server/lib/task.coffee b/packages/server/lib/task.coffee index ca97bf2d0543..ba2b53fb12e6 100644 --- a/packages/server/lib/task.coffee +++ b/packages/server/lib/task.coffee @@ -1,7 +1,7 @@ _ = require("lodash") Promise = require("bluebird") debug = require("debug")("cypress:server:task") -plugins = require("./plugins") +background = require("./background") docsUrl = "https://on.cypress.io/api/task" @@ -11,27 +11,27 @@ throwKnownError = (message, props = {}) -> throw err module.exports = { - run: (pluginsFilePath, options) -> + run: (backgroundFilePath, options) -> debug("run task", options.task, "with arg", options.arg) - fileAndDocsUrl = "\n\nFix this in your plugins file here:\n#{pluginsFilePath}\n\n#{docsUrl}" + fileAndDocsUrl = "\n\nFix this in your background file here:\n#{backgroundFilePath}\n\n#{docsUrl}" Promise .try -> - if not plugins.has("task") + if not background.isRegistered("task") debug("'task' event is not registered") - throwKnownError("The 'task' event has not been registered in the plugins file. You must register it before using cy.task()#{fileAndDocsUrl}") + throwKnownError("The 'task' event has not been registered in the background file. You must register it before using cy.task()#{fileAndDocsUrl}") - plugins.execute("task", options.task, options.arg) + background.execute("task", options.task, options.arg) .then (result) -> if result is "__cypress_unhandled__" debug("task is unhandled") - return plugins.execute("_get:task:keys").then (keys) -> - throwKnownError("The task '#{options.task}' was not handled in the plugins file. The following tasks are registered: #{keys.join(", ")}#{fileAndDocsUrl}") + return background.execute("_get:task:keys").then (keys) -> + throwKnownError("The task '#{options.task}' was not handled in the background file. The following tasks are registered: #{keys.join(", ")}#{fileAndDocsUrl}") if result is undefined debug("result is undefined") - return plugins.execute("_get:task:body", options.task).then (body) -> + return background.execute("_get:task:body", options.task).then (body) -> handler = if body then "\n\nThe task handler was:\n\n#{body}" else "" throwKnownError("The task '#{options.task}' returned undefined. You must return a promise, a value, or null to indicate that the task was handled.#{handler}#{fileAndDocsUrl}") @@ -40,7 +40,7 @@ module.exports = { .timeout(options.timeout) .catch Promise.TimeoutError, -> debug("timed out after #{options.timeout}ms") - plugins.execute("_get:task:body", options.task).then (body) -> + background.execute("_get:task:body", options.task).then (body) -> err = new Error("The task handler was:\n\n#{body}#{fileAndDocsUrl}") err.timedOut = true throw err diff --git a/packages/server/lib/util/path_helpers.js b/packages/server/lib/util/path_helpers.js index f83161e81f6e..64e26ad2f23f 100644 --- a/packages/server/lib/util/path_helpers.js +++ b/packages/server/lib/util/path_helpers.js @@ -34,7 +34,6 @@ const checkIfResolveChangedRootFolder = (resolved, initial) => { !resolved.startsWith(initial) } - // real folder path found could be different due to symlinks // For example, folder /tmp/foo on Mac is really /private/tmp/foo const getRealFolderPath = function (folder) { diff --git a/packages/server/lib/util/random.js b/packages/server/lib/util/random.js index 16f62fe199b3..ecfe9bdf67c2 100644 --- a/packages/server/lib/util/random.js +++ b/packages/server/lib/util/random.js @@ -19,7 +19,6 @@ const id = () => }) } - module.exports = { id, } diff --git a/packages/server/lib/util/saved_state.js b/packages/server/lib/util/saved_state.js index c8131c8f6255..3dc45df70e56 100644 --- a/packages/server/lib/util/saved_state.js +++ b/packages/server/lib/util/saved_state.js @@ -67,7 +67,6 @@ const formStatePath = (projectRoot) => { }) } - module.exports = { toHashName, formStatePath, diff --git a/packages/server/lib/util/security.js b/packages/server/lib/util/security.js index e6be56584dcb..1c3ab13001f5 100644 --- a/packages/server/lib/util/security.js +++ b/packages/server/lib/util/security.js @@ -25,7 +25,6 @@ const strip = (html) => { .replace(jiraTopWindowGetterRe, '$1 || $2.parent.__Cypress__$3') } - const stripStream = () => { return pumpify( replacestream(topOrParentEqualityBeforeRe, '$1self'), @@ -35,7 +34,6 @@ const stripStream = () => { ) } - module.exports = { strip, diff --git a/packages/server/lib/util/shell.js b/packages/server/lib/util/shell.js index 69ab538318e1..2021873dfe3c 100644 --- a/packages/server/lib/util/shell.js +++ b/packages/server/lib/util/shell.js @@ -85,7 +85,6 @@ const findBash = () => { .then(R.prop('stdout')) } - const getShell = function (shell) { let s diff --git a/packages/server/lib/util/specs.js b/packages/server/lib/util/specs.js index 4514809bad50..b14ffa5dfa4e 100644 --- a/packages/server/lib/util/specs.js +++ b/packages/server/lib/util/specs.js @@ -24,7 +24,6 @@ const getPatternRelativeToProjectRoot = (specPattern, projectRoot) => { }) } - const find = function (config, specPattern) { let fixturesFolderPath @@ -115,7 +114,6 @@ const find = function (config, specPattern) { }) } - const matchesSpecPattern = function (file) { if (!specPattern) { return true diff --git a/packages/server/lib/util/system.js b/packages/server/lib/util/system.js index 54335fa32cc9..023a01959026 100644 --- a/packages/server/lib/util/system.js +++ b/packages/server/lib/util/system.js @@ -28,7 +28,6 @@ const getOsVersion = () => { }) } - module.exports = { info () { return getOsVersion() diff --git a/packages/server/lib/util/terminal.js b/packages/server/lib/util/terminal.js index dc571efad3ec..f94f0967930e 100644 --- a/packages/server/lib/util/terminal.js +++ b/packages/server/lib/util/terminal.js @@ -29,7 +29,6 @@ const getMaximumColumns = () => return Math.min(MAXIMUM_SIZE, terminalSize.get().columns) } - const getBordersLength = (left, right) => { return _ .chain([left, right]) @@ -39,7 +38,6 @@ const getBordersLength = (left, right) => { .value() } - const convertDecimalsToNumber = function (colWidths, cols) { let diff const sum = _.sum(colWidths) @@ -80,7 +78,6 @@ const renderTables = (...tables) => { .value() } - const getChars = function (type) { switch (type) { case 'border': @@ -158,7 +155,6 @@ const wrapBordersInGray = (chars) => { }) } - const table = function (options = {}) { const { colWidths, type } = options diff --git a/packages/server/test/e2e/2_controllers_spec.coffee b/packages/server/test/e2e/2_controllers_spec.coffee index a1c89b7e5c5c..56c94a44d084 100644 --- a/packages/server/test/e2e/2_controllers_spec.coffee +++ b/packages/server/test/e2e/2_controllers_spec.coffee @@ -3,7 +3,7 @@ Fixtures = require("../support/helpers/fixtures") nonExistentSpec = Fixtures.projectPath("non-existent-spec") -describe "e2e plugins", -> +describe "e2e controllers", -> e2e.setup() it "fails when spec does not exist", -> diff --git a/packages/server/test/e2e/3_background_events_spec.coffee b/packages/server/test/e2e/3_background_events_spec.coffee new file mode 100644 index 000000000000..3125256ff875 --- /dev/null +++ b/packages/server/test/e2e/3_background_events_spec.coffee @@ -0,0 +1,87 @@ +path = require("path") + +e2e = require("../support/helpers/e2e") +Fixtures = require("../support/helpers/fixtures") + +backgroundExtension = Fixtures.projectPath("background-extension") +backgroundConfig = Fixtures.projectPath("background-config") +workingPreprocessor = Fixtures.projectPath("working-preprocessor") +backgroundAsyncError = Fixtures.projectPath("background-async-error") +backgroundAbsolutePath = Fixtures.projectPath("background-absolute-path") +backgroundAfterScreenshot = Fixtures.projectPath("background-after-screenshot") +backgroundPluginsFile = Fixtures.projectPath("background-plugins-file") + +describe "e2e background events", -> + e2e.setup() + + it "passes", -> + e2e.exec(@, { + spec: "app_spec.coffee" + project: workingPreprocessor + snapshot: true + expectedExitCode: 0 + }) + + it "fails", -> + e2e.exec(@, { + spec: "app_spec.coffee" + project: backgroundAsyncError + snapshot: true + expectedExitCode: 1 + }) + + it "can modify config from background", -> + e2e.exec(@, { + spec: "app_spec.coffee" + env: "foo=foo,bar=bar" + config: { pageLoadTimeout: 10000 } + project: backgroundConfig + snapshot: true + expectedExitCode: 0 + }) + + it "works with user extensions", -> + e2e.exec(@, { + browser: "chrome" + spec: "app_spec.coffee" + project: backgroundExtension + snapshot: true + expectedExitCode: 0 + }) + + it "handles absolute path to backgroundFile", -> + e2e.exec(@, { + spec: "absolute_spec.coffee" + config: { + backgroundFile: path.join( + backgroundAbsolutePath, + "cypress/background/index.js" + ) + } + project: backgroundAbsolutePath + snapshot: true + expectedExitCode: 0 + }) + + it "calls after:screenshot for cy.screenshot() and failure screenshots", -> + e2e.exec(@, { + spec: "after_screenshot_spec.coffee" + project: backgroundAfterScreenshot + snapshot: true + expectedExitCode: 1 + }) + + it "errors when pluginsFile is used in config", -> + e2e.exec(@, { + spec: "simple_spec.coffee" + config: "pluginsFile=cypress/integration/background/index.js" + snapshot: true + expectedExitCode: 1 + }) + + it "errors when backgroundFile path is default and plugins/index.js exists", -> + e2e.exec(@, { + project: backgroundPluginsFile + snapshot: true + expectedExitCode: 1 + }) diff --git a/packages/server/test/e2e/3_plugins_spec.coffee b/packages/server/test/e2e/3_plugins_spec.coffee deleted file mode 100644 index 3c820a6df501..000000000000 --- a/packages/server/test/e2e/3_plugins_spec.coffee +++ /dev/null @@ -1,71 +0,0 @@ -path = require("path") - -e2e = require("../support/helpers/e2e") -Fixtures = require("../support/helpers/fixtures") - -pluginExtension = Fixtures.projectPath("plugin-extension") -pluginConfig = Fixtures.projectPath("plugin-config") -workingPreprocessor = Fixtures.projectPath("working-preprocessor") -pluginsAsyncError = Fixtures.projectPath("plugins-async-error") -pluginsAbsolutePath = Fixtures.projectPath("plugins-absolute-path") -pluginAfterScreenshot = Fixtures.projectPath("plugin-after-screenshot") - -describe "e2e plugins", -> - e2e.setup() - - it "passes", -> - e2e.exec(@, { - spec: "app_spec.coffee" - project: workingPreprocessor - snapshot: true - expectedExitCode: 0 - }) - - it "fails", -> - e2e.exec(@, { - spec: "app_spec.coffee" - project: pluginsAsyncError - snapshot: true - expectedExitCode: 1 - }) - - it "can modify config from plugins", -> - e2e.exec(@, { - spec: "app_spec.coffee" - env: "foo=foo,bar=bar" - config: { pageLoadTimeout: 10000 } - project: pluginConfig - snapshot: true - expectedExitCode: 0 - }) - - it "works with user extensions", -> - e2e.exec(@, { - browser: "chrome" - spec: "app_spec.coffee" - project: pluginExtension - snapshot: true - expectedExitCode: 0 - }) - - it "handles absolute path to pluginsFile", -> - e2e.exec(@, { - spec: "absolute_spec.coffee" - config: { - pluginsFile: path.join( - pluginsAbsolutePath, - "cypress/plugins/index.js" - ) - } - project: pluginsAbsolutePath - snapshot: true - expectedExitCode: 0 - }) - - it "calls after:screenshot for cy.screenshot() and failure screenshots", -> - e2e.exec(@, { - spec: "after_screenshot_spec.coffee" - project: pluginAfterScreenshot - snapshot: true - expectedExitCode: 1 - }) diff --git a/packages/server/test/e2e/6_task_spec.coffee b/packages/server/test/e2e/6_task_spec.coffee index 52061f4e9f43..199afc2081d8 100644 --- a/packages/server/test/e2e/6_task_spec.coffee +++ b/packages/server/test/e2e/6_task_spec.coffee @@ -12,10 +12,10 @@ describe "e2e task", -> expectedExitCode: 2 }) .then ({ stdout }) -> - ## should include a stack trace from plugins file + ## should include a stack trace from background file match = stdout.match(/at errors(.*)\n/) expect(match).not.to.be.null - expect(match[0]).to.include("plugins/index.js") + expect(match[0]).to.include("background/index.js") it "merges task events on subsequent registrations and logs warning for conflicts", -> e2e.exec(@, { diff --git a/packages/server/test/integration/cypress_spec.coffee b/packages/server/test/integration/cypress_spec.coffee index f9b775a5dc67..0150fa9f0f92 100644 --- a/packages/server/test/integration/cypress_spec.coffee +++ b/packages/server/test/integration/cypress_spec.coffee @@ -31,7 +31,7 @@ user = require("#{root}lib/user") config = require("#{root}lib/config") cache = require("#{root}lib/cache") errors = require("#{root}lib/errors") -plugins = require("#{root}lib/plugins") +background = require("#{root}lib/background") cypress = require("#{root}lib/cypress") Project = require("#{root}lib/project") Server = require("#{root}lib/server") @@ -97,14 +97,14 @@ describe "lib/cypress", -> @pristinePath = Fixtures.projectPath("pristine") @noScaffolding = Fixtures.projectPath("no-scaffolding") @recordPath = Fixtures.projectPath("record") - @pluginConfig = Fixtures.projectPath("plugin-config") - @pluginBrowser = Fixtures.projectPath("plugin-browser") + @backgroundConfig = Fixtures.projectPath("background-config") + @backgroundBrowser = Fixtures.projectPath("background-browser") @idsPath = Fixtures.projectPath("ids") ## force cypress to call directly into main without ## spawning a separate process sinon.stub(videoCapture, "start").resolves({}) - sinon.stub(plugins, "init").resolves(undefined) + sinon.stub(background, "init").resolves(undefined) sinon.stub(cypress, "isCurrentlyRunningElectron").returns(true) sinon.stub(extension, "setHostAndPath").resolves() sinon.stub(launcher, "detect").resolves(TYPICAL_BROWSERS) @@ -705,11 +705,11 @@ describe "lib/cypress", -> @expectExitWith(0) - it "can override values in plugins", -> - plugins.init.restore() + it "can override values in background", -> + background.init.restore() cypress.start([ - "--run-project=#{@pluginConfig}", "--config=requestTimeout=1234,videoCompression=false" + "--run-project=#{@backgroundConfig}", "--config=requestTimeout=1234,videoCompression=false" "--env=foo=foo,bar=bar" ]) .then => @@ -724,7 +724,7 @@ describe "lib/cypress", -> expect(cfg.resolved.videoCompression).to.deep.eq({ value: 20 - from: "plugin" + from: "background" }) expect(cfg.resolved.requestTimeout).to.deep.eq({ value: 1234 @@ -732,7 +732,7 @@ describe "lib/cypress", -> }) expect(cfg.resolved.env.foo).to.deep.eq({ value: "bar" - from: "plugin" + from: "background" }) expect(cfg.resolved.env.bar).to.deep.eq({ value: "bar" @@ -741,9 +741,9 @@ describe "lib/cypress", -> @expectExitWith(0) - describe "plugins", -> + describe "background", -> beforeEach -> - plugins.init.restore() + background.init.restore() browsers.open.restore() ee = new EE() @@ -775,7 +775,7 @@ describe "lib/cypress", -> context "before:browser:launch", -> it "chrome", -> cypress.start([ - "--run-project=#{@pluginBrowser}" + "--run-project=#{@backgroundBrowser}" "--browser=chrome" ]) .then => @@ -798,11 +798,11 @@ describe "lib/cypress", -> videoCapture.start.returns({ write }) cypress.start([ - "--run-project=#{@pluginBrowser}" + "--run-project=#{@backgroundBrowser}" "--browser=electron" ]) .then => - expect(Windows.create).to.be.calledWithMatch(@pluginBrowser, { + expect(Windows.create).to.be.calledWithMatch(@backgroundBrowser, { browser: "electron" foo: "bar" onNewWindow: sinon.match.func diff --git a/packages/server/test/integration/http_requests_spec.coffee b/packages/server/test/integration/http_requests_spec.coffee index b8d13e1d407e..f4b1c50080c4 100644 --- a/packages/server/test/integration/http_requests_spec.coffee +++ b/packages/server/test/integration/http_requests_spec.coffee @@ -24,7 +24,7 @@ Project = require("#{root}lib/project") Watchers = require("#{root}lib/watchers") errors = require("#{root}lib/errors") files = require("#{root}lib/controllers/files") -preprocessor = require("#{root}lib/plugins/preprocessor") +preprocessor = require("#{root}lib/background/preprocessor") fs = require("#{root}lib/util/fs") glob = require("#{root}lib/util/glob") CacheBuster = require("#{root}lib/util/cache_buster") diff --git a/packages/server/test/support/fixtures/projects/plugin-after-screenshot/cypress.json b/packages/server/test/support/fixtures/projects/background-absolute-path/cypress.json similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-after-screenshot/cypress.json rename to packages/server/test/support/fixtures/projects/background-absolute-path/cypress.json diff --git a/packages/server/test/support/fixtures/projects/plugins-absolute-path/cypress/plugins/index.js b/packages/server/test/support/fixtures/projects/background-absolute-path/cypress/background/index.js similarity index 100% rename from packages/server/test/support/fixtures/projects/plugins-absolute-path/cypress/plugins/index.js rename to packages/server/test/support/fixtures/projects/background-absolute-path/cypress/background/index.js diff --git a/packages/server/test/support/fixtures/projects/plugins-absolute-path/cypress/integration/absolute_spec.coffee b/packages/server/test/support/fixtures/projects/background-absolute-path/cypress/integration/absolute_spec.coffee similarity index 61% rename from packages/server/test/support/fixtures/projects/plugins-absolute-path/cypress/integration/absolute_spec.coffee rename to packages/server/test/support/fixtures/projects/background-absolute-path/cypress/integration/absolute_spec.coffee index 073616935021..c458db4921ab 100644 --- a/packages/server/test/support/fixtures/projects/plugins-absolute-path/cypress/integration/absolute_spec.coffee +++ b/packages/server/test/support/fixtures/projects/background-absolute-path/cypress/integration/absolute_spec.coffee @@ -1,2 +1,2 @@ -it "uses the plugins file", -> +it "uses the background file", -> cy.task('returns:arg', 'foo').should('equal', 'foo') diff --git a/packages/server/test/support/fixtures/projects/plugin-browser/cypress.json b/packages/server/test/support/fixtures/projects/background-after-screenshot/cypress.json similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-browser/cypress.json rename to packages/server/test/support/fixtures/projects/background-after-screenshot/cypress.json diff --git a/packages/server/test/support/fixtures/projects/plugin-after-screenshot/cypress/plugins/index.js b/packages/server/test/support/fixtures/projects/background-after-screenshot/cypress/background/index.js similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-after-screenshot/cypress/plugins/index.js rename to packages/server/test/support/fixtures/projects/background-after-screenshot/cypress/background/index.js diff --git a/packages/server/test/support/fixtures/projects/plugin-after-screenshot/cypress/integration/after_screenshot_spec.coffee b/packages/server/test/support/fixtures/projects/background-after-screenshot/cypress/integration/after_screenshot_spec.coffee similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-after-screenshot/cypress/integration/after_screenshot_spec.coffee rename to packages/server/test/support/fixtures/projects/background-after-screenshot/cypress/integration/after_screenshot_spec.coffee diff --git a/packages/server/test/support/fixtures/projects/plugin-after-screenshot/screenshot-replacement.png b/packages/server/test/support/fixtures/projects/background-after-screenshot/screenshot-replacement.png similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-after-screenshot/screenshot-replacement.png rename to packages/server/test/support/fixtures/projects/background-after-screenshot/screenshot-replacement.png diff --git a/packages/server/test/support/fixtures/projects/plugin-config/cypress.json b/packages/server/test/support/fixtures/projects/background-async-error/cypress.json similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-config/cypress.json rename to packages/server/test/support/fixtures/projects/background-async-error/cypress.json diff --git a/packages/server/test/support/fixtures/projects/plugins-async-error/cypress/plugins/index.js b/packages/server/test/support/fixtures/projects/background-async-error/cypress/background/index.js similarity index 73% rename from packages/server/test/support/fixtures/projects/plugins-async-error/cypress/plugins/index.js rename to packages/server/test/support/fixtures/projects/background-async-error/cypress/background/index.js index 30ae36270881..5b6f065af418 100644 --- a/packages/server/test/support/fixtures/projects/plugins-async-error/cypress/plugins/index.js +++ b/packages/server/test/support/fixtures/projects/background-async-error/cypress/background/index.js @@ -4,7 +4,7 @@ module.exports = (on) => { on('file:preprocessor', () => { return new Promise(() => { setTimeout(() => { - throw new Error('Async error from plugins file') + throw new Error('Async error from background file') }, 50) }) }) diff --git a/packages/server/test/support/fixtures/projects/plugins-async-error/cypress/integration/app_spec.coffee b/packages/server/test/support/fixtures/projects/background-async-error/cypress/integration/app_spec.coffee similarity index 100% rename from packages/server/test/support/fixtures/projects/plugins-async-error/cypress/integration/app_spec.coffee rename to packages/server/test/support/fixtures/projects/background-async-error/cypress/integration/app_spec.coffee diff --git a/packages/server/test/support/fixtures/projects/plugin-extension/cypress.json b/packages/server/test/support/fixtures/projects/background-browser/cypress.json similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-extension/cypress.json rename to packages/server/test/support/fixtures/projects/background-browser/cypress.json diff --git a/packages/server/test/support/fixtures/projects/plugin-browser/cypress/plugins/index.coffee b/packages/server/test/support/fixtures/projects/background-browser/cypress/background/index.coffee similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-browser/cypress/plugins/index.coffee rename to packages/server/test/support/fixtures/projects/background-browser/cypress/background/index.coffee diff --git a/packages/server/test/support/fixtures/projects/plugin-browser/cypress/integration/app_spec.coffee b/packages/server/test/support/fixtures/projects/background-browser/cypress/integration/app_spec.coffee similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-browser/cypress/integration/app_spec.coffee rename to packages/server/test/support/fixtures/projects/background-browser/cypress/integration/app_spec.coffee diff --git a/packages/server/test/support/fixtures/projects/plugins-absolute-path/cypress.json b/packages/server/test/support/fixtures/projects/background-config/cypress.json similarity index 100% rename from packages/server/test/support/fixtures/projects/plugins-absolute-path/cypress.json rename to packages/server/test/support/fixtures/projects/background-config/cypress.json diff --git a/packages/server/test/support/fixtures/projects/plugin-config/cypress/plugins/index.js b/packages/server/test/support/fixtures/projects/background-config/cypress/background/index.js similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-config/cypress/plugins/index.js rename to packages/server/test/support/fixtures/projects/background-config/cypress/background/index.js diff --git a/packages/server/test/support/fixtures/projects/plugin-config/cypress/integration/app_spec.coffee b/packages/server/test/support/fixtures/projects/background-config/cypress/integration/app_spec.coffee similarity index 81% rename from packages/server/test/support/fixtures/projects/plugin-config/cypress/integration/app_spec.coffee rename to packages/server/test/support/fixtures/projects/background-config/cypress/integration/app_spec.coffee index 8b956d3b0bce..7e51e3d5e5dd 100644 --- a/packages/server/test/support/fixtures/projects/plugin-config/cypress/integration/app_spec.coffee +++ b/packages/server/test/support/fixtures/projects/background-config/cypress/integration/app_spec.coffee @@ -1,5 +1,5 @@ it "overrides config", -> - ## overrides come from plugins + ## overrides come from background file expect(Cypress.config("defaultCommandTimeout")).to.eq(500) expect(Cypress.config("videoCompression")).to.eq(20) @@ -7,7 +7,7 @@ it "overrides config", -> expect(Cypress.config("pageLoadTimeout")).to.eq(10000) it "overrides env", -> - ## overrides come from plugins + ## overrides come from background file expect(Cypress.env("foo")).to.eq("bar") ## overrides come from CLI diff --git a/packages/server/test/support/fixtures/projects/plugins-async-error/cypress.json b/packages/server/test/support/fixtures/projects/background-extension/cypress.json similarity index 100% rename from packages/server/test/support/fixtures/projects/plugins-async-error/cypress.json rename to packages/server/test/support/fixtures/projects/background-extension/cypress.json diff --git a/packages/server/test/support/fixtures/projects/plugin-extension/cypress/plugins/index.coffee b/packages/server/test/support/fixtures/projects/background-extension/cypress/background/index.coffee similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-extension/cypress/plugins/index.coffee rename to packages/server/test/support/fixtures/projects/background-extension/cypress/background/index.coffee diff --git a/packages/server/test/support/fixtures/projects/plugin-extension/cypress/integration/app_spec.coffee b/packages/server/test/support/fixtures/projects/background-extension/cypress/integration/app_spec.coffee similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-extension/cypress/integration/app_spec.coffee rename to packages/server/test/support/fixtures/projects/background-extension/cypress/integration/app_spec.coffee diff --git a/packages/server/test/support/fixtures/projects/plugin-extension/ext/background.js b/packages/server/test/support/fixtures/projects/background-extension/ext/background.js similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-extension/ext/background.js rename to packages/server/test/support/fixtures/projects/background-extension/ext/background.js diff --git a/packages/server/test/support/fixtures/projects/plugin-extension/ext/manifest.json b/packages/server/test/support/fixtures/projects/background-extension/ext/manifest.json similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-extension/ext/manifest.json rename to packages/server/test/support/fixtures/projects/background-extension/ext/manifest.json diff --git a/packages/server/test/support/fixtures/projects/plugin-extension/index.html b/packages/server/test/support/fixtures/projects/background-extension/index.html similarity index 100% rename from packages/server/test/support/fixtures/projects/plugin-extension/index.html rename to packages/server/test/support/fixtures/projects/background-extension/index.html diff --git a/packages/server/test/support/fixtures/projects/background-plugins-file/cypress.json b/packages/server/test/support/fixtures/projects/background-plugins-file/cypress.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/server/test/support/fixtures/projects/background-plugins-file/cypress.json @@ -0,0 +1 @@ +{} diff --git a/packages/server/test/support/fixtures/projects/background-plugins-file/cypress/integration/background_plugins_file.coffee b/packages/server/test/support/fixtures/projects/background-plugins-file/cypress/integration/background_plugins_file.coffee new file mode 100644 index 000000000000..346e8e5a9db7 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/background-plugins-file/cypress/integration/background_plugins_file.coffee @@ -0,0 +1 @@ +it "is true", -> diff --git a/packages/server/test/support/fixtures/projects/background-plugins-file/cypress/plugins/index.js b/packages/server/test/support/fixtures/projects/background-plugins-file/cypress/plugins/index.js new file mode 100644 index 000000000000..0c0c42d5b58c --- /dev/null +++ b/packages/server/test/support/fixtures/projects/background-plugins-file/cypress/plugins/index.js @@ -0,0 +1 @@ +module.exports = () => {} diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/plugins/index.js b/packages/server/test/support/fixtures/projects/e2e/cypress/background/index.js similarity index 99% rename from packages/server/test/support/fixtures/projects/e2e/cypress/plugins/index.js rename to packages/server/test/support/fixtures/projects/e2e/cypress/background/index.js index eb208051ffc1..0673b06fbad8 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/plugins/index.js +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/background/index.js @@ -6,13 +6,17 @@ const Promise = require('bluebird') module.exports = (on) => { // save some time by only reading the originals once let cache = {} + function getCachedImage (name) { const cachedImage = cache[name] + if (cachedImage) return Promise.resolve(cachedImage) const imagePath = path.join(__dirname, '..', 'screenshots', `${name}.png`) + return Jimp.read(imagePath).then((image) => { cache[name] = image + return image }) } @@ -52,6 +56,7 @@ module.exports = (on) => { } const comparePath = path.join(__dirname, '..', 'screenshots', `${b}.png`) + return Promise.all([ getCachedImage(a), Jimp.read(comparePath), diff --git a/packages/server/test/support/fixtures/projects/empty-folders/cypress/plugins/.gitkeep b/packages/server/test/support/fixtures/projects/empty-folders/cypress/background/.gitkeep similarity index 100% rename from packages/server/test/support/fixtures/projects/empty-folders/cypress/plugins/.gitkeep rename to packages/server/test/support/fixtures/projects/empty-folders/cypress/background/.gitkeep diff --git a/packages/server/test/support/fixtures/projects/multiple-task-registrations/cypress/background/index.js b/packages/server/test/support/fixtures/projects/multiple-task-registrations/cypress/background/index.js new file mode 100644 index 000000000000..8c66f332da02 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/multiple-task-registrations/cypress/background/index.js @@ -0,0 +1,19 @@ +module.exports = (on) => { + on('task', { + 'one' () { + return 'one' + }, + 'two' () { + return 'two' + }, + }) + + on('task', { + 'two' () { + return 'two again' + }, + 'three' () { + return 'three' + }, + }) +} diff --git a/packages/server/test/support/fixtures/projects/multiple-task-registrations/cypress/plugins/index.js b/packages/server/test/support/fixtures/projects/multiple-task-registrations/cypress/plugins/index.js deleted file mode 100644 index 2979d06e965d..000000000000 --- a/packages/server/test/support/fixtures/projects/multiple-task-registrations/cypress/plugins/index.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = (on) => { - on('task', { - 'one' () { return 'one' }, - 'two' () { return 'two' }, - }) - - on('task', { - 'two' () { return 'two again' }, - 'three' () { return 'three' }, - }) -} diff --git a/packages/server/test/support/fixtures/projects/non-existent-spec/cypress/plugins/index.js b/packages/server/test/support/fixtures/projects/non-existent-spec/cypress/background/index.js similarity index 100% rename from packages/server/test/support/fixtures/projects/non-existent-spec/cypress/plugins/index.js rename to packages/server/test/support/fixtures/projects/non-existent-spec/cypress/background/index.js diff --git a/packages/server/test/support/fixtures/projects/task-not-registered/cypress/integration/task_not_registered_spec.coffee b/packages/server/test/support/fixtures/projects/task-not-registered/cypress/integration/task_not_registered_spec.coffee index 36c4bc6705ce..704129728aeb 100644 --- a/packages/server/test/support/fixtures/projects/task-not-registered/cypress/integration/task_not_registered_spec.coffee +++ b/packages/server/test/support/fixtures/projects/task-not-registered/cypress/integration/task_not_registered_spec.coffee @@ -1,2 +1,2 @@ -it "fails because the 'task' event is not registered in plugins file", -> +it "fails because the 'task' event is not registered in background file", -> cy.task("some:task") diff --git a/packages/server/test/support/fixtures/projects/todos/cypress.json b/packages/server/test/support/fixtures/projects/todos/cypress.json index c98ed7c0b3ac..dd656e084068 100644 --- a/packages/server/test/support/fixtures/projects/todos/cypress.json +++ b/packages/server/test/support/fixtures/projects/todos/cypress.json @@ -4,5 +4,5 @@ "supportFile": "tests/_support/spec_helper.js", "port": 8888, "projectId": "abc123", - "pluginsFile": false + "backgroundFile": false } diff --git a/packages/server/test/support/fixtures/projects/working-preprocessor/cypress/plugins/index.js b/packages/server/test/support/fixtures/projects/working-preprocessor/cypress/background/index.js similarity index 100% rename from packages/server/test/support/fixtures/projects/working-preprocessor/cypress/plugins/index.js rename to packages/server/test/support/fixtures/projects/working-preprocessor/cypress/background/index.js diff --git a/packages/server/test/support/fixtures/server/throws_error.coffee b/packages/server/test/support/fixtures/server/throws_error.coffee index b518660ca067..cb1f2b4bcb61 100644 --- a/packages/server/test/support/fixtures/server/throws_error.coffee +++ b/packages/server/test/support/fixtures/server/throws_error.coffee @@ -1 +1 @@ -throw new Error("error thrown by pluginsFile") +throw new Error("error thrown by backgroundFile") diff --git a/packages/server/test/unit/plugins/child/preprocessor_spec.coffee b/packages/server/test/unit/background/child/preprocessor_spec.coffee similarity index 94% rename from packages/server/test/unit/plugins/child/preprocessor_spec.coffee rename to packages/server/test/unit/background/child/preprocessor_spec.coffee index ea3a64145d0d..1d6b8d335e12 100644 --- a/packages/server/test/unit/plugins/child/preprocessor_spec.coffee +++ b/packages/server/test/unit/background/child/preprocessor_spec.coffee @@ -2,10 +2,10 @@ require("../../../spec_helper") EE = require('events') -util = require("#{root}../../lib/plugins/util") -preprocessor = require("#{root}../../lib/plugins/child/preprocessor") +util = require("#{root}../../lib/background/util") +preprocessor = require("#{root}../../lib/background/child/preprocessor") -describe "lib/plugins/child/preprocessor", -> +describe "lib/background/child/preprocessor", -> beforeEach -> @ipc = { send: sinon.spy() diff --git a/packages/server/test/unit/plugins/child/run_plugins_spec.coffee b/packages/server/test/unit/background/child/run_background_spec.coffee similarity index 59% rename from packages/server/test/unit/plugins/child/run_plugins_spec.coffee rename to packages/server/test/unit/background/child/run_background_spec.coffee index 8a030398dd35..40a818fa7a3c 100644 --- a/packages/server/test/unit/plugins/child/run_plugins_spec.coffee +++ b/packages/server/test/unit/background/child/run_background_spec.coffee @@ -4,10 +4,10 @@ _ = require("lodash") cp = require("child_process") snapshot = require("snap-shot-it") -preprocessor = require("#{root}../../lib/plugins/child/preprocessor") -task = require("#{root}../../lib/plugins/child/task") -runPlugins = require("#{root}../../lib/plugins/child/run_plugins") -util = require("#{root}../../lib/plugins/util") +preprocessor = require("#{root}../../lib/background/child/preprocessor") +task = require("#{root}../../lib/background/child/task") +runBackground = require("#{root}../../lib/background/child/run_background") +util = require("#{root}../../lib/background/util") Fixtures = require("#{root}../../test/support/helpers/fixtures") colorCodeRe = /\[[0-9;]+m/gm @@ -19,8 +19,12 @@ withoutColorCodes = (str) -> str.replace(colorCodeRe, "") withoutPath = (str) -> str.replace(pathRe, '$2)') withoutStackPaths = (stack) -> stack.replace(stackPathRe, '$2') -describe "lib/plugins/child/run_plugins", -> +describe "lib/background/child/run_background", -> beforeEach -> + @process = { + on: sinon.stub() + } + @ipc = { send: sinon.spy() on: sinon.stub() @@ -28,78 +32,80 @@ describe "lib/plugins/child/run_plugins", -> } afterEach -> - mockery.deregisterMock("plugins-file") - mockery.deregisterSubstitute("plugins-file") + mockery.deregisterMock("background-file") + mockery.deregisterSubstitute("background-file") - it "sends error message if pluginsFile is missing", -> - mockery.registerSubstitute("plugins-file", "/does/not/exist.coffee") - runPlugins(@ipc, "plugins-file") - expect(@ipc.send).to.be.calledWith("load:error", "PLUGINS_FILE_ERROR", "plugins-file") + it "sends error message if backgroundFile is missing", -> + mockery.registerSubstitute("background-file", "/does/not/exist.coffee") + runBackground(@process, @ipc, "background-file") + expect(@ipc.send).to.be.calledWith("load:error", "BACKGROUND_FILE_ERROR", "background-file") snapshot(withoutStackPaths(@ipc.send.lastCall.args[3])) - it "sends error message if requiring pluginsFile errors", -> - ## path for substitute is relative to lib/plugins/child/plugins_child.js + it "sends error message if requiring backgroundFile errors", -> + ## path for substitute is relative to lib/background/child/BACKGROUND_child.js mockery.registerSubstitute( - "plugins-file", + "background-file", Fixtures.path("server/throws_error.coffee") ) - runPlugins(@ipc, "plugins-file") - expect(@ipc.send).to.be.calledWith("load:error", "PLUGINS_FILE_ERROR", "plugins-file") + runBackground(@process, @ipc, "background-file") + expect(@ipc.send).to.be.calledWith("load:error", "BACKGROUND_FILE_ERROR", "background-file") snapshot(withoutStackPaths(@ipc.send.lastCall.args[3])) - it "sends error message if pluginsFile has syntax error", -> - ## path for substitute is relative to lib/plugins/child/plugins_child.js + it "sends error message if backgroundFile has syntax error", -> + ## path for substitute is relative to lib/background/child/BACKGROUND_child.js mockery.registerSubstitute( - "plugins-file", + "background-file", Fixtures.path("server/syntax_error.coffee") ) - runPlugins(@ipc, "plugins-file") - expect(@ipc.send).to.be.calledWith("load:error", "PLUGINS_FILE_ERROR", "plugins-file") + runBackground(@process, @ipc, "background-file") + expect(@ipc.send).to.be.calledWith("load:error", "BACKGROUND_FILE_ERROR", "background-file") snapshot(withoutColorCodes(withoutPath(@ipc.send.lastCall.args[3]))) - it "sends error message if pluginsFile does not export a function", -> - mockery.registerMock("plugins-file", null) - runPlugins(@ipc, "plugins-file") - expect(@ipc.send).to.be.calledWith("load:error", "PLUGINS_DIDNT_EXPORT_FUNCTION", "plugins-file") + it "sends error message if backgroundFile does not export a function", -> + mockery.registerMock("background-file", null) + runBackground(@process, @ipc, "background-file") + expect(@ipc.send).to.be.calledWith("load:error", "BACKGROUND_DIDNT_EXPORT_FUNCTION", "background-file") snapshot(JSON.stringify(@ipc.send.lastCall.args[3])) describe "on 'load' message", -> - it "sends error if pluginsFile function rejects the promise", (done) -> - err = new Error('foo') - pluginsFn = sinon.stub().rejects(err) + afterEach -> + @ipc.send = -> - mockery.registerMock("plugins-file", pluginsFn) + it "sends error if backgroundFile function rejects the promise", (done) -> + err = new Error('foo') + backgroundFn = sinon.stub().rejects(err) + mockery.registerMock("background-file", backgroundFn) @ipc.on.withArgs("load").yields({}) - runPlugins(@ipc, "plugins-file") + runBackground(@process, @ipc, "background-file") - @ipc.send = (event, errorType, pluginsFile, stack) -> + @ipc.send = (event, errorType, backgroundFile, stack) -> expect(event).to.eq("load:error") - expect(errorType).to.eq("PLUGINS_FUNCTION_ERROR") - expect(pluginsFile).to.eq("plugins-file") + expect(errorType).to.eq("BACKGROUND_FUNCTION_ERROR") + expect(backgroundFile).to.eq("background-file") expect(stack).to.eq(err.stack) done() - it "calls function exported by pluginsFile with register function and config", -> - pluginsFn = sinon.spy() - mockery.registerMock("plugins-file", pluginsFn) - runPlugins(@ipc, "plugins-file") + it "calls function exported by backgroundFile with register function and config", -> + backgroundFn = sinon.spy() + mockery.registerMock("background-file", backgroundFn) + runBackground(@process, @ipc, "background-file") config = {} @ipc.on.withArgs("load").yield(config) - expect(pluginsFn).to.be.called - expect(pluginsFn.lastCall.args[0]).to.be.a("function") - expect(pluginsFn.lastCall.args[1]).to.equal(config) + expect(backgroundFn).to.be.called + expect(backgroundFn.lastCall.args[0]).to.be.a("function") + expect(backgroundFn.lastCall.args[1]).to.equal(config) - it "sends error if pluginsFile function throws an error", (done) -> + it "sends error if backgroundFile function throws an error", (done) -> err = new Error('foo') - mockery.registerMock "plugins-file", -> throw err - runPlugins(@ipc, "plugins-file") + mockery.registerMock "background-file", -> throw err + runBackground(@process, @ipc, "background-file") @ipc.on.withArgs("load").yield() - @ipc.send = (event, errorType, pluginsFile, stack) -> + @ipc.send = (event, errorType, backgroundFile, stack) -> expect(event).to.eq("load:error") - expect(errorType).to.eq("PLUGINS_FUNCTION_ERROR") - expect(pluginsFile).to.eq("plugins-file") + expect(errorType).to.eq("BACKGROUND_FUNCTION_ERROR") + expect(backgroundFile).to.eq("background-file") expect(stack).to.eq(err.stack) done() @@ -109,12 +115,12 @@ describe "lib/plugins/child/run_plugins", -> @onFilePreprocessor = sinon.stub().resolves() @beforeBrowserLaunch = sinon.stub().resolves() @taskRequested = sinon.stub().resolves("foo") - pluginsFn = (register) => + backgroundFn = (register) => register("file:preprocessor", @onFilePreprocessor) register("before:browser:launch", @beforeBrowserLaunch) register("task", @taskRequested) - mockery.registerMock("plugins-file", pluginsFn) - runPlugins(@ipc, "plugins-file") + mockery.registerMock("background-file", backgroundFn) + runBackground(@process, @ipc, "background-file") @ipc.on.withArgs("load").yield() context "file:preprocessor", -> @@ -171,23 +177,22 @@ describe "lib/plugins/child/run_plugins", -> describe "errors", -> beforeEach -> - mockery.registerMock("plugins-file", ->) - sinon.stub(process, "on") + mockery.registerMock("background-file", ->) @err = { name: "error name" message: "error message" } - runPlugins(@ipc, "plugins-file") + runBackground(@process, @ipc, "background-file") it "sends the serialized error via ipc on process uncaughtException", -> - process.on.withArgs("uncaughtException").yield(@err) + @process.on.withArgs("uncaughtException").yield(@err) expect(@ipc.send).to.be.calledWith("error", @err) it "sends the serialized error via ipc on process unhandledRejection", -> - process.on.withArgs("unhandledRejection").yield(@err) + @process.on.withArgs("unhandledRejection").yield(@err) expect(@ipc.send).to.be.calledWith("error", @err) it "sends the serialized reason via ipc on process unhandledRejection", -> - process.on.withArgs("unhandledRejection").yield({ reason: @err }) + @process.on.withArgs("unhandledRejection").yield({ reason: @err }) expect(@ipc.send).to.be.calledWith("error", @err) diff --git a/packages/server/test/unit/plugins/child/task_spec.coffee b/packages/server/test/unit/background/child/task_spec.coffee similarity index 93% rename from packages/server/test/unit/plugins/child/task_spec.coffee rename to packages/server/test/unit/background/child/task_spec.coffee index 43013c655078..f4a1f6d4ae35 100644 --- a/packages/server/test/unit/plugins/child/task_spec.coffee +++ b/packages/server/test/unit/background/child/task_spec.coffee @@ -2,10 +2,10 @@ require("../../../spec_helper") EE = require('events') -util = require("#{root}../../lib/plugins/util") -task = require("#{root}../../lib/plugins/child/task") +util = require("#{root}../../lib/background/util") +task = require("#{root}../../lib/background/child/task") -describe "lib/plugins/child/task", -> +describe "lib/background/child/task", -> beforeEach -> @ipc = { send: sinon.spy() diff --git a/packages/server/test/unit/plugins/index_spec.coffee b/packages/server/test/unit/background/index_spec.coffee similarity index 52% rename from packages/server/test/unit/plugins/index_spec.coffee rename to packages/server/test/unit/background/index_spec.coffee index aecd6cb4d819..2243f82b60ed 100644 --- a/packages/server/test/unit/plugins/index_spec.coffee +++ b/packages/server/test/unit/background/index_spec.coffee @@ -2,19 +2,19 @@ require("../../spec_helper") cp = require("child_process") -util = require("#{root}../lib/plugins/util") -plugins = require("#{root}../lib/plugins") +util = require("#{root}../lib/background/util") +background = require("#{root}../lib/background") -describe "lib/plugins/index", -> +describe "lib/background/index", -> beforeEach -> - plugins._reset() + background._reset() - @pluginsProcess = { + @backgroundProcess = { send: sinon.spy() on: sinon.stub() kill: sinon.spy() } - sinon.stub(cp, "fork").returns(@pluginsProcess) + sinon.stub(cp, "fork").returns(@backgroundProcess) @ipc = { send: sinon.spy() @@ -23,41 +23,41 @@ describe "lib/plugins/index", -> sinon.stub(util, "wrapIpc").returns(@ipc) context "#init", -> - it "is noop if no pluginsFile", -> - plugins.init({}) ## doesn't reject or time out + it "is noop if no backgroundFile", -> + background.init({}) ## doesn't reject or time out it "forks child process", -> - plugins.init({ pluginsFile: "cypress-plugin" }) + background.init({ backgroundFile: "background-file" }) expect(cp.fork).to.be.called - expect(cp.fork.lastCall.args[0]).to.contain("plugins/child/index.js") - expect(cp.fork.lastCall.args[1]).to.eql(["--file", "cypress-plugin"]) + expect(cp.fork.lastCall.args[0]).to.contain("background/child/index.js") + expect(cp.fork.lastCall.args[1]).to.eql(["--file", "background-file"]) it "calls any handlers registered with the wrapped ipc", -> handler = sinon.spy() - plugins.registerHandler(handler) - plugins.init({ pluginsFile: "cypress-plugin" }) + background.registerHandler(handler) + background.init({ backgroundFile: "background-file" }) expect(handler).to.be.called expect(handler.lastCall.args[0].send).to.be.a("function") expect(handler.lastCall.args[0].on).to.be.a("function") it "sends config via ipc", -> @ipc.on.withArgs("loaded").yields([]) - config = { pluginsFile: "cypress-plugin" } - plugins.init(config).then => + config = { backgroundFile: "background-file" } + background.init(config).then => expect(@ipc.send).to.be.calledWith("load", config) it "resolves once it receives 'loaded' message", -> @ipc.on.withArgs("loaded").yields([]) ## should resolve and not time out - plugins.init({ pluginsFile: "cypress-plugin" }) + background.init({ backgroundFile: "background-file" }) it "kills child process if it already exists", -> @ipc.on.withArgs("loaded").yields([]) - plugins.init({ pluginsFile: "cypress-plugin" }) + background.init({ backgroundFile: "background-file" }) .then => - plugins.init({ pluginsFile: "cypress-plugin" }) + background.init({ backgroundFile: "background-file" }) .then => - expect(@pluginsProcess.kill).to.be.calledOnce + expect(@backgroundProcess.kill).to.be.calledOnce describe "loaded message", -> beforeEach -> @@ -67,12 +67,12 @@ describe "lib/plugins/index", -> event: "some:event" eventId: 0 }]) - plugins.init({ pluginsFile: "cypress-plugin" }) + background.init({ backgroundFile: "background-file" }) it "sends 'execute' message when event is executed, wrapped in promise", -> sinon.stub(util, "wrapParentPromise").resolves("value").yields("00") - plugins.execute("some:event", "foo", "bar").then (value) => + background.execute("some:event", "foo", "bar").then (value) => expect(util.wrapParentPromise).to.be.called expect(@ipc.send).to.be.calledWith( "execute", @@ -83,27 +83,27 @@ describe "lib/plugins/index", -> expect(value).to.equal("value") describe "load:error message", -> - context "PLUGINS_FILE_ERROR", -> + context "BACKGROUND_FILE_ERROR", -> beforeEach -> - @ipc.on.withArgs("load:error").yields("PLUGINS_FILE_ERROR", "path/to/pluginsFile.js", "error message stack") + @ipc.on.withArgs("load:error").yields("BACKGROUND_FILE_ERROR", "path/to/backgroundFile.js", "error message stack") - it "rejects plugins.init", -> - plugins.init({ pluginsFile: "cypress-plugin" }) + it "rejects background.init", -> + background.init({ backgroundFile: "background-file" }) .catch (err) => - expect(err.message).to.contain("The plugins file is missing or invalid") - expect(err.message).to.contain("path/to/pluginsFile.js") + expect(err.message).to.contain("The background file is missing or invalid") + expect(err.message).to.contain("path/to/backgroundFile.js") expect(err.message).to.contain("The following error was thrown") expect(err.message).to.contain("error message stack") - context "PLUGINS_FUNCTION_ERROR", -> + context "BACKGROUND_FUNCTION_ERROR", -> beforeEach -> - @ipc.on.withArgs("load:error").yields("PLUGINS_FUNCTION_ERROR", "path/to/pluginsFile.js", "error message stack") + @ipc.on.withArgs("load:error").yields("BACKGROUND_FUNCTION_ERROR", "path/to/backgroundFile.js", "error message stack") - it "rejects plugins.init", -> - plugins.init({ pluginsFile: "cypress-plugin" }) + it "rejects background.init", -> + background.init({ backgroundFile: "background-file" }) .catch (err) => - expect(err.message).to.contain("The function exported by the plugins file threw an error.") - expect(err.message).to.contain("path/to/pluginsFile.js") + expect(err.message).to.contain("The function exported by the background file threw an error.") + expect(err.message).to.contain("path/to/backgroundFile.js") expect(err.message).to.contain("The following error was thrown:") expect(err.message).to.contain("error message stack") @@ -115,54 +115,54 @@ describe "lib/plugins/index", -> } @onError = sinon.spy() @ipc.on.withArgs("loaded").yields([]) - plugins.init({ pluginsFile: "cypress-plugin" }, { onError: @onError }) + background.init({ backgroundFile: "background-file" }, { onError: @onError }) - it "kills the plugins process when plugins process errors", -> - @pluginsProcess.on.withArgs("error").yield(@err) - expect(@pluginsProcess.kill).to.be.called + it "kills the background process when background process errors", -> + @backgroundProcess.on.withArgs("error").yield(@err) + expect(@backgroundProcess.kill).to.be.called - it "kills the plugins process when ipc sends error", -> + it "kills the background process when ipc sends error", -> @ipc.on.withArgs("error").yield(@err) - expect(@pluginsProcess.kill).to.be.called + expect(@backgroundProcess.kill).to.be.called - it "calls onError when plugins process errors", -> - @pluginsProcess.on.withArgs("error").yield(@err) + it "calls onError when background process errors", -> + @backgroundProcess.on.withArgs("error").yield(@err) expect(@onError).to.be.called - expect(@onError.lastCall.args[0].title).to.equal("Error running plugin") - expect(@onError.lastCall.args[0].stack).to.include("The following error was thrown by a plugin") + expect(@onError.lastCall.args[0].title).to.equal("Error running background plugin") + expect(@onError.lastCall.args[0].stack).to.include("The following error was thrown by a plugin in the background process") expect(@onError.lastCall.args[0].stack).to.include(@err.message) it "calls onError when ipc sends error", -> @ipc.on.withArgs("error").yield(@err) expect(@onError).to.be.called - expect(@onError.lastCall.args[0].title).to.equal("Error running plugin") - expect(@onError.lastCall.args[0].stack).to.include("The following error was thrown by a plugin") + expect(@onError.lastCall.args[0].title).to.equal("Error running background plugin") + expect(@onError.lastCall.args[0].stack).to.include("The following error was thrown by a plugin in the background process") expect(@onError.lastCall.args[0].stack).to.include(@err.message) context "#register", -> it "registers callback for event", -> foo = sinon.spy() - plugins.register("foo", foo) - plugins.execute("foo") + background.register("foo", foo) + background.execute("foo") expect(foo).to.be.called it "throws if event is not a string", -> - expect(-> plugins.register()).to.throw("must be called with an event as its 1st argument") + expect(-> background.register()).to.throw("must be called with an event as its 1st argument") it "throws if callback is not a function", -> - expect(-> plugins.register("foo")).to.throw("must be called with a callback function as its 2nd argument") + expect(-> background.register("foo")).to.throw("must be called with a callback function as its 2nd argument") - context "#has", -> + context "#isRegistered", -> it "returns true when event has been registered", -> - plugins.register("foo", ->) - expect(plugins.has("foo")).to.be.true + background.register("foo", ->) + expect(background.isRegistered("foo")).to.be.true it "returns false when event has not been registered", -> - expect(plugins.has("foo")).to.be.false + expect(background.isRegistered("foo")).to.be.false context "#execute", -> it "calls the callback registered for the event", -> foo = sinon.spy() - plugins.register("foo", foo) - plugins.execute("foo", "arg1", "arg2") + background.register("foo", foo) + background.execute("foo", "arg1", "arg2") expect(foo).to.be.calledWith("arg1", "arg2") diff --git a/packages/server/test/unit/plugins/preprocessor_spec.coffee b/packages/server/test/unit/background/preprocessor_spec.coffee similarity index 93% rename from packages/server/test/unit/plugins/preprocessor_spec.coffee rename to packages/server/test/unit/background/preprocessor_spec.coffee index a5d83657a6b5..c4cabca99b98 100644 --- a/packages/server/test/unit/plugins/preprocessor_spec.coffee +++ b/packages/server/test/unit/background/preprocessor_spec.coffee @@ -7,10 +7,10 @@ snapshot = require("snap-shot-it") appData = require("#{root}../lib/util/app_data") { toHashName } = require("#{root}../lib/util/saved_state") -plugins = require("#{root}../lib/plugins") -preprocessor = require("#{root}../lib/plugins/preprocessor") +background = require("#{root}../lib/background") +preprocessor = require("#{root}../lib/background/preprocessor") -describe "lib/plugins/preprocessor", -> +describe "lib/background/preprocessor", -> beforeEach -> Fixtures.scaffold() @todosPath = Fixtures.projectPath("todos") @@ -23,7 +23,7 @@ describe "lib/plugins/preprocessor", -> @localPreprocessorPath = path.join(@todosPath, "prep.coffee") @plugin = sinon.stub().returns("/path/to/output.js") - plugins.register("file:preprocessor", @plugin) + background.register("file:preprocessor", @plugin) preprocessor.close() @@ -72,14 +72,14 @@ describe "lib/plugins/preprocessor", -> expect(@plugin).to.be.calledOnce it "uses default preprocessor if none registered", -> - plugins._reset() - sinon.stub(plugins, "register") - sinon.stub(plugins, "execute").returns(->) + background._reset() + sinon.stub(background, "register") + sinon.stub(background, "execute").returns(->) browserifyFn = -> browserify = sinon.stub().returns(browserifyFn) mockery.registerMock("@cypress/browserify-preprocessor", browserify) preprocessor.getFile(@filePath, @config) - expect(plugins.register).to.be.calledWith("file:preprocessor", browserifyFn) + expect(background.register).to.be.calledWith("file:preprocessor", browserifyFn) expect(browserify).to.be.called context "#removeFile", -> diff --git a/packages/server/test/unit/plugins/util_spec.coffee b/packages/server/test/unit/background/util_spec.coffee similarity index 98% rename from packages/server/test/unit/plugins/util_spec.coffee rename to packages/server/test/unit/background/util_spec.coffee index 268128fb0171..3c0d30664db5 100644 --- a/packages/server/test/unit/plugins/util_spec.coffee +++ b/packages/server/test/unit/background/util_spec.coffee @@ -2,9 +2,9 @@ require("../../spec_helper") Promise = require("bluebird") -util = require("#{root}../lib/plugins/util") +util = require("#{root}../lib/background/util") -describe "lib/plugins/util", -> +describe "lib/background/util", -> context "#wrapIpc", -> beforeEach -> diff --git a/packages/server/test/unit/browsers/chrome_spec.coffee b/packages/server/test/unit/browsers/chrome_spec.coffee index be273232e550..9a31fc073bf2 100644 --- a/packages/server/test/unit/browsers/chrome_spec.coffee +++ b/packages/server/test/unit/browsers/chrome_spec.coffee @@ -3,7 +3,7 @@ require("../../spec_helper") os = require("os") extension = require("@packages/extension") -plugins = require("#{root}../lib/plugins") +background = require("#{root}../lib/background") utils = require("#{root}../lib/browsers/utils") chrome = require("#{root}../lib/browsers/chrome") @@ -14,30 +14,30 @@ describe "lib/browsers/chrome", -> sinon.stub(chrome, "_getArgs").returns(@args) sinon.stub(chrome, "_writeExtension").resolves("/path/to/ext") - sinon.stub(plugins, "has") - sinon.stub(plugins, "execute") + sinon.stub(background, "isRegistered") + sinon.stub(background, "execute") sinon.stub(utils, "launch") sinon.stub(utils, "getProfileDir").returns("/profile/dir") sinon.stub(utils, "ensureCleanCache").resolves("/profile/dir/CypressCache") it "is noop without before:browser:launch", -> - plugins.has.returns(false) + background.isRegistered.returns(false) chrome.open("chrome", "http://", {}, {}) .then -> - expect(plugins.execute).not.to.be.called + expect(background.execute).not.to.be.called it "is noop if newArgs are not returned", -> - plugins.has.returns(true) - plugins.execute.resolves(null) + background.isRegistered.returns(true) + background.execute.resolves(null) chrome.open("chrome", "http://", {}, {}) .then => expect(utils.launch).to.be.calledWith("chrome", "http://", @args) - it "normalizes --load-extension if provided in plugin", -> - plugins.has.returns(true) - plugins.execute.resolves([ + it "normalizes --load-extension if provided in background file", -> + background.isRegistered.returns(true) + background.execute.resolves([ "--foo=bar", "--load-extension=/foo/bar/baz.js" ]) @@ -57,9 +57,9 @@ describe "lib/browsers/chrome", -> "--disk-cache-dir=/profile/dir/CypressCache" ]) - it "normalizes multiple extensions from plugins", -> - plugins.has.returns(true) - plugins.execute.resolves([ + it "normalizes multiple extensions from background", -> + background.isRegistered.returns(true) + background.execute.resolves([ "--foo=bar", "--load-extension=/foo/bar/baz.js,/quux.js" ]) diff --git a/packages/server/test/unit/browsers/electron_spec.coffee b/packages/server/test/unit/browsers/electron_spec.coffee index fecd63912581..ca2031677543 100644 --- a/packages/server/test/unit/browsers/electron_spec.coffee +++ b/packages/server/test/unit/browsers/electron_spec.coffee @@ -6,7 +6,7 @@ la = require("lazy-ass") check = require("check-more-types") menu = require("#{root}../lib/gui/menu") -plugins = require("#{root}../lib/plugins") +background = require("#{root}../lib/background") Windows = require("#{root}../lib/gui/windows") electron = require("#{root}../lib/browsers/electron") savedState = require("#{root}../lib/saved_state") @@ -40,8 +40,8 @@ describe "lib/browsers/electron", -> context ".open", -> beforeEach -> sinon.stub(electron, "_render").resolves(@win) - sinon.stub(plugins, "has") - sinon.stub(plugins, "execute") + sinon.stub(background, "isRegistered") + sinon.stub(background, "execute") savedState() .then (state) => @@ -80,8 +80,8 @@ describe "lib/browsers/electron", -> expect(@automation.use.lastCall.args[0].onRequest).to.be.a("function") it "is noop when before:browser:launch yields null", -> - plugins.has.returns(true) - plugins.execute.resolves(null) + background.isRegistered.returns(true) + background.execute.resolves(null) electron.open("electron", @url, @options, @automation) .then => @@ -91,8 +91,8 @@ describe "lib/browsers/electron", -> ## https://github.com/cypress-io/cypress/issues/1992 it "it merges in options without removing essential options", -> - plugins.has.returns(true) - plugins.execute.resolves({foo: "bar"}) + background.isRegistered.returns(true) + background.execute.resolves({foo: "bar"}) electron.open("electron", @url, @options, @automation) .then => diff --git a/packages/server/test/unit/config_spec.coffee b/packages/server/test/unit/config_spec.coffee index 371a133173eb..3e4b77f8484d 100644 --- a/packages/server/test/unit/config_spec.coffee +++ b/packages/server/test/unit/config_spec.coffee @@ -245,17 +245,17 @@ describe "lib/config", -> @setup({pageLoadTimeout: "foo"}) @expectValidationFails("be a number") - context "pluginsFile", -> + context "backgroundFile", -> it "passes if a string", -> - @setup({pluginsFile: "cypress/plugins"}) + @setup({backgroundFile: "cypress/background"}) @expectValidationPasses() it "passes if false", -> - @setup({pluginsFile: false}) + @setup({backgroundFile: false}) @expectValidationPasses() it "fails if not a string or false", -> - @setup({pluginsFile: 42}) + @setup({backgroundFile: 42}) @expectValidationFails("be a string") context "port", -> @@ -730,7 +730,7 @@ describe "lib/config", -> videoUploadOnPasses: { value: true, from: "default" } videosFolder: { value: "cypress/videos", from: "default" }, supportFile: { value: "cypress/support", from: "default" }, - pluginsFile: { value: "cypress/plugins", from: "default" }, + backgroundFile: { value: "cypress/background", from: "default" }, fixturesFolder: { value: "cypress/fixtures", from: "default" }, integrationFolder: { value: "cypress/integration", from: "default" }, screenshotsFolder: { value: "cypress/screenshots", from: "default" }, @@ -789,7 +789,7 @@ describe "lib/config", -> videoUploadOnPasses: { value: true, from: "default" } videosFolder: { value: "cypress/videos", from: "default" }, supportFile: { value: "cypress/support", from: "default" }, - pluginsFile: { value: "cypress/plugins", from: "default" }, + backgroundFile: { value: "cypress/background", from: "default" }, fixturesFolder: { value: "cypress/fixtures", from: "default" }, integrationFolder: { value: "cypress/integration", from: "default" }, screenshotsFolder: { value: "cypress/screenshots", from: "default" }, @@ -814,9 +814,9 @@ describe "lib/config", -> } }) - context ".updateWithPluginValues", -> + context ".updateWithBackgroundValues", -> it "is noop when no overrides", -> - expect(config.updateWithPluginValues({foo: 'bar'}, null)).to.deep.eq({ + expect(config.updateWithBackgroundValues({foo: 'bar'}, null)).to.deep.eq({ foo: 'bar' }) @@ -848,7 +848,7 @@ describe "lib/config", -> } } - expect(config.updateWithPluginValues(cfg, overrides)).to.deep.eq({ + expect(config.updateWithBackgroundValues(cfg, overrides)).to.deep.eq({ foo: "bar" baz: "baz" lol: 1234 @@ -859,12 +859,12 @@ describe "lib/config", -> } resolved: { foo: { value: "bar", from: "default" } - baz: { value: "baz", from: "plugin" } + baz: { value: "baz", from: "background" } lol: { value: 1234, from: "env" } env: { a: { value: "a", from: "config" } - b: { value: "bb", from: "plugin" } - c: { value: "c", from: "plugin" } + b: { value: "bb", from: "background" } + c: { value: "c", from: "background" } } } }) @@ -1041,56 +1041,56 @@ describe "lib/config", -> .catch (err) -> expect(err.message).to.include("The support file is missing or invalid.") - context ".setPluginsFile", -> - it "does nothing if pluginsFile is falsey", -> + context ".setBackgroundFile", -> + it "does nothing if backgroundFile is falsey", -> obj = { projectRoot: "/_test-output/path/to/project" } - config.setPluginsFile(obj) + config.setBackgroundFile(obj) .then (result) -> expect(result).to.eql(obj) - it "sets the pluginsFile to default index.js if does not exist", -> + it "sets the backgroundFile to default index.js if does not exist", -> projectRoot = path.join(process.cwd(), "test/support/fixtures/projects/no-scaffolding") obj = { projectRoot: projectRoot - pluginsFile: "#{projectRoot}/cypress/plugins" + backgroundFile: "#{projectRoot}/cypress/background" } - config.setPluginsFile(obj) + config.setBackgroundFile(obj) .then (result) -> expect(result).to.eql({ projectRoot: projectRoot - pluginsFile: "#{projectRoot}/cypress/plugins/index.js" + backgroundFile: "#{projectRoot}/cypress/background/index.js" }) - it "set the pluginsFile to false if it does not exist, plugins folder exists, and pluginsFile is the default", -> + it "set the backgroundFile to false if it does not exist, background folder exists, and backgroundFile is the default", -> projectRoot = path.join(process.cwd(), "test/support/fixtures/projects/empty-folders") obj = config.setAbsolutePaths({ projectRoot: projectRoot - pluginsFile: "#{projectRoot}/cypress/plugins" + backgroundFile: "#{projectRoot}/cypress/background" }) - config.setPluginsFile(obj) + config.setBackgroundFile(obj) .then (result) -> expect(result).to.eql({ projectRoot: projectRoot - pluginsFile: false + backgroundFile: false }) - it "throws error if pluginsFile is not default and does not exist", -> + it "throws error if backgroundFile is not default and does not exist", -> projectRoot = process.cwd() obj = { projectRoot: projectRoot - pluginsFile: "does/not/exist" + backgroundFile: "does/not/exist" } - config.setPluginsFile(obj) + config.setBackgroundFile(obj) .catch (err) -> - expect(err.message).to.include("The plugins file is missing or invalid.") + expect(err.message).to.include("The background file is missing or invalid.") context ".setParentTestsPaths", -> it "sets parentTestsFolder and parentTestsFolderDisplay", -> @@ -1148,7 +1148,7 @@ describe "lib/config", -> expect(config.setAbsolutePaths(obj)).to.deep.eq(obj) - ["fileServerFolder", "fixturesFolder", "integrationFolder", "unitFolder", "supportFile", "pluginsFile"].forEach (folder) -> + ["fileServerFolder", "fixturesFolder", "integrationFolder", "unitFolder", "supportFile", "backgroundFile"].forEach (folder) -> it "converts relative #{folder} to absolute path", -> obj = { diff --git a/packages/server/test/unit/open_project_spec.coffee b/packages/server/test/unit/open_project_spec.coffee index 4db1a000db15..d3e608238c86 100644 --- a/packages/server/test/unit/open_project_spec.coffee +++ b/packages/server/test/unit/open_project_spec.coffee @@ -3,7 +3,7 @@ require("../spec_helper") browsers = require("#{root}lib/browsers") Project = require("#{root}lib/project") openProject = require("#{root}lib/open_project") -preprocessor = require("#{root}lib/plugins/preprocessor") +preprocessor = require("#{root}lib/background/preprocessor") describe "lib/open_project", -> beforeEach -> diff --git a/packages/server/test/unit/project_spec.coffee b/packages/server/test/unit/project_spec.coffee index ebcbf1d20034..be18eabdb685 100644 --- a/packages/server/test/unit/project_spec.coffee +++ b/packages/server/test/unit/project_spec.coffee @@ -14,8 +14,8 @@ Server = require("#{root}lib/server") Project = require("#{root}lib/project") Automation = require("#{root}lib/automation") savedState = require("#{root}lib/saved_state") -preprocessor = require("#{root}lib/plugins/preprocessor") -plugins = require("#{root}lib/plugins") +preprocessor = require("#{root}lib/background/preprocessor") +background = require("#{root}lib/background") fs = require("#{root}lib/util/fs") settings = require("#{root}lib/util/settings") @@ -154,9 +154,9 @@ describe "lib/project", -> sinon.stub(@project, "getConfig").resolves(@config) sinon.stub(Server.prototype, "open").resolves([]) sinon.stub(Server.prototype, "reset") - sinon.stub(config, "updateWithPluginValues").returns(@config) - sinon.stub(scaffold, "plugins").resolves() - sinon.stub(plugins, "init").resolves() + sinon.stub(config, "updateWithBackgroundValues").returns(@config) + sinon.stub(scaffold, "background").resolves() + sinon.stub(background, "init").resolves() it "calls #watchSettingsAndStartWebsockets with options + config", -> opts = {changeEvents: false, onAutomationRequest: ->} @@ -177,24 +177,24 @@ describe "lib/project", -> @project.open(opts).then => expect(@project.getConfig).to.be.calledWith(opts) - it "initializes the plugins", -> + it "initializes the background", -> @project.open({}).then => - expect(plugins.init).to.be.called + expect(background.init).to.be.called - it "calls support.plugins with pluginsFile directory", -> + it "calls support.background with backgroundFile directory", -> @project.open({}).then => - expect(scaffold.plugins).to.be.calledWith(path.dirname(@config.pluginsFile)) + expect(scaffold.background).to.be.calledWith(path.dirname(@config.backgroundFile)) - it "calls options.onError with plugins error when there is a plugins error", -> + it "calls options.onError with background error when there is a background error", -> onError = sinon.spy() err = { - name: "plugin error name" - message: "plugin error message" + name: "background error name" + message: "background error message" } @project.open({ onError: onError }).then => - pluginsOnError = plugins.init.lastCall.args[1].onError - expect(pluginsOnError).to.be.a("function") - pluginsOnError(err) + backgroundOnError = background.init.lastCall.args[1].onError + expect(backgroundOnError).to.be.a("function") + backgroundOnError(err) expect(onError).to.be.calledWith(err) it "updates config.state when saved state changes", -> @@ -275,9 +275,9 @@ describe "lib/project", -> sinon.stub(scaffold, "integration").resolves() sinon.stub(scaffold, "fixture").resolves() sinon.stub(scaffold, "support").resolves() - sinon.stub(scaffold, "plugins").resolves() + sinon.stub(scaffold, "background").resolves() - @obj = {projectRoot: "pr", fixturesFolder: "ff", integrationFolder: "if", supportFolder: "sf", pluginsFile: "pf/index.js"} + @obj = {projectRoot: "pr", fixturesFolder: "ff", integrationFolder: "if", supportFolder: "sf", backgroundFile: "pf/index.js"} it "calls scaffold.integration with integrationFolder", -> @project.scaffold(@obj).then => @@ -291,10 +291,10 @@ describe "lib/project", -> @project.scaffold(@obj).then => expect(scaffold.support).to.be.calledWith(@obj.supportFolder) - it "does not call support.plugins if config.pluginsFile is falsey", -> - @obj.pluginsFile = false + it "does not call support.background if config.backgroundFile is falsey", -> + @obj.backgroundFile = false @project.scaffold(@obj).then => - expect(scaffold.plugins).not.to.be.called + expect(scaffold.background).not.to.be.called context "#watchSettings", -> beforeEach -> @@ -368,41 +368,41 @@ describe "lib/project", -> .catch (e) -> expect(e.message).to.include("The support file is missing or invalid.") - context "#watchPluginsFile", -> + context "#watchBackgroundFile", -> beforeEach -> sinon.stub(fs, "pathExists").resolves(true) @project = Project("/_test-output/path/to/project") @project.watchers = { watchTree: sinon.spy() } - sinon.stub(plugins, "init").resolves() + sinon.stub(background, "init").resolves() @config = { - pluginsFile: "/path/to/plugins-file" + backgroundFile: "/path/to/background-file" } - it "does nothing when {pluginsFile: false}", -> - @config.pluginsFile = false - @project.watchPluginsFile(@config).then => + it "does nothing when {backgroundFile: false}", -> + @config.backgroundFile = false + @project.watchBackgroundFile(@config).then => expect(@project.watchers.watchTree).not.to.be.called - it "does nothing if pluginsFile does not exist", -> + it "does nothing if backgroundFile does not exist", -> fs.pathExists.resolves(false) - @project.watchPluginsFile(@config).then => + @project.watchBackgroundFile(@config).then => expect(@project.watchers.watchTree).not.to.be.called - it "watches the pluginsFile", -> - @project.watchPluginsFile(@config).then => - expect(@project.watchers.watchTree).to.be.calledWith(@config.pluginsFile) + it "watches the backgroundFile", -> + @project.watchBackgroundFile(@config).then => + expect(@project.watchers.watchTree).to.be.calledWith(@config.backgroundFile) expect(@project.watchers.watchTree.lastCall.args[1]).to.be.an("object") expect(@project.watchers.watchTree.lastCall.args[1].onChange).to.be.a("function") - it "calls plugins.init when file changes", -> - @project.watchPluginsFile(@config).then => + it "calls background.init when file changes", -> + @project.watchBackgroundFile(@config).then => @project.watchers.watchTree.firstCall.args[1].onChange() - expect(plugins.init).to.be.calledWith(@config) + expect(background.init).to.be.calledWith(@config) - it "handles errors from calling plugins.init", (done) -> + it "handles errors from calling background.init", (done) -> error = {name: "foo", message: "foo"} - plugins.init.rejects(error) - @project.watchPluginsFile(@config, { + background.init.rejects(error) + @project.watchBackgroundFile(@config, { onError: (err) -> expect(err).to.eql(error) done() diff --git a/packages/server/test/unit/scaffold_spec.coffee b/packages/server/test/unit/scaffold_spec.coffee index 64dcc8a13eac..08bbca6859c6 100644 --- a/packages/server/test/unit/scaffold_spec.coffee +++ b/packages/server/test/unit/scaffold_spec.coffee @@ -198,48 +198,48 @@ describe "lib/scaffold", -> snapshot(commandsContents) snapshot(indexContents) - context ".plugins", -> + context ".background", -> beforeEach -> pristinePath = Fixtures.projectPath("pristine") config.get(pristinePath).then (@cfg) => - {@pluginsFile} = @cfg - @pluginsFolder = path.dirname(@pluginsFile) + {@backgroundFile} = @cfg + @backgroundFolder = path.dirname(@backgroundFile) - it "creates pluginsFile when pluginsFolder does not exist", -> + it "creates backgroundFile when backgroundFolder does not exist", -> ## first remove it - fs.removeAsync(@pluginsFolder) + fs.removeAsync(@backgroundFolder) .then => - scaffold.plugins(@pluginsFolder, @cfg) + scaffold.background(@backgroundFolder, @cfg) .then => - fs.readFileAsync(@pluginsFolder + "/index.js", "utf8") + fs.readFileAsync(@backgroundFolder + "/index.js", "utf8") .then (str) -> snapshot(str.split('`').join('')) - it "does not create any files if pluginsFile directory already exists", -> + it "does not create any files if backgroundFile directory already exists", -> ## first remove it - fs.removeAsync(@pluginsFolder) + fs.removeAsync(@backgroundFolder) .then => - ## create the pluginsFolder ourselves manually - fs.ensureDirAsync(@pluginsFolder) + ## create the backgroundFolder ourselves manually + fs.ensureDirAsync(@backgroundFolder) .then => ## now scaffold - scaffold.plugins(@pluginsFolder, @cfg) + scaffold.background(@backgroundFolder, @cfg) .then => - glob("**/*", {cwd: @pluginsFolder}) + glob("**/*", {cwd: @backgroundFolder}) .then (files) -> ## ensure no files exist expect(files.length).to.eq(0) - it "does not create any files if pluginsFile is not default", -> - @cfg.resolved.pluginsFile.from = "config" + it "does not create any files if backgroundFile is not default", -> + @cfg.resolved.backgroundFile.from = "config" - it "does not create any files if pluginsFile is false", -> - @cfg.pluginsFile = false + it "does not create any files if backgroundFile is false", -> + @cfg.backgroundFile = false - scaffold.plugins(@pluginsFile, @cfg) + scaffold.background(@backgroundFile, @cfg) .then => - glob("**/*", {cwd: @pluginsFile}) + glob("**/*", {cwd: @backgroundFile}) .then (files) -> expect(files.length).to.eq(0) @@ -307,7 +307,7 @@ describe "lib/scaffold", -> beforeEach -> todosPath = Fixtures.projectPath("todos") config.get(todosPath).then (@cfg) => - @cfg.pluginsFile = path.join(@cfg.projectRoot, "cypress/plugins/index.js") + @cfg.backgroundFile = path.join(@cfg.projectRoot, "cypress/background/index.js") it "returns tree-like structure of scaffolded", -> snapshot(scaffold.fileTree(@cfg)) @@ -320,6 +320,6 @@ describe "lib/scaffold", -> @cfg.supportFile = false snapshot(scaffold.fileTree(@cfg)) - it "leaves out plugins if configured to false", -> - @cfg.pluginsFile = false + it "leaves out background if configured to false", -> + @cfg.backgroundFile = false snapshot(scaffold.fileTree(@cfg)) diff --git a/packages/server/test/unit/screenshots_spec.coffee b/packages/server/test/unit/screenshots_spec.coffee index d27c11cf8266..68800cae3adb 100644 --- a/packages/server/test/unit/screenshots_spec.coffee +++ b/packages/server/test/unit/screenshots_spec.coffee @@ -11,7 +11,7 @@ config = require("#{root}lib/config") screenshots = require("#{root}lib/screenshots") fs = require("#{root}lib/util/fs") settings = require("#{root}lib/util/settings") -plugins = require("#{root}lib/plugins") +background = require("#{root}lib/background") screenshotAutomation = require("#{root}lib/automation/screenshot") image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALlJREFUeNpi1F3xYAIDA4MBA35wgQWqyB5dRoaVmeHJ779wPhOM0aQtyBAoyglmOwmwM6z1lWY44CMDFgcBFmRTGp3EGGJe/WIQ5mZm4GRlBGJmhlm3PqGaeODpNzCtKsbGIARUCALvvv6FWw9XeOvrH4bbQNOQwfabnzHdGK3AwyAjyAqX2HPzC0Pn7Y9wPtyNIMGlD74wmAqwMZz+8AvFxzATVZAFQIqwABWQiWtgAY5uCnKAAwQYAPr8OZysiz4PAAAAAElFTkSuQmCC" @@ -518,11 +518,11 @@ describe "lib/screenshots", -> path: "/path/to/my-screenshot.png" } - sinon.stub(plugins, "has") - sinon.stub(plugins, "execute") + sinon.stub(background, "isRegistered") + sinon.stub(background, "execute") - it "resolves whitelisted details if no after:screenshot plugin registered", -> - plugins.has.returns(false) + it "resolves whitelisted details if no after:screenshot event registered", -> + background.isRegistered.returns(false) screenshots.afterScreenshot(@data, @details).then (result) => expect(_.omit(result, "duration")).to.eql({ @@ -540,9 +540,9 @@ describe "lib/screenshots", -> }) expect(result.duration).to.be.a("number") - it "executes after:screenshot plugin and merges in size, dimensions, and/or path", -> - plugins.has.returns(true) - plugins.execute.resolves({ + it "executes after:screenshot event and merges in size, dimensions, and/or path", -> + background.isRegistered.returns(true) + background.execute.resolves({ size: 200 dimensions: { width: 2000, height: 1320 } path: "/new/path/to/screenshot.png" @@ -567,7 +567,7 @@ describe "lib/screenshots", -> expect(result.duration).to.be.a("number") it "ignores updates that are not an object", -> - plugins.execute.resolves("foo") + background.execute.resolves("foo") screenshots.afterScreenshot(@data, @details).then (result) => expect(_.omit(result, "duration")).to.eql({ diff --git a/packages/server/test/unit/socket_spec.coffee b/packages/server/test/unit/socket_spec.coffee index 064d8bcb706b..6f671d9e8562 100644 --- a/packages/server/test/unit/socket_spec.coffee +++ b/packages/server/test/unit/socket_spec.coffee @@ -15,7 +15,7 @@ Server = require("#{root}lib/server") Automation = require("#{root}lib/automation") exec = require("#{root}lib/exec") savedState = require("#{root}lib/saved_state") -preprocessor = require("#{root}lib/plugins/preprocessor") +preprocessor = require("#{root}lib/background/preprocessor") fs = require("#{root}lib/util/fs") open = require("#{root}lib/util/open") Fixtures = require("#{root}/test/support/helpers/fixtures") diff --git a/packages/server/test/unit/spec_spec.coffee b/packages/server/test/unit/spec_spec.coffee index 8c2283362ce3..622ff4950459 100644 --- a/packages/server/test/unit/spec_spec.coffee +++ b/packages/server/test/unit/spec_spec.coffee @@ -3,7 +3,7 @@ require("../spec_helper") _ = require("lodash") path = require("path") spec = require("#{root}lib/controllers/spec") -preprocessor = require("#{root}lib/plugins/preprocessor") +preprocessor = require("#{root}lib/background/preprocessor") errors = require("#{root}lib/errors") describe "lib/controllers/spec", -> diff --git a/packages/server/test/unit/task_spec.coffee b/packages/server/test/unit/task_spec.coffee index 59b1f0c2e80c..1d82ded87590 100644 --- a/packages/server/test/unit/task_spec.coffee +++ b/packages/server/test/unit/task_spec.coffee @@ -2,51 +2,51 @@ require("../spec_helper") _ = require("lodash") Promise = require("bluebird") -plugins = require("#{root}lib/plugins") +background = require("#{root}lib/background") task = require("#{root}lib/task") fail = (message) -> throw new Error(message) describe "lib/task", -> beforeEach -> - @pluginsFile = "cypress/plugins" - sinon.stub(plugins, "execute").resolves("result") - sinon.stub(plugins, "has").returns(true) + @backgroundFile = "cypress/background" + sinon.stub(background, "execute").resolves("result") + sinon.stub(background, "isRegistered").returns(true) - it "executes the 'task' plugin", -> - task.run(@pluginsFile, { task: "some:task", arg: "some:arg", timeout: 1000 }).then -> - expect(plugins.execute).to.be.calledWith("task", "some:task", "some:arg") + it "executes the 'task' event", -> + task.run(@backgroundFile, { task: "some:task", arg: "some:arg", timeout: 1000 }).then -> + expect(background.execute).to.be.calledWith("task", "some:task", "some:arg") - it "resolves the result of the 'task' plugin", -> - task.run(@pluginsFile, { task: "some:task", arg: "some:arg", timeout: 1000 }).then (result) -> + it "resolves the result of the 'task' event", -> + task.run(@backgroundFile, { task: "some:task", arg: "some:arg", timeout: 1000 }).then (result) -> expect(result).to.equal("result") it "throws if 'task' event is not registered", -> - plugins.has.returns(false) + background.isRegistered.returns(false) - task.run(@pluginsFile, { timeout: 1000 }).catch (err) => - expect(err.message).to.equal("The 'task' event has not been registered in the plugins file. You must register it before using cy.task()\n\nFix this in your plugins file here:\n#{@pluginsFile}\n\nhttps://on.cypress.io/api/task") + task.run(@backgroundFile, { timeout: 1000 }).catch (err) => + expect(err.message).to.equal("The 'task' event has not been registered in the background file. You must register it before using cy.task()\n\nFix this in your background file here:\n#{@backgroundFile}\n\nhttps://on.cypress.io/api/task") it "throws if 'task' event resolves __cypress_unhandled__", -> - plugins.execute.withArgs("task").resolves("__cypress_unhandled__") - plugins.execute.withArgs("_get:task:keys").resolves(["foo", "bar"]) - task.run(@pluginsFile, { task: "some:task", arg: "some:arg", timeout: 1000 }).catch (err) => - expect(err.message).to.equal("The task 'some:task' was not handled in the plugins file. The following tasks are registered: foo, bar\n\nFix this in your plugins file here:\n#{@pluginsFile}\n\nhttps://on.cypress.io/api/task") + background.execute.withArgs("task").resolves("__cypress_unhandled__") + background.execute.withArgs("_get:task:keys").resolves(["foo", "bar"]) + task.run(@backgroundFile, { task: "some:task", arg: "some:arg", timeout: 1000 }).catch (err) => + expect(err.message).to.equal("The task 'some:task' was not handled in the background file. The following tasks are registered: foo, bar\n\nFix this in your background file here:\n#{@backgroundFile}\n\nhttps://on.cypress.io/api/task") it "throws if 'task' event resolves undefined", -> - plugins.execute.withArgs("task").resolves(undefined) - plugins.execute.withArgs("_get:task:body").resolves("function () {}") - task.run(@pluginsFile, { task: "some:task", arg: "some:arg", timeout: 1000 }).catch (err) => - expect(err.message).to.equal("The task 'some:task' returned undefined. You must return a promise, a value, or null to indicate that the task was handled.\n\nThe task handler was:\n\nfunction () {}\n\nFix this in your plugins file here:\n#{@pluginsFile}\n\nhttps://on.cypress.io/api/task") + background.execute.withArgs("task").resolves(undefined) + background.execute.withArgs("_get:task:body").resolves("function () {}") + task.run(@backgroundFile, { task: "some:task", arg: "some:arg", timeout: 1000 }).catch (err) => + expect(err.message).to.equal("The task 'some:task' returned undefined. You must return a promise, a value, or null to indicate that the task was handled.\n\nThe task handler was:\n\nfunction () {}\n\nFix this in your background file here:\n#{@backgroundFile}\n\nhttps://on.cypress.io/api/task") it "throws if 'task' event resolves undefined - without task body", -> - plugins.execute.withArgs("task").resolves(undefined) - plugins.execute.withArgs("_get:task:body").resolves("") - task.run(@pluginsFile, { task: "some:task", arg: "some:arg", timeout: 1000 }).catch (err) => - expect(err.message).to.equal("The task 'some:task' returned undefined. You must return a promise, a value, or null to indicate that the task was handled.\n\nFix this in your plugins file here:\n#{@pluginsFile}\n\nhttps://on.cypress.io/api/task") + background.execute.withArgs("task").resolves(undefined) + background.execute.withArgs("_get:task:body").resolves("") + task.run(@backgroundFile, { task: "some:task", arg: "some:arg", timeout: 1000 }).catch (err) => + expect(err.message).to.equal("The task 'some:task' returned undefined. You must return a promise, a value, or null to indicate that the task was handled.\n\nFix this in your background file here:\n#{@backgroundFile}\n\nhttps://on.cypress.io/api/task") it "throws if it times out", -> - plugins.execute.withArgs("task").resolves(Promise.delay(250)) - plugins.execute.withArgs("_get:task:body").resolves("function () {}") - task.run(@pluginsFile, { task: "some:task", arg: "some:arg", timeout: 10 }).catch (err) => - expect(err.message).to.equal("The task handler was:\n\nfunction () {}\n\nFix this in your plugins file here:\n#{@pluginsFile}\n\nhttps://on.cypress.io/api/task") + background.execute.withArgs("task").resolves(Promise.delay(250)) + background.execute.withArgs("_get:task:body").resolves("function () {}") + task.run(@backgroundFile, { task: "some:task", arg: "some:arg", timeout: 10 }).catch (err) => + expect(err.message).to.equal("The task handler was:\n\nfunction () {}\n\nFix this in your background file here:\n#{@backgroundFile}\n\nhttps://on.cypress.io/api/task") From a5bd2f66f52c5a0e0036c41eb03591b266e1a6f7 Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Mon, 3 Dec 2018 14:31:45 -0500 Subject: [PATCH 03/37] Upgrade mocha to latest version (5.2.0) (#2703) Closes #2528 --- packages/driver/package.json | 2 +- packages/driver/src/cypress.coffee | 4 - packages/driver/src/cypress/cy.coffee | 12 +- .../driver/src/cypress/error_messages.coffee | 11 ++ packages/driver/src/cypress/mocha.coffee | 6 +- packages/driver/src/cypress/runner.coffee | 150 +++++++----------- .../integration/cypress/cypress_spec.coffee | 4 +- .../integration/e2e/promises_spec.coffee | 4 +- .../integration/e2e/return_value_spec.coffee | 24 +++ .../test/unit_old/cypress/mocha_spec.coffee | 16 -- .../test/unit_old/cypress/runner_spec.coffee | 25 --- .../1_commands_outside_of_test_spec.coffee.js | 2 + .../__snapshots__/3_only_spec.coffee.js | 45 +++++- .../4_return_value_spec.coffee.js | 36 +++-- packages/server/test/e2e/3_only_spec.coffee | 2 +- .../test/e2e/4_return_value_spec.coffee | 2 +- .../integration/only_multiple_spec.coffee | 13 ++ .../integration/return_value_spec.coffee | 6 +- 18 files changed, 199 insertions(+), 165 deletions(-) create mode 100644 packages/server/test/support/fixtures/projects/e2e/cypress/integration/only_multiple_spec.coffee diff --git a/packages/driver/package.json b/packages/driver/package.json index 2964423657ee..7b02c6f8b489 100644 --- a/packages/driver/package.json +++ b/packages/driver/package.json @@ -49,7 +49,7 @@ "method-override": "^2.3.1", "minimatch": "^3.0.0", "minimist": "^1.2.0", - "mocha": "cypress-io/mocha#58f6eac05e664fc6b69aa9fba70f1f6b5531a900", + "mocha": "5.2.0", "moment": "^2.14.1", "morgan": "^1.3.0", "npm-install-version": "^6.0.2", diff --git a/packages/driver/src/cypress.coffee b/packages/driver/src/cypress.coffee index 584de63b42ac..e522abfef4c8 100644 --- a/packages/driver/src/cypress.coffee +++ b/packages/driver/src/cypress.coffee @@ -143,10 +143,6 @@ class $Cypress @action("cypress:config", config) initialize: ($autIframe) -> - ## push down the options - ## to the runner - @mocha.options(@runner) - @cy.initialize($autIframe) run: (fn) -> diff --git a/packages/driver/src/cypress/cy.coffee b/packages/driver/src/cypress/cy.coffee index 8a80eda2abee..2f6b7ad2d7d4 100644 --- a/packages/driver/src/cypress/cy.coffee +++ b/packages/driver/src/cypress/cy.coffee @@ -1054,9 +1054,15 @@ create = (specWindow, Cypress, Cookies, state, config, log) -> ## if we're cy or we've enqueued commands if isCy(ret) or (queue.length > currentLength) - ## the run should already be kicked off - ## by now and return this promise - return state("promise") + if fn.length + ## if user has passed done callback + ## don't return anything so we don't get an + ## 'overspecified' error from mocha + return + else + ## otherwise, return the 'queue promise' + ## so mocha awaits it + return state("promise") ## else just return ret return ret diff --git a/packages/driver/src/cypress/error_messages.coffee b/packages/driver/src/cypress/error_messages.coffee index ec5dbc9a63db..d498a3ff38ac 100644 --- a/packages/driver/src/cypress/error_messages.coffee +++ b/packages/driver/src/cypress/error_messages.coffee @@ -470,6 +470,17 @@ module.exports = { async_timed_out: "Timed out after '{{ms}}ms'. The done() callback was never invoked!" invalid_interface: "Invalid mocha interface '{{name}}'" timed_out: "Cypress command timeout of '{{ms}}ms' exceeded." + overspecified: """ + Cypress detected that you returned a promise in a test, but also invoked a done callback. Return a promise -or- invoke a done callback, not both. + + Read more here: https://on.cypress.io/returning-promise-and-invoking-done-callback + + #{divider(60, '-')} + + Original mocha error: + + {{error}} + """ navigation: cross_origin: """ diff --git a/packages/driver/src/cypress/mocha.coffee b/packages/driver/src/cypress/mocha.coffee index 21df770d7629..aabb7a210a0e 100644 --- a/packages/driver/src/cypress/mocha.coffee +++ b/packages/driver/src/cypress/mocha.coffee @@ -99,6 +99,9 @@ patchRunnerFail = -> ## matching the current Runner.prototype.fail except ## changing the logic for determing whether this is a valid err Runner::fail = (runnable, err) -> + if err?.message?.indexOf("Resolution method is overspecified") > -1 + err.message = $utils.errMessageByPath("mocha.overspecified", { error: err.stack }) + ## if this isnt a correct error object then just bail ## and call the original function if Object.prototype.toString.call(err) isnt "[object Error]" @@ -189,9 +192,6 @@ create = (specWindow, Cypress, reporter) -> getRootSuite: -> _mocha.suite - - options: (runner) -> - runner.options(_mocha.options) } module.exports = { diff --git a/packages/driver/src/cypress/runner.coffee b/packages/driver/src/cypress/runner.coffee index 15a96379d89c..d375c9f80a9a 100644 --- a/packages/driver/src/cypress/runner.coffee +++ b/packages/driver/src/cypress/runner.coffee @@ -6,7 +6,6 @@ Pending = require("mocha/lib/pending") $Log = require("./log") $utils = require("./utils") -defaultGrepRe = /.*/ mochaCtxKeysRe = /^(_runnable|test)$/ betweenQuotesRe = /\"(.+?)\"/ @@ -193,7 +192,7 @@ getAllSiblingTests = (suite, getTestById) -> ## iterate through each of our suites tests. ## this will iterate through all nested tests ## as well. and then we add it only if its - ## in our grepp'd tests array + ## in our filtered tests array if getTestById(test.id) tests.push test @@ -212,7 +211,7 @@ getTestFromHook = (hook, suite, getTestById) -> return found if found ## returns us the very first test - ## which is in our grepped tests array + ## which is in our filtered tests array ## based on walking down the current suite ## iterating through each test until it matches found = onFirstTest suite, (test) => @@ -227,11 +226,11 @@ getTestFromHook = (hook, suite, getTestById) -> ## we have to see if this is the last suite amongst ## its siblings. but first we have to filter out -## suites which dont have a grep'd test in them +## suites which dont have a filtered test in them isLastSuite = (suite, tests) -> return false if suite.root - ## grab all of the suites from our grep'd tests + ## grab all of the suites from our filtered tests ## including all of their ancestor suites! suites = _.reduce tests, (memo, test) -> while parent = test.parent @@ -296,17 +295,17 @@ overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, getTests) when "afterEach" t = getTest() - ## find all of the grep'd _tests which share + ## find all of the filtered _tests which share ## the same parent suite as our current _test tests = getAllSiblingTests(t.parent, getTestById) ## make sure this test isnt the last test overall but also - ## isnt the last test in our grep'd parent suite's tests array + ## isnt the last test in our filtered parent suite's tests array if @suite.root and (t isnt _.last(allTests)) and (t isnt _.last(tests)) changeFnToRunAfterHooks() when "afterAll" - ## find all of the grep'd allTests which share + ## find all of the filtered allTests which share ## the same parent suite as our current _test if t = getTest() siblings = getAllSiblingTests(t.parent, getTestById) @@ -327,17 +326,6 @@ overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, getTests) _runnerHook.call(@, name, fn) -matchesGrep = (runnable, grep) -> - ## we have optimized this iteration to the maximum. - ## we memoize the existential matchesGrep property - ## so we dont regex again needlessly when going - ## through tests which have already been set earlier - if (not runnable.matchesGrep?) or (not _.isEqual(runnable.grepRe, grep)) - runnable.grepRe = grep - runnable.matchesGrep = grep.test(runnable.fullTitle()) - - runnable.matchesGrep - getTestResults = (tests) -> _.map tests, (test) -> obj = _.pick(test, "id", "duration", "state") @@ -347,7 +335,12 @@ getTestResults = (tests) -> obj.state = "skipped" obj -normalizeAll = (suite, initialTests = {}, grep, setTestsById, setTests, onRunnable, onLogsById, getTestId) -> +hasOnly = (suite) -> + suite._onlyTests.length or + suite._onlySuites.length or + _.some(suite.suites, hasOnly) + +normalizeAll = (suite, initialTests = {}, setTestsById, setTests, onRunnable, onLogsById, getTestId) -> hasTests = false ## only loop until we find the first test @@ -361,10 +354,8 @@ normalizeAll = (suite, initialTests = {}, grep, setTestsById, setTests, onRunnab ## we hand back a normalized object but also ## create optimized lookups for the tests without ## traversing through it multiple times - tests = {} - grepIsDefault = _.isEqual(grep, defaultGrepRe) - - obj = normalize(suite, tests, initialTests, grep, grepIsDefault, onRunnable, onLogsById, getTestId) + tests = {} + normalizedSuite = normalize(suite, tests, initialTests, onRunnable, onLogsById, getTestId) if setTestsById ## use callback here to hand back @@ -375,10 +366,10 @@ normalizeAll = (suite, initialTests = {}, grep, setTestsById, setTests, onRunnab ## same pattern here setTests(_.values(tests)) - return obj + return normalizedSuite -normalize = (runnable, tests, initialTests, grep, grepIsDefault, onRunnable, onLogsById, getTestId) -> - normalizer = (runnable) => +normalize = (runnable, tests, initialTests, onRunnable, onLogsById, getTestId) -> + normalizeRunnable = (runnable) => runnable.id = getTestId() ## tests have a type of 'test' whereas suites do not have a type property @@ -402,57 +393,50 @@ normalize = (runnable, tests, initialTests, grep, grepIsDefault, onRunnable, onL push = (test) => tests[test.id] ?= test - obj = normalizer(runnable) + normalizedRunnable = normalizeRunnable(runnable) - ## if we have a default grep then avoid - ## grepping altogether and just push - ## tests into the array of tests - if grepIsDefault + if runnable.type isnt "suite" or not hasOnly(runnable) if runnable.type is "test" push(runnable) - ## and recursively iterate and normalize all other _runnables - _.each {tests: runnable.tests, suites: runnable.suites}, (_runnables, key) => - if runnable[key] - obj[key] = _.map _runnables, (runnable) => - normalize(runnable, tests, initialTests, grep, grepIsDefault, onRunnable, onLogsById, getTestId) - else - ## iterate through all tests and only push them in - ## if they match the current grep - obj.tests = _.reduce runnable.tests ? [], (memo, test) => - ## only push in the test if it matches - ## our grep - if matchesGrep(test, grep) - memo.push(normalizer(test)) - push(test) - memo - , [] - - ## and go through the suites - obj.suites = _.reduce runnable.suites ? [], (memo, suite) => - ## but only add them if a single nested test - ## actually matches the grep - any = anyTestInSuite suite, (test) => - matchesGrep(test, grep) - - if any - memo.push( - normalize( - suite, - tests, - initialTests, - grep, - grepIsDefault, - onRunnable, - onLogsById, - getTestId - ) - ) - - memo - , [] - - return obj + ## recursively iterate and normalize all other _runnables + _.each {tests: runnable.tests, suites: runnable.suites}, (_runnables, type) => + if runnable[type] + normalizedRunnable[type] = _.map _runnables, (runnable) => + normalize(runnable, tests, initialTests, onRunnable, onLogsById, getTestId) + + return normalizedRunnable + + ## this follows how mocha filters onlys. its runner#filterOnly + ## is pretty much the same minus the normalization part + filterOnly = (normalizedSuite, suite) -> + if suite._onlyTests.length + suite.tests = suite._onlyTests + normalizedSuite.tests = _.map suite._onlyTests, (test) => + normalizedTest = normalizeRunnable(test, initialTests, onRunnable, onLogsById, getTestId) + push(normalizedTest) + normalizedTest + suite.suites = [] + normalizedSuite.suites = [] + else + suite.tests = [] + normalizedSuite.tests = [] + _.each suite._onlySuites, (onlySuite) -> + normalizedOnlySuite = normalizeRunnable(onlySuite, initialTests, onRunnable, onLogsById, getTestId) + if hasOnly(onlySuite) + filterOnly(normalizedOnlySuite, onlySuite) + + suite.suites = _.filter suite.suites, (childSuite) -> + normalizedChildSuite = normalizeRunnable(childSuite, initialTests, onRunnable, onLogsById, getTestId) + suite._onlySuites.indexOf(childSuite) isnt -1 or filterOnly(normalizedChildSuite, childSuite) + normalizedSuite.suites = _.map suite.suites, (childSuite) -> + normalize(childSuite, tests, initialTests, onRunnable, onLogsById, getTestId) + + return suite.tests.length or suite.suites.length + + filterOnly(normalizedRunnable, runnable) + + return normalizedRunnable afterEachFailed = (Cypress, test, err) -> test.state = "failed" @@ -717,23 +701,6 @@ create = (specWindow, mocha, Cypress, cy) -> overrideRunnerHook(Cypress, _runner, getTestById, getTest, setTest, getTests) return { - grep: (re) -> - if arguments.length - _runner._grep = re - else - ## grab grep from the mocha _runner - ## or just set it to all in case - ## there is a mocha regression - _runner._grep ?= defaultGrepRe - - options: (options = {}) -> - ## TODO - ## need to handle - ## ignoreLeaks, asyncOnly, globals - - if re = options.grep - @grep(re) - normalizeAll: (tests) -> ## if we have an uncaught error then slice out ## all of the tests and suites and just generate @@ -750,7 +717,6 @@ create = (specWindow, mocha, Cypress, cy) -> normalizeAll( _runner.suite, tests, - @grep(), setTestsById, setTests, onRunnable, diff --git a/packages/driver/test/cypress/integration/cypress/cypress_spec.coffee b/packages/driver/test/cypress/integration/cypress/cypress_spec.coffee index d8b51dd1b2b4..a2d89ce5548c 100644 --- a/packages/driver/test/cypress/integration/cypress/cypress_spec.coffee +++ b/packages/driver/test/cypress/integration/cypress/cypress_spec.coffee @@ -29,7 +29,7 @@ describe "driver/src/cypress/index", -> expect($el.get(0)).to.eq($foo.get(0)) context "#backend", -> - it "sets __stackCleaned__ on errors", (done) -> + it "sets __stackCleaned__ on errors", -> cy.stub(@Cypress, "emit") .withArgs("backend:request") .yieldsAsync({ @@ -45,8 +45,6 @@ describe "driver/src/cypress/index", -> expect(err.backend).to.be.true expect(err.stack).not.to.include("From previous event") - done() - context "Log", -> it "throws when using Cypress.Log.command()", -> fn = -> diff --git a/packages/driver/test/cypress/integration/e2e/promises_spec.coffee b/packages/driver/test/cypress/integration/e2e/promises_spec.coffee index cd165e95aec7..cbfcd7f286c9 100644 --- a/packages/driver/test/cypress/integration/e2e/promises_spec.coffee +++ b/packages/driver/test/cypress/integration/e2e/promises_spec.coffee @@ -106,7 +106,7 @@ describe "promises", -> cy.foo() - it "can return a promise that throws on its own without warning", (done) -> + it "can return a promise that throws on its own without warning", -> Cypress.Promise .delay(10) .then -> @@ -116,7 +116,6 @@ describe "promises", -> throw new Error("foo") .catch -> - done() it "can still fail cypress commands", (done) -> cy.on "fail", (err) -> @@ -128,3 +127,4 @@ describe "promises", -> .then -> cy.wrap({}).then -> throw new Error("foo") + return diff --git a/packages/driver/test/cypress/integration/e2e/return_value_spec.coffee b/packages/driver/test/cypress/integration/e2e/return_value_spec.coffee index 9a10b99e8776..1513bf7820ba 100644 --- a/packages/driver/test/cypress/integration/e2e/return_value_spec.coffee +++ b/packages/driver/test/cypress/integration/e2e/return_value_spec.coffee @@ -16,6 +16,10 @@ describe "return values", -> return undefined + it "can return cy and have done callback", (done) -> + cy.wrap({}).then -> + done() + it "throws when returning a non promise and invoking cy commands", (done) -> cy.on "fail", (err) -> expect(err.message).to.include("> foo") @@ -91,3 +95,23 @@ describe "return values", -> return "bar" cy.foo() + + describe "without invoking cy", -> + it "handles returning undefined", -> + return undefined + + it "handles synchronously invoking and returning done callback", (done) -> + return done() + + it "handles synchronously invoking done callback and returning undefined", (done) -> + done() + return undefined + + it "handles synchronously invoking done callback and returning a value", (done) -> + done() + return "foo" + + it "handles asynchronously invoking done callback", (done) -> + setTimeout -> + done() + return "foo" diff --git a/packages/driver/test/unit_old/cypress/mocha_spec.coffee b/packages/driver/test/unit_old/cypress/mocha_spec.coffee index 73c02d9ccea8..77507fb9b914 100644 --- a/packages/driver/test/unit_old/cypress/mocha_spec.coffee +++ b/packages/driver/test/unit_old/cypress/mocha_spec.coffee @@ -51,12 +51,6 @@ describe "$Cypress.Mocha API", -> beforeEach -> @mocha = $Cypress.Mocha.create(@Cypress, @iframe) - describe "abort", -> - it "resets mocha grep to all", -> - @mocha.grep /\w+/ - @Cypress.trigger "abort" - expect(@mocha.mocha._grep).to.match /.*/ - describe "stop", -> it "calls stop", -> stop = @sandbox.stub @mocha, "stop" @@ -104,16 +98,6 @@ describe "$Cypress.Mocha API", -> @Cypress.trigger("stop") expect(@Cypress.mocha).to.be.null - context "#grep", -> - beforeEach -> - @mocha = $Cypress.Mocha.create(@Cypress, @iframe) - - it "proxies argument to mocha.grep", -> - grep = @sandbox.spy @mocha.mocha, "grep" - re = /\w+/ - @mocha.grep(re) - expect(grep).to.be.calledWith re - context "#getRunner", -> beforeEach -> @mocha = $Cypress.Mocha.create(@Cypress, @iframe) diff --git a/packages/driver/test/unit_old/cypress/runner_spec.coffee b/packages/driver/test/unit_old/cypress/runner_spec.coffee index 3ed987f861dc..9d60c67e4900 100644 --- a/packages/driver/test/unit_old/cypress/runner_spec.coffee +++ b/packages/driver/test/unit_old/cypress/runner_spec.coffee @@ -626,20 +626,6 @@ describe "$Cypress.Runner API", -> expect(calls).to.have.length(1) done() - context "#grep", -> - beforeEach -> - @runner = $Cypress.Runner.runner(@Cypress, {}) - - it "set /.*/ by default", -> - @runner.grep() - expect(@runner.runner._grep).to.match /.*/ - - it "can set to another RegExp", -> - re = /.+/ - @runner.grep(re) - - expect(@runner.runner._grep).to.eq re - context "#anyTestInSuite", -> beforeEach -> runner = Fixtures.createRunnables { @@ -717,17 +703,6 @@ describe "$Cypress.Runner API", -> ## 4 tests expect(@runner.tests).to.have.length(4) - it "only pushes matching grep tests", -> - ## with 4 existing tests - expect(@runner.tests).to.have.length(4) - - @runner.grep(/four/) - - @runner.normalizeAll() - - ## only 1 test should have matched the grep - expect(@runner.tests).to.have.length(1) - it "sets runnable type", -> types = _.map @runner.runnables, "type" expect(types).to.deep.eq ["suite", "test", "suite", "test", "test", "suite", "test"] diff --git a/packages/server/__snapshots__/1_commands_outside_of_test_spec.coffee.js b/packages/server/__snapshots__/1_commands_outside_of_test_spec.coffee.js index 9eabcb080251..06858fd2977b 100644 --- a/packages/server/__snapshots__/1_commands_outside_of_test_spec.coffee.js +++ b/packages/server/__snapshots__/1_commands_outside_of_test_spec.coffee.js @@ -47,6 +47,8 @@ We dynamically generated a new test to display this failure. at stack trace line at stack trace line at stack trace line + at stack trace line + at stack trace line diff --git a/packages/server/__snapshots__/3_only_spec.coffee.js b/packages/server/__snapshots__/3_only_spec.coffee.js index 07f47cef3995..ad6cc66aad3c 100644 --- a/packages/server/__snapshots__/3_only_spec.coffee.js +++ b/packages/server/__snapshots__/3_only_spec.coffee.js @@ -7,14 +7,49 @@ exports['e2e only spec failing 1'] = ` ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ │ Cypress: 1.2.3 │ │ Browser: FooBrowser 88 │ - │ Specs: 1 found (only_spec.coffee) │ - │ Searched: cypress/integration/only_spec.coffee │ + │ Specs: 2 found (only_multiple_spec.coffee, only_spec.coffee) │ + │ Searched: cypress/integration/only*.coffee │ └────────────────────────────────────────────────────────────────────────────────────────────────┘ ──────────────────────────────────────────────────────────────────────────────────────────────────── - Running: only_spec.coffee... (1 of 1) + Running: only_multiple_spec.coffee... (1 of 2) + + + s1 + ✓ t3 + - t4 + + + 1 passing + 1 pending + + + (Results) + + ┌─────────────────────────────────────────┐ + │ Tests: 2 │ + │ Passing: 1 │ + │ Failing: 0 │ + │ Pending: 1 │ + │ Skipped: 0 │ + │ Screenshots: 0 │ + │ Video: true │ + │ Duration: X seconds │ + │ Spec Ran: only_multiple_spec.coffee │ + └─────────────────────────────────────────┘ + + + (Video) + + - Started processing: Compressing to 32 CRF + - Finished processing: /foo/bar/.projects/e2e/cypress/videos/abc123.mp4 (X seconds) + + +──────────────────────────────────────────────────────────────────────────────────────────────────── + + Running: only_spec.coffee... (2 of 2) s1 @@ -52,9 +87,11 @@ exports['e2e only spec failing 1'] = ` Spec Tests Passing Failing Pending Skipped ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ + │ ✔ only_multiple_spec.coffee XX:XX 2 1 - 1 - │ + ├────────────────────────────────────────────────────────────────────────────────────────────────┤ │ ✔ only_spec.coffee XX:XX 1 1 - - - │ └────────────────────────────────────────────────────────────────────────────────────────────────┘ - All specs passed! XX:XX 1 1 - - - + All specs passed! XX:XX 3 2 - 1 - ` diff --git a/packages/server/__snapshots__/4_return_value_spec.coffee.js b/packages/server/__snapshots__/4_return_value_spec.coffee.js index 9db8da1481dd..aeb6fa32c8d8 100644 --- a/packages/server/__snapshots__/4_return_value_spec.coffee.js +++ b/packages/server/__snapshots__/4_return_value_spec.coffee.js @@ -18,10 +18,11 @@ exports['e2e return value failing1 1'] = ` 1) errors when invoking commands and return a different value - 2) errors when invoking commands in custom command and returning differnet value + 2) errors when invoking commands in custom command and returning different value + 3) errors when not invoking commands, invoking done callback, and returning a promise 0 passing - 2 failing + 3 failing 1) errors when invoking commands and return a different value: CypressError: Cypress detected that you invoked one or more cy commands but returned a different value. @@ -54,7 +55,7 @@ https://on.cypress.io/returning-value-and-commands-in-test at stack trace line at stack trace line - 2) errors when invoking commands in custom command and returning differnet value: + 2) errors when invoking commands in custom command and returning different value: CypressError: Cypress detected that you invoked one or more cy commands in a custom command but returned a different value. The custom command was: @@ -85,18 +86,34 @@ https://on.cypress.io/returning-value-and-commands-in-custom-command at stack trace line at stack trace line + 3) errors when not invoking commands, invoking done callback, and returning a promise: + Cypress detected that you returned a promise in a test, but also invoked a done callback. Return a promise -or- invoke a done callback, not both. + +Read more here: https://on.cypress.io/returning-promise-and-invoking-done-callback + +----------------------------------------------------------- + +Original mocha error: + +Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both. + at stack trace line + at stack trace line + Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both. + at stack trace line + at stack trace line + (Results) ┌────────────────────────────────────────┐ - │ Tests: 2 │ + │ Tests: 3 │ │ Passing: 0 │ - │ Failing: 2 │ + │ Failing: 3 │ │ Pending: 0 │ │ Skipped: 0 │ - │ Screenshots: 2 │ + │ Screenshots: 3 │ │ Video: true │ │ Duration: X seconds │ │ Spec Ran: return_value_spec.coffee │ @@ -106,7 +123,8 @@ https://on.cypress.io/returning-value-and-commands-in-custom-command (Screenshots) - /foo/bar/.projects/e2e/cypress/screenshots/return_value_spec.coffee/errors when invoking commands and return a different value (failed).png (1280x720) - - /foo/bar/.projects/e2e/cypress/screenshots/return_value_spec.coffee/errors when invoking commands in custom command and returning differnet value (failed).png (1280x720) + - /foo/bar/.projects/e2e/cypress/screenshots/return_value_spec.coffee/errors when invoking commands in custom command and returning different value (failed).png (1280x720) + - /foo/bar/.projects/e2e/cypress/screenshots/return_value_spec.coffee/errors when not invoking commands invoking done callback and returning a promise (failed).png (1280x720) (Video) @@ -122,9 +140,9 @@ https://on.cypress.io/returning-value-and-commands-in-custom-command Spec Tests Passing Failing Pending Skipped ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ - │ ✖ return_value_spec.coffee XX:XX 2 - 2 - - │ + │ ✖ return_value_spec.coffee XX:XX 3 - 3 - - │ └────────────────────────────────────────────────────────────────────────────────────────────────┘ - 1 of 1 failed (100%) XX:XX 2 - 2 - - + 1 of 1 failed (100%) XX:XX 3 - 3 - - ` diff --git a/packages/server/test/e2e/3_only_spec.coffee b/packages/server/test/e2e/3_only_spec.coffee index 3540916e29f1..42542b1326fc 100644 --- a/packages/server/test/e2e/3_only_spec.coffee +++ b/packages/server/test/e2e/3_only_spec.coffee @@ -5,7 +5,7 @@ describe "e2e only spec", -> it "failing", -> e2e.exec(@, { - spec: "only_spec.coffee" + spec: "only*.coffee" snapshot: true expectedExitCode: 0 }) diff --git a/packages/server/test/e2e/4_return_value_spec.coffee b/packages/server/test/e2e/4_return_value_spec.coffee index c5c811d47d46..4cfa52092d1a 100644 --- a/packages/server/test/e2e/4_return_value_spec.coffee +++ b/packages/server/test/e2e/4_return_value_spec.coffee @@ -7,5 +7,5 @@ describe "e2e return value", -> e2e.exec(@, { spec: "return_value_spec.coffee" snapshot: true - expectedExitCode: 2 + expectedExitCode: 3 }) diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/only_multiple_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/only_multiple_spec.coffee new file mode 100644 index 000000000000..84271b37ff0c --- /dev/null +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/only_multiple_spec.coffee @@ -0,0 +1,13 @@ +it "t1", -> +it "t2", -> +it "t3", -> + +describe "s1", -> + it.only "t3", -> + + it.only "t4" + + it "t5", -> + +describe "s2", -> + it "t3", -> diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/return_value_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/return_value_spec.coffee index 1190c7f9a8ec..ca32aaed8db8 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/return_value_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/return_value_spec.coffee @@ -3,10 +3,14 @@ it "errors when invoking commands and return a different value", -> return [{}, 1, 2, "foo", (->)] -it "errors when invoking commands in custom command and returning differnet value", -> +it "errors when invoking commands in custom command and returning different value", -> Cypress.Commands.add "foo", -> cy.wrap(null) return "bar" cy.foo() + +it "errors when not invoking commands, invoking done callback, and returning a promise", (done) -> + return Promise.resolve(null).then -> + done() From e92908652a6cc9242addac74b24b520b2fd16955 Mon Sep 17 00:00:00 2001 From: Lila Conlee Date: Mon, 3 Dec 2018 14:33:36 -0500 Subject: [PATCH 04/37] Yield null from cy.writeFile (#2731) - Fixes #2466 - [Docs PR](https://github.com/cypress-io/cypress-documentation/pull/1117) Should be part of 4.0.0 --- packages/driver/src/cy/commands/files.coffee | 5 +---- .../cypress/integration/commands/files_spec.coffee | 10 ++-------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/packages/driver/src/cy/commands/files.coffee b/packages/driver/src/cy/commands/files.coffee index 6578adbc4d88..40f7a3009f07 100644 --- a/packages/driver/src/cy/commands/files.coffee +++ b/packages/driver/src/cy/commands/files.coffee @@ -94,16 +94,13 @@ module.exports = (Commands, Cypress, cy, state, config) -> }) if _.isObject(contents) - objContents = contents contents = JSON.stringify(contents, null, 2) Cypress.backend("write:file", fileName, contents, _.pick(options, ["encoding", "flag"])) .then ({ contents, filePath }) -> consoleProps["File Path"] = filePath consoleProps["Contents"] = contents - if objContents? - return objContents - return contents + return null .catch Promise.TimeoutError, (err) -> $utils.throwErrByPath "files.timed_out", { onFail: options._log diff --git a/packages/driver/test/cypress/integration/commands/files_spec.coffee b/packages/driver/test/cypress/integration/commands/files_spec.coffee index b767fbcb5369..b23d0bf22d54 100644 --- a/packages/driver/test/cypress/integration/commands/files_spec.coffee +++ b/packages/driver/test/cypress/integration/commands/files_spec.coffee @@ -286,17 +286,11 @@ describe "src/cy/commands/files", -> } ) - it "sets the contents as the subject", -> + it "yields null", -> Cypress.backend.resolves(okResponse) cy.writeFile("foo.txt", "contents").then (subject) -> - expect(subject).to.equal("contents") - - it "sets a JSON as the subject", -> - Cypress.backend.resolves(okResponse) - - cy.writeFile("foo.json", { name: "Test" }).then (subject) -> - expect(subject.name).to.equal("Test") + expect(subject).to.not.exist it "can write a string", -> Cypress.backend.resolves(okResponse) From 18a87de0ad9da6691e094795095c1480e3778094 Mon Sep 17 00:00:00 2001 From: Lila Conlee Date: Tue, 4 Dec 2018 09:54:30 -0500 Subject: [PATCH 05/37] Upgrade Sinon to 7.1.1 (#2881) - Fixes #2866 --- packages/driver/package.json | 2 +- .../test/cypress/integration/commands/angular_spec.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/driver/package.json b/packages/driver/package.json index 7b02c6f8b489..f6e048086af3 100644 --- a/packages/driver/package.json +++ b/packages/driver/package.json @@ -55,7 +55,7 @@ "npm-install-version": "^6.0.2", "parse-domain": "2.0.0", "setimmediate": "^1.0.2", - "sinon": "3.2.0", + "sinon": "7.1.1", "text-mask-addons": "^3.7.2", "underscore": "^1.8.3", "underscore.string": "3.3.4", diff --git a/packages/driver/test/cypress/integration/commands/angular_spec.coffee b/packages/driver/test/cypress/integration/commands/angular_spec.coffee index abdcb8a9e789..c42d426cfcad 100644 --- a/packages/driver/test/cypress/integration/commands/angular_spec.coffee +++ b/packages/driver/test/cypress/integration/commands/angular_spec.coffee @@ -199,7 +199,7 @@ describe "src/cy/commands/angular", -> ## to retry after the first one resolves cy.ng("model", "missing-input") .then -> - retry.reset() + retry.resetHistory() .wait(100) .then -> expect(retry.callCount).to.eq 0 From aac89a1309c96ef350a24dfeabd86793f3046ee9 Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Tue, 4 Dec 2018 17:30:34 -0500 Subject: [PATCH 06/37] Add plugin events that mirror driver events (#2309) * Closes #2283 Related: * Docs: https://github.com/cypress-io/cypress-documentation/pull/967 * cypress-on: https://github.com/cypress-io/cypress-on/pull/96 --- cli/types/index.d.ts | 38 +-- cli/types/tests/actions.ts | 22 +- cli/types/tests/kitchen-sink.ts | 14 +- .../integration/update_banner_spec.coffee | 2 +- packages/driver/README.md | 10 +- .../src/cy/commands/actions/type.coffee | 2 +- packages/driver/src/cy/commands/agents.coffee | 2 +- packages/driver/src/cy/commands/clock.coffee | 4 +- .../driver/src/cy/commands/cookies.coffee | 2 +- .../src/cy/commands/local_storage.coffee | 2 +- .../driver/src/cy/commands/navigation.coffee | 56 ++-- packages/driver/src/cy/commands/popups.coffee | 4 +- .../driver/src/cy/commands/querying.coffee | 6 +- .../driver/src/cy/commands/screenshot.coffee | 2 +- packages/driver/src/cy/commands/window.coffee | 2 +- packages/driver/src/cy/commands/xhr.coffee | 6 +- packages/driver/src/cy/errors.coffee | 2 + packages/driver/src/cypress.coffee | 103 +++++--- packages/driver/src/cypress/cy.coffee | 26 +- .../driver/src/cypress/error_messages.coffee | 29 +++ packages/driver/src/cypress/events.coffee | 49 +++- packages/driver/src/cypress/log.coffee | 2 +- packages/driver/src/cypress/runner.coffee | 42 +-- packages/driver/src/cypress/utils.coffee | 4 +- .../driver/test/cypress/fixtures/sinon.html | 2 +- .../test/cypress/fixtures/sync_error.html | 2 +- .../commands/actions/check_spec.coffee | 40 +-- .../commands/actions/click_spec.coffee | 54 ++-- .../commands/actions/focus_spec.coffee | 34 +-- .../commands/actions/hover_spec.coffee | 2 +- .../commands/actions/scroll_spec.coffee | 32 +-- .../commands/actions/select_spec.coffee | 26 +- .../commands/actions/submit_spec.coffee | 16 +- .../commands/actions/trigger_spec.coffee | 34 +-- .../commands/actions/type_spec.coffee | 84 +++--- .../integration/commands/agents_spec.coffee | 6 +- .../integration/commands/aliasing_spec.coffee | 14 +- .../integration/commands/angular_spec.coffee | 18 +- .../commands/assertions_spec.coffee | 68 ++--- .../integration/commands/clock_spec.coffee | 16 +- .../integration/commands/commands_spec.coffee | 2 +- .../commands/connectors_spec.coffee | 56 ++-- .../integration/commands/cookies_spec.coffee | 38 +-- .../integration/commands/exec_spec.coffee | 28 +- .../integration/commands/files_spec.coffee | 28 +- .../integration/commands/fixtures_spec.coffee | 12 +- .../commands/local_storage_spec.coffee | 6 +- .../integration/commands/location_spec.coffee | 12 +- .../integration/commands/misc_spec.coffee | 4 +- .../commands/navigation_spec.coffee | 244 +++++++++++------- .../integration/commands/popups_spec.coffee | 2 +- .../integration/commands/querying_spec.coffee | 78 +++--- .../integration/commands/request_spec.coffee | 28 +- .../commands/screenshot_spec.coffee | 30 +-- .../integration/commands/task_spec.coffee | 18 +- .../commands/traversals_spec.coffee | 18 +- .../integration/commands/waiting_spec.coffee | 70 ++--- .../integration/commands/window_spec.coffee | 34 +-- .../integration/commands/xhr_spec.coffee | 52 ++-- .../integration/cypress/cy_spec.coffee | 12 +- .../integration/cypress/runner_spec.coffee | 2 +- .../integration/dom/elements_spec.coffee | 4 +- .../integration/e2e/cancellation_spec.coffee | 2 +- .../integration/e2e/events_spec.coffee | 40 +++ .../integration/e2e/promises_spec.coffee | 6 +- .../integration/e2e/return_value_spec.coffee | 8 +- .../e2e/uncaught_errors_spec.coffee | 6 +- .../test/unit_old/cypress/log_spec.coffee | 12 +- .../test/unit_old/cypress/runner_spec.coffee | 86 +++--- .../integration/examples/navigation.spec.js | 4 +- packages/reporter/src/lib/events.js | 4 +- packages/reporter/src/lib/events.spec.js | 12 +- packages/runner/src/iframe/iframe-model.js | 2 +- packages/runner/src/lib/event-manager.js | 4 +- ...caught_uncaught_hook_errors_spec.coffee.js | 2 +- .../background_driver_events_spec.coffee.js | 83 ++++++ .../lib/background/child/driver_events.js | 19 ++ packages/server/lib/background/child/index.js | 1 + .../lib/background/child/preprocessor.js | 6 +- .../lib/background/child/run_background.js | 8 + .../lib/background/driver_events.coffee | 13 + packages/server/lib/errors.coffee | 10 + packages/server/lib/reporter.coffee | 2 +- packages/server/lib/socket.coffee | 7 +- packages/server/lib/util/inject.js | 2 +- packages/server/test/e2e/6_visit_spec.coffee | 2 +- .../e2e/background_driver_events_spec.coffee | 15 ++ .../test/integration/server_spec.coffee | 24 +- .../background-driver-events/cypress.json | 1 + .../cypress/background/index.js | 36 +++ .../background_driver_events_spec.coffee | 3 + .../integration/async_timeouts_spec.coffee | 2 +- .../caught_async_sync_test_spec.coffee | 10 +- .../hook_caught_error_failing_spec.coffee | 14 +- ..._uncaught_error_events_failing_spec.coffee | 8 +- .../cypress/integration/iframe_spec.coffee | 4 +- .../integration/issue_2196_spec.coffee | 12 +- .../uncaught_during_hook_spec.coffee | 2 +- .../e2e/cypress/integration/visit_spec.coffee | 2 +- .../e2e/cypress/integration/xhr_spec.coffee | 4 +- .../cypress/background/index.js | 4 +- .../server/absolute_url_expected.html | 2 +- .../fixtures/server/expected_head_inject.html | 2 +- .../server/expected_https_inject.html | 2 +- .../server/expected_no_head_tag_inject.html | 2 +- .../child/run_background_spec.coffee | 4 +- 106 files changed, 1278 insertions(+), 873 deletions(-) create mode 100644 packages/driver/test/cypress/integration/e2e/events_spec.coffee create mode 100644 packages/server/__snapshots__/background_driver_events_spec.coffee.js create mode 100644 packages/server/lib/background/child/driver_events.js create mode 100644 packages/server/lib/background/driver_events.coffee create mode 100644 packages/server/test/e2e/background_driver_events_spec.coffee create mode 100644 packages/server/test/support/fixtures/projects/background-driver-events/cypress.json create mode 100644 packages/server/test/support/fixtures/projects/background-driver-events/cypress/background/index.js create mode 100644 packages/server/test/support/fixtures/projects/background-driver-events/cypress/integration/background_driver_events_spec.coffee diff --git a/cli/types/index.d.ts b/cli/types/index.d.ts index e29251778c8a..edeadc88c28e 100644 --- a/cli/types/index.d.ts +++ b/cli/types/index.d.ts @@ -2014,14 +2014,14 @@ declare namespace Cypress { * * @param {Window} contentWindow the remote page's window object */ - onBeforeLoad(win: Window): void + onStart(win: Window): void /** * Called once your page has fired its load event. * * @param {Window} contentWindow the remote page's window object */ - onLoad(win: Window): void + onReady(win: Window): void /** * Whether to fail on response codes other than 2xx and 3xx @@ -3654,7 +3654,7 @@ declare namespace Cypress { (fn: (currentSubject: Subject) => void): Chainable } - // for just a few events like "window:alert" it makes sense to allow passing cy.stub() or + // for just a few events like "page:alert" it makes sense to allow passing cy.stub() or // a user callback function. Others probably only need a callback function. /** @@ -3680,7 +3680,7 @@ declare namespace Cypress { * // stub "window.alert" in a single test * it('shows alert', () => { * const stub = cy.stub() - * cy.on('window:alert', stub) + * cy.on('page:alert', stub) * // trigger application code that calls alert(...) * .then(() => { * expect(stub).to.have.been.calledOnce @@ -3694,18 +3694,18 @@ declare namespace Cypress { * Cypress will auto accept confirmations. Return `false` from this event and the confirmation will be cancelled. * @see https://on.cypress.io/catalog-of-events#App-Events * @example - * cy.on('window:confirm', (str) => { + * cy.on('page:confirm', (str) => { * console.log(str) * return false // simulate "Cancel" * }) */ - (action: 'window:confirm', fn: ((text: string) => false | void) | Agent): void + (action: 'page:confirm', fn: ((text: string) => false | void) | Agent): void /** * Fires when your app calls the global `window.alert()` method. * Cypress will auto accept alerts. You cannot change this behavior. * @example * const stub = cy.stub() - * cy.on('window:alert', stub) + * cy.on('page:alert', stub) * // assume the button calls window.alert() * cy.get('.my-button').click() * .then(() => { @@ -3713,37 +3713,37 @@ declare namespace Cypress { * }) * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'window:alert', fn: ((text: string) => void) | Agent): void + (action: 'page:alert', fn: ((text: string) => void) | Agent): void /** - * Fires as the page begins to load, but before any of your applications JavaScript has executed. This fires at the exact same time as `cy.visit()` `onBeforeLoad` callback. Useful to modify the window on a page transition. + * Fires as the page begins to load, but before any of your applications JavaScript has executed. This fires at the exact same time as `cy.visit()` `onStart` callback. Useful to modify the window on a page transition. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'window:before:load', fn: (win: Window) => void): void + (action: 'page:start', fn: (win: Window) => void): void /** - * Fires after all your resources have finished loading after a page transition. This fires at the exact same time as a `cy.visit()` `onLoad` callback. + * Fires after all your resources have finished loading after a page transition. This fires at the exact same time as a `cy.visit()` `onReady` callback. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'window:load', fn: (win: Window) => void): void + (action: 'page:ready', fn: (win: Window) => void): void /** * Fires when your application is about to navigate away. The real event object is provided to you. Your app may have set a `returnValue` on the event, which is useful to assert on. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'window:before:unload', fn: (event: BeforeUnloadEvent) => void): void + (action: 'before:window:unload', fn: (event: BeforeUnloadEvent) => void): void /** * Fires when your application is has unloaded and is navigating away. The real event object is provided to you. This event is not cancelable. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'window:unload', fn: (event: Event) => void): void + (action: 'page:end', fn: (event: Event) => void): void /** * Fires whenever Cypress detects that your application's URL has changed. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'url:changed', fn: (url: string) => void): void + (action: 'page:url:changed', fn: (url: string) => void): void /** * Fires when the test has failed. It is technically possible to prevent the test from actually failing by binding to this event and invoking an async `done` callback. However this is **strongly discouraged**. Tests should never legitimately fail. This event exists because it's extremely useful for debugging purposes. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'fail', fn: (error: Error, mocha: Mocha.IRunnable) => void): void + (action: 'test:fail', fn: (error: Error, mocha: Mocha.IRunnable) => void): void /** * Fires whenever the viewport changes via a `cy.viewport()` or naturally when Cypress resets the viewport to the default between tests. Useful for debugging purposes. * @see https://on.cypress.io/catalog-of-events#App-Events @@ -3753,7 +3753,7 @@ declare namespace Cypress { * Fires whenever **Cypress** is scrolling your application. This event is fired when Cypress is {% url 'waiting for and calculating actionability' interacting-with-elements %}. It will scroll to 'uncover' elements currently being covered. This event is extremely useful to debug why Cypress may think an element is not interactive. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'scrolled', fn: ($el: JQuery) => void): void + (action: 'internal:scrolled', fn: ($el: JQuery) => void): void /** * Fires when a cy command is first invoked and enqueued to be run later. Useful for debugging purposes if you're confused about the order in which commands will execute. * @see https://on.cypress.io/catalog-of-events#App-Events @@ -3788,12 +3788,12 @@ declare namespace Cypress { * Fires before the test and all **before** and **beforeEach** hooks run. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'test:before:run', fn: (attributes: ObjectLike, test: Mocha.ITest) => void): void + (action: 'test:run:start', fn: (attributes: ObjectLike, test: Mocha.ITest) => void): void /** * Fires after the test and all **afterEach** and **after** hooks run. * @see https://on.cypress.io/catalog-of-events#App-Events */ - (action: 'test:after:run', fn: (attributes: ObjectLike, test: Mocha.ITest) => void): void + (action: 'test:run:end', fn: (attributes: ObjectLike, test: Mocha.ITest) => void): void } // $CommandQueue from `command_queue.coffee` - a lot to type. Might be more useful if it was written in TS diff --git a/cli/types/tests/actions.ts b/cli/types/tests/actions.ts index ae407691ce85..5fd9d3181b50 100644 --- a/cli/types/tests/actions.ts +++ b/cli/types/tests/actions.ts @@ -3,35 +3,35 @@ Cypress.on('uncaught:exception', (error, runnable) => { runnable // $ExpectType IRunnable }) -Cypress.on('window:confirm', (text) => { +Cypress.on('page:confirm', (text) => { text // $ExpectType string }) -Cypress.on('window:alert', (text) => { +Cypress.on('page:alert', (text) => { text // $ExpectType string }) -Cypress.on('window:before:load', (win) => { +Cypress.on('page:start', (win) => { win // $ExpectType Window }) -Cypress.on('window:load', (win) => { +Cypress.on('page:ready', (win) => { win // $ExpectType Window }) -Cypress.on('window:before:unload', (event) => { +Cypress.on('before:window:unload', (event) => { event // $ExpectType BeforeUnloadEvent }) -Cypress.on('window:unload', (event) => { +Cypress.on('page:end', (event) => { event // $ExpectType Event }) -Cypress.on('url:changed', (url) => { +Cypress.on('page:url:changed', (url) => { url // $ExpectType string }) -Cypress.on('fail', (error, mocha) => { +Cypress.on('test:fail', (error, mocha) => { error // $ExpectType Error mocha // $ExpectType IRunnable }) @@ -40,7 +40,7 @@ Cypress.on('viewport:changed', (viewport) => { viewport // $ExpectType Viewport }) -Cypress.on('scrolled', ($el) => { +Cypress.on('internal:scrolled', ($el) => { $el // $ExpectType JQuery }) @@ -68,12 +68,12 @@ Cypress.on('log:changed', (log, interactive: boolean) => { log // $ExpectTyped any }) -Cypress.on('test:before:run', (attributes , test) => { +Cypress.on('test:run:start', (attributes , test) => { attributes // $ExpectType ObjectLike test // $ExpectType ITest }) -Cypress.on('test:after:run', (attributes , test) => { +Cypress.on('test:run:end', (attributes , test) => { attributes // $ExpectType ObjectLike test // $ExpectType ITest }) diff --git a/cli/types/tests/kitchen-sink.ts b/cli/types/tests/kitchen-sink.ts index b24f676b6e2d..3b5c69a7fe33 100644 --- a/cli/types/tests/kitchen-sink.ts +++ b/cli/types/tests/kitchen-sink.ts @@ -38,15 +38,15 @@ Cypress.browser // $ExpectType Browser // stubbing window.alert type on "Cypress" should // work with plain function or with a Sinon stub -Cypress.on('window:alert', () => {}) -Cypress.on('window:alert', cy.stub()) +Cypress.on('page:alert', () => {}) +Cypress.on('page:alert', cy.stub()) // same for a single test -cy.on('window:alert', () => {}) -cy.on('window:alert', cy.stub()) +cy.on('page:alert', () => {}) +cy.on('page:alert', cy.stub()) -// window:confirm stubbing -cy.on('window:confirm', () => {}) -cy.on('window:confirm', cy.stub()) +// page:confirm stubbing +cy.on('page:confirm', () => {}) +cy.on('page:confirm', cy.stub()) // specifying HTTP method directly in the options object cy.request({ diff --git a/packages/desktop-gui/cypress/integration/update_banner_spec.coffee b/packages/desktop-gui/cypress/integration/update_banner_spec.coffee index 7d660e29736b..b50e8f4475ea 100644 --- a/packages/desktop-gui/cypress/integration/update_banner_spec.coffee +++ b/packages/desktop-gui/cypress/integration/update_banner_spec.coffee @@ -12,7 +12,7 @@ describe "Update Banner", -> cy.fixture("specs").as("specs") cy.visitIndex({ - onBeforeLoad: (win) -> + onStart: (win) -> cy.spy(win, "setInterval") }).then (win) -> { @start, @ipc } = win.App diff --git a/packages/driver/README.md b/packages/driver/README.md index 4cfd0594b510..7771f18a0cfb 100644 --- a/packages/driver/README.md +++ b/packages/driver/README.md @@ -77,8 +77,8 @@ after:add | Runner | Anyone | when all runnables have been added to the UI runnables:ready | Runner | Anyone | when all runnables have been reduced to basic objects mocha:start | Mocha | Cypress | when mocha runner triggers its 'start' event suite:start | Mocha | Cypress | when mocha runner fires its 'suite' event -test:before:run:async | Cypress | Anyone | before any code has run for a particular test -test:before:run:async | Cypress | Cypress | before any hooks for a test have started +test:run:start:async | Cypress | Anyone | before any code has run for a particular test +test:run:start:async | Cypress | Cypress | before any hooks for a test have started hook:start | Mocha | Cypress | when mocha runner fires its 'hook' event test:start | Mocha | Cypress | when mocha runner fires its 'test' event suite:end | Mocha | Cypress | when mocha runner fires its 'suite end' event @@ -88,8 +88,8 @@ mocha:pending | Mocha | Cypress | when mocha runner fires its 'pending' event mocha:fail | Mocha | Cypress | when mocha runner fires its 'fail' event test:end | Mocha | Cypress | when mocha runner fires its 'test end' event test:results:ready | Runner | Anyone | when we receive the 'test:end' event -test:after:hooks | Cypress | Cypress | after all hooks have run for a test -test:after:run | Cypress | Anyone | after any code has run for a test +after:test:hooks | Cypress | Cypress | after all hooks have run for a test +test:run:end | Cypress | Anyone | after any code has run for a test mocha:end | Mocha | Cypress | when mocha runner fires its 'end' event after:run | Runner | Anyone | after run has finished @@ -119,7 +119,7 @@ paused | Cypress | Runner | when pausing is being requested Event | From | To | Description --- | --- | --- | --- -url:changed | Cypress | Anyone | when aut app url is changed +page:url:changed | Cypress | Anyone | when aut app url is changed page:loading | Cypress | Anyone | when aut app is currently loading a page viewport | Cypress | Anyone | when viewport has changed diff --git a/packages/driver/src/cy/commands/actions/type.coffee b/packages/driver/src/cy/commands/actions/type.coffee index a401b26467c3..3b9acae6245b 100644 --- a/packages/driver/src/cy/commands/actions/type.coffee +++ b/packages/driver/src/cy/commands/actions/type.coffee @@ -17,7 +17,7 @@ weekRegex = /^\d{4}-W(0[1-9]|[1-4]\d|5[0-3])$/ timeRegex = /^([0-1]\d|2[0-3]):[0-5]\d(:[0-5]\d)?(\.[0-9]{1,3})?$/ module.exports = (Commands, Cypress, cy, state, config) -> - Cypress.on "test:before:run", -> + Cypress.on "test:run:start", -> $Keyboard.resetModifiers(state("document"), state("window")) Commands.addAll({ prevSubject: "element" }, { diff --git a/packages/driver/src/cy/commands/agents.coffee b/packages/driver/src/cy/commands/agents.coffee index 1b2964da1e3b..85c36b3de78d 100644 --- a/packages/driver/src/cy/commands/agents.coffee +++ b/packages/driver/src/cy/commands/agents.coffee @@ -119,7 +119,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> ## before each of our tests we always want ## to reset the counts + the sandbox - Cypress.on("test:before:run", resetAndSetSandbox) + Cypress.on("test:run:start", resetAndSetSandbox) wrap = (ctx, type, agent, obj, method, count) -> if not count diff --git a/packages/driver/src/cy/commands/clock.coffee b/packages/driver/src/cy/commands/clock.coffee index 2aff5be52e08..92ea126d06ef 100644 --- a/packages/driver/src/cy/commands/clock.coffee +++ b/packages/driver/src/cy/commands/clock.coffee @@ -22,9 +22,9 @@ module.exports = (Commands, Cypress, cy, state, config) -> ## this MUST be prepended else if we are stubbing or spying on ## global timers they will be reset in agents before this runs ## its reset function - Cypress.prependListener("test:before:run", reset) + Cypress.prependListener("test:run:start", reset) - Cypress.on "window:before:load", (contentWindow) -> + Cypress.on "page:start", (contentWindow) -> ## if a clock has been created before this event (likely before ## a cy.visit(), then bind that clock to the new window if clock diff --git a/packages/driver/src/cy/commands/cookies.coffee b/packages/driver/src/cy/commands/cookies.coffee index 973e26229890..8dee580b151e 100644 --- a/packages/driver/src/cy/commands/cookies.coffee +++ b/packages/driver/src/cy/commands/cookies.coffee @@ -70,7 +70,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> automateCookies("clear:cookies", cookies, log, timeout) - Cypress.on "test:before:run:async", -> + Cypress.on "test:run:start:async", -> ## TODO: handle failure here somehow ## maybe by tapping into the Cypress reset ## stuff, or handling this in the runner itself? diff --git a/packages/driver/src/cy/commands/local_storage.coffee b/packages/driver/src/cy/commands/local_storage.coffee index ca764acc3b5b..6278adbc178f 100644 --- a/packages/driver/src/cy/commands/local_storage.coffee +++ b/packages/driver/src/cy/commands/local_storage.coffee @@ -21,7 +21,7 @@ clearLocalStorage = (state, keys) -> module.exports = (Commands, Cypress, cy, state, config) -> ## this MUST be prepended before anything else - Cypress.prependListener "test:before:run", -> + Cypress.prependListener "test:run:start", -> try ## this may fail if the current ## window is bound to another origin diff --git a/packages/driver/src/cy/commands/navigation.coffee b/packages/driver/src/cy/commands/navigation.coffee index 0945bd3fa3f4..d2d239e72962 100644 --- a/packages/driver/src/cy/commands/navigation.coffee +++ b/packages/driver/src/cy/commands/navigation.coffee @@ -60,7 +60,7 @@ cannotVisit2ndDomain = (origin, previousDomainVisited, log) -> aboutBlank = (win) -> new Promise (resolve) -> - cy.once("window:load", resolve) + cy.once("page:ready", resolve) $utils.locHref("about:blank", win) @@ -82,7 +82,7 @@ navigationChanged = (Cypress, cy, state, source, arg) -> return if url is previousUrl ## else notify the world and log this event - Cypress.action("cy:url:changed", url) + Cypress.action("cy:page:url:changed", url) urls.push(url) @@ -211,7 +211,7 @@ stabilityChanged = (Cypress, state, config, stable, event) -> loading = -> new Promise (resolve, reject) -> - cy.once "window:load", -> + cy.once "page:ready", -> cy.state("onPageLoadErr", null) options._log.set("message", "--page loaded--").snapshot().end() @@ -236,7 +236,7 @@ stabilityChanged = (Cypress, state, config, stable, event) -> module.exports = (Commands, Cypress, cy, state, config) -> reset() - Cypress.on("test:before:run", reset) + Cypress.on("test:run:start", reset) Cypress.on "stability:changed", (bool, event) -> ## only send up page loading events when we're @@ -284,7 +284,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> else resp - Cypress.on "window:before:load", (contentWindow) -> + Cypress.on "page:start", (contentWindow) -> ## TODO: just use a closure here current = state("current") @@ -295,7 +295,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> return if not runnable options = _.last(current.get("args")) - options?.onBeforeLoad?.call(runnable.ctx, contentWindow) + options?.onStart?.call(runnable.ctx, contentWindow) Commands.addAll({ reload: (args...) -> @@ -349,11 +349,11 @@ module.exports = (Commands, Cypress, cy, state, config) -> cleanup = -> knownCommandCausedInstability = false - cy.removeListener("window:load", resolve) + cy.removeListener("page:ready", resolve) knownCommandCausedInstability = true - cy.once("window:load", resolve) + cy.once("page:ready", resolve) $utils.locReload(forceReload, state("window")) @@ -396,14 +396,14 @@ module.exports = (Commands, Cypress, cy, state, config) -> ## clear the current timeout cy.clearTimeout() - cy.once("window:before:unload", beforeUnload) + cy.once("before:window:unload", beforeUnload) didLoad = new Promise (resolve) -> cleanup = -> - cy.removeListener("window:load", resolve) - cy.removeListener("window:before:unload", beforeUnload) + cy.removeListener("page:ready", resolve) + cy.removeListener("before:window:unload", beforeUnload) - cy.once("window:load", resolve) + cy.once("page:ready", resolve) knownCommandCausedInstability = true @@ -459,13 +459,29 @@ module.exports = (Commands, Cypress, cy, state, config) -> if not _.isString(url) $utils.throwErrByPath("visit.invalid_1st_arg") + if options.onBeforeLoad + $utils.throwErrByPath("visit.renamed_callback", { + args: { + oldName: "onBeforeLoad" + newName: "onStart" + } + }) + + if options.onLoad + $utils.throwErrByPath("visit.renamed_callback", { + args: { + oldName: "onLoad" + newName: "onReady" + } + }) + _.defaults(options, { auth: null failOnStatusCode: true log: true timeout: config("pageLoadTimeout") - onBeforeLoad: -> - onLoad: -> + onStart: -> + onReady: -> }) consoleProps = {} @@ -519,11 +535,11 @@ module.exports = (Commands, Cypress, cy, state, config) -> $utils.iframeSrc($autIframe, url) - onLoad = -> + onReady = -> ## reset window on load win = state("window") - options.onLoad?.call(runnable.ctx, win) + options.onReady?.call(runnable.ctx, win) options._log.set({url: url}) if options._log @@ -561,11 +577,11 @@ module.exports = (Commands, Cypress, cy, state, config) -> ## if all that is changing is the hash then we know ## the browser won't actually make a new http request - ## for this, and so we need to resolve onLoad immediately + ## for this, and so we need to resolve onReady immediately ## and bypass the actual visit resolution stuff if bothUrlsMatchAndRemoteHasHash(current, remote) return changeIframeSrc(remote.href, "hashchange") - .then(onLoad) + .then(onReady) if existingHash ## strip out the existing hash if we have one @@ -611,8 +627,8 @@ module.exports = (Commands, Cypress, cy, state, config) -> url = $Location.fullyQualifyUrl(url) - changeIframeSrc(url, "window:load") - .then(onLoad) + changeIframeSrc(url, "page:ready") + .then(onReady) else ## if we've already visited a new superDomain ## then die else we'd be in a terrible endless loop diff --git a/packages/driver/src/cy/commands/popups.coffee b/packages/driver/src/cy/commands/popups.coffee index 7119313e2223..1d887a5f7a04 100644 --- a/packages/driver/src/cy/commands/popups.coffee +++ b/packages/driver/src/cy/commands/popups.coffee @@ -26,8 +26,8 @@ windowConfirmed = (Cypress, str, ret) -> }) module.exports = (Commands, Cypress, cy, state, config) -> - Cypress.on "window:alert", (str) -> + Cypress.on "page:alert", (str) -> windowAlert(Cypress, str) - Cypress.on "window:confirmed", (str, ret) -> + Cypress.on "page:confirmed", (str, ret) -> windowConfirmed(Cypress, str, ret) diff --git a/packages/driver/src/cy/commands/querying.coffee b/packages/driver/src/cy/commands/querying.coffee index 05102051cb1d..1c048fc55863 100644 --- a/packages/driver/src/cy/commands/querying.coffee +++ b/packages/driver/src/cy/commands/querying.coffee @@ -17,7 +17,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> restoreContains() ## restore before each test and whenever we stop - Cypress.on("test:before:run", restoreContains) + Cypress.on("test:run:start", restoreContains) Cypress.on("stop", restoreContains) Commands.addAll({ @@ -47,7 +47,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> getFocused = -> focused = cy.getFocused() log(focused) - + return focused do resolveFocused = (failedByNonAssertion = false) -> @@ -447,7 +447,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> else ## remove our listener if we happen to reach the end ## event which will finalize cleanup if there was no next obj - cy.once "command:queue:before:end", -> + cy.once "before:command:queue:end", -> cleanup() cy.state("withinSubject", null) diff --git a/packages/driver/src/cy/commands/screenshot.coffee b/packages/driver/src/cy/commands/screenshot.coffee index 82a7cb636b3e..74628871b963 100644 --- a/packages/driver/src/cy/commands/screenshot.coffee +++ b/packages/driver/src/cy/commands/screenshot.coffee @@ -276,7 +276,7 @@ takeScreenshot = (Cypress, state, screenshotConfig, options = {}) -> module.exports = (Commands, Cypress, cy, state, config) -> ## failure screenshot when not interactive - Cypress.on "runnable:after:run:async", (test, runnable) -> + Cypress.on "after:runnable:run:async", (test, runnable) -> screenshotConfig = $Screenshot.getConfig() return if not test.err or not screenshotConfig.screenshotOnRunFailure or config("isInteractive") or test.err.isPending diff --git a/packages/driver/src/cy/commands/window.coffee b/packages/driver/src/cy/commands/window.coffee index 18f7c2120cd1..1eaee8b02905 100644 --- a/packages/driver/src/cy/commands/window.coffee +++ b/packages/driver/src/cy/commands/window.coffee @@ -31,7 +31,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> ## currentViewport could already be set due to previous runs currentViewport ?= defaultViewport - Cypress.on "test:before:run:async", -> + Cypress.on "test:run:start:async", -> ## if we have viewportDefaults it means ## something has changed the default and we ## need to restore prior to running the next test diff --git a/packages/driver/src/cy/commands/xhr.coffee b/packages/driver/src/cy/commands/xhr.coffee index fe5e43a524af..907d05c15ad2 100644 --- a/packages/driver/src/cy/commands/xhr.coffee +++ b/packages/driver/src/cy/commands/xhr.coffee @@ -226,9 +226,9 @@ module.exports = (Commands, Cypress, cy, state, config) -> ## we need to cancel all outstanding ## XHR's so the command log displays ## correctly - Cypress.on("window:unload", abort) + Cypress.on("page:end", abort) - Cypress.on "test:before:run", -> + Cypress.on "test:run:start", -> ## reset the existing server reset() @@ -245,7 +245,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> return null - Cypress.on "window:before:load", (contentWindow) -> + Cypress.on "page:start", (contentWindow) -> if server ## dynamically bind the server to whatever is currently running server.bindTo(contentWindow) diff --git a/packages/driver/src/cy/errors.coffee b/packages/driver/src/cy/errors.coffee index beb2d1bcbd21..6c9760ab5e4f 100644 --- a/packages/driver/src/cy/errors.coffee +++ b/packages/driver/src/cy/errors.coffee @@ -28,6 +28,7 @@ create = (state, config, log) -> createUncaughtException = (type, args) -> [msg, source, lineno, colno, err] = args + type = err?.from or type current = state("current") @@ -48,6 +49,7 @@ create = (state, config, log) -> suffixMsg = switch type when "app" then "uncaught.fromApp" when "spec" then "uncaught.fromSpec" + when "cypress" then "uncaught.fromCypress" err = $utils.appendErrMsg(err, $utils.errMessageByPath(suffixMsg)) diff --git a/packages/driver/src/cypress.coffee b/packages/driver/src/cypress.coffee index e522abfef4c8..f804629ca960 100644 --- a/packages/driver/src/cypress.coffee +++ b/packages/driver/src/cypress.coffee @@ -63,6 +63,37 @@ throwPrivateCommandInterface = (method) -> args: { method } }) +serializeError = (err) -> + _.extend({}, _.pick(err, "name", "message", "stack", "displayMessage"), { + actual: $utils.stringify(err.actual) + expected: $utils.stringify(err.expected) + }) + +serializeCommand = (command) -> + if command.attributes + name = command.get("name") + args = command.get("args") + else + name = command.name + args = command.args + + { + name: name + args: _.reject args, (arg) -> _.isFunction(arg) or _.isObject(arg) + } + +serializeRetry = (retry) -> + { + name: retry._name + error: serializeError(retry.error) + runnable: serializeTest(retry._runnable) + } + +serializeTest = (test) -> + _.extend({}, _.pick(test, "async", "body", "file", "id", "pending", "sync", "timedOut", "title", "type"), { + parentId: test.parent.id + }) + class $Cypress constructor: (config = {}) -> @cy = null @@ -74,6 +105,8 @@ class $Cypress @events = $Events.extend(@) + $Events.throwOnRenamedEvent(@, "Cypress") + @setConfig(config) setConfig: (config = {}) -> @@ -200,8 +233,8 @@ class $Cypress ## ## when this happens mocha aborts the entire run ## and does not do the usual cleanup so that means - ## we have to fire the test:after:hooks and - ## test:after:run events ourselves + ## we have to fire the after:test:hooks and + ## test:run:end events ourselves @emit("run:end") if @config("isTextTerminal") @@ -259,30 +292,32 @@ class $Cypress when "mocha:runnable:run" @runner.onRunnableRun(args...) - when "runner:test:before:run" + when "runner:test:run:start" ## get back to a clean slate @cy.reset() - @emit("test:before:run", args...) + @emitToBackend("test:run:start", serializeTest(args[1])) + @emit("test:run:start", args...) - when "runner:test:before:run:async" + when "runner:test:run:start:async" ## TODO: handle timeouts here? or in the runner? - @emitThen("test:before:run:async", args...) + @emitThen("test:run:start:async", args...) - when "runner:runnable:after:run:async" - @emitThen("runnable:after:run:async", args...) + when "runner:after:runnable:run:async" + @emitThen("after:runnable:run:async", args...) - when "runner:test:after:run" + when "runner:test:run:end" @runner.cleanupQueue(@config("numTestsKeptInMemory")) ## this event is how the reporter knows how to display ## stats and runnable properties such as errors - @emit("test:after:run", args...) + @emitToBackend("test:run:end", serializeTest(args[1])) + @emit("test:run:end", args...) if @config("isTextTerminal") ## needed for calculating wallClockDuration ## and the timings of after + afterEach hooks - @emit("mocha", "test:after:run", args[0]) + @emit("mocha", "test:run:end", args[0]) when "cy:before:all:screenshots" @emit("before:all:screenshots", args...) @@ -306,9 +341,9 @@ class $Cypress @emit("log:changed", args...) - when "cy:fail" + when "cy:test:fail" ## comes from cypress errors fail() - @emitMap("fail", args...) + @emitMap("test:fail", args...) when "cy:stability:changed" @emit("stability:changed", args...) @@ -326,25 +361,29 @@ class $Cypress @emit("viewport:changed", args...) when "cy:command:start" + @emitToBackend("command:start", serializeCommand(args[0])) @emit("command:start", args...) when "cy:command:end" + @emitToBackend("command:end", serializeCommand(args[0])) @emit("command:end", args...) when "cy:command:retry" + @emitToBackend("command:retry", serializeRetry(args[0])) @emit("command:retry", args...) when "cy:command:enqueued" + @emitToBackend("command:enqueued", serializeCommand(args[0])) @emit("command:enqueued", args[0]) - when "cy:command:queue:before:end" - @emit("command:queue:before:end") + when "cy:before:command:queue:end" + @emit("before:command:queue:end") when "cy:command:queue:end" @emit("command:queue:end") - when "cy:url:changed" - @emit("url:changed", args[0]) + when "cy:page:url:changed" + @emit("page:url:changed", args[0]) when "cy:next:subject:prepared" @emit("next:subject:prepared", args...) @@ -353,27 +392,27 @@ class $Cypress @emitThen("collect:run:state") when "cy:scrolled" - @emit("scrolled", args...) + @emit("internal:scrolled", args...) when "app:uncaught:exception" @emitMap("uncaught:exception", args...) - when "app:window:alert" - @emit("window:alert", args[0]) + when "app:page:alert" + @emit("page:alert", args[0]) - when "app:window:confirm" - @emitMap("window:confirm", args[0]) + when "app:page:confirm" + @emitMap("page:confirm", args[0]) - when "app:window:confirmed" - @emit("window:confirmed", args...) + when "app:page:confirmed" + @emit("page:confirmed", args...) when "app:page:loading" @emit("page:loading", args[0]) - when "app:window:before:load" + when "app:page:start" @cy.onBeforeAppWindowLoad(args[0]) - @emit("window:before:load", args[0]) + @emit("page:start", args[0]) when "app:navigation:changed" @emit("navigation:changed", args...) @@ -381,14 +420,14 @@ class $Cypress when "app:form:submitted" @emit("form:submitted", args[0]) - when "app:window:load" - @emit("window:load", args[0]) + when "app:page:ready" + @emit("page:ready", args[0]) - when "app:window:before:unload" - @emit("window:before:unload", args[0]) + when "app:before:window:unload" + @emit("before:window:unload", args[0]) - when "app:window:unload" - @emit("window:unload", args[0]) + when "app:page:end" + @emit("page:end", args[0]) when "spec:script:error" @emit("script:error", args...) diff --git a/packages/driver/src/cypress/cy.coffee b/packages/driver/src/cypress/cy.coffee index 2f6b7ad2d7d4..76577b81a654 100644 --- a/packages/driver/src/cypress/cy.coffee +++ b/packages/driver/src/cypress/cy.coffee @@ -119,25 +119,25 @@ create = (specWindow, Cypress, Cookies, state, config, log) -> timers.reset() - Cypress.action("app:window:before:unload", e) + Cypress.action("app:before:window:unload", e) ## return undefined so our beforeunload handler ## doesnt trigger a confirmation dialog return undefined onUnload: (e) -> - Cypress.action("app:window:unload", e) + Cypress.action("app:page:end", e) onNavigation: (args...) -> Cypress.action("app:navigation:changed", args...) onAlert: (str) -> - Cypress.action("app:window:alert", str) + Cypress.action("app:page:alert", str) onConfirm: (str) -> - results = Cypress.action("app:window:confirm", str) + results = Cypress.action("app:page:confirm", str) ## return false if ANY results are false ## else true ret = !_.some(results, returnedFalse) - Cypress.action("app:window:confirmed", str, ret) + Cypress.action("app:page:confirmed", str, ret) return ret }) @@ -354,7 +354,7 @@ create = (specWindow, Cypress, Cookies, state, config, log) -> if not command ## trigger queue is almost finished - Cypress.action("cy:command:queue:before:end") + Cypress.action("cy:before:command:queue:end") ## we need to wait after all commands have ## finished running if the application under @@ -563,8 +563,8 @@ create = (specWindow, Cypress, Cookies, state, config, log) -> ## 1. callback with state("done") when async ## 2. throw the error for the promise chain try - ## collect all of the callbacks for 'fail' - rets = Cypress.action("cy:fail", err, state("runnable")) + ## collect all of the callbacks for 'test:fail' + rets = Cypress.action("cy:test:fail", err, state("runnable")) catch err2 ## and if any of these throw synchronously immediately error finish(err2) @@ -676,7 +676,7 @@ create = (specWindow, Cypress, Cookies, state, config, log) -> ## by trying to talk to the contentWindow document to see if ## its accessible. ## when we find ourselves in a cross origin situation, then our - ## proxy has not injected Cypress.action('window:before:load') + ## proxy has not injected Cypress.action('page:start') ## so Cypress.onBeforeAppWindowLoad() was never called $autIframe.on "load", -> ## if setting these props failed @@ -693,7 +693,7 @@ create = (specWindow, Cypress, Cookies, state, config, log) -> ## about:blank in a visit, we do need these contentWindowListeners(getContentWindow($autIframe)) - Cypress.action("app:window:load", state("window")) + Cypress.action("app:page:ready", state("window")) ## we are now stable again which is purposefully ## the last event we call here, to give our event @@ -906,9 +906,9 @@ create = (specWindow, Cypress, Cookies, state, config, log) -> timers.wrap(contentWindow) - onSpecWindowUncaughtException: -> + onSpecWindowUncaughtException: (args...) -> ## create the special uncaught exception err - err = errors.createUncaughtException("spec", arguments) + err = errors.createUncaughtException("spec", args) if runnable = state("runnable") ## we're using an explicit done callback here @@ -1088,6 +1088,8 @@ create = (specWindow, Cypress, Cookies, state, config, log) -> $Events.extend(cy) + $Events.throwOnRenamedEvent(cy, "cy") + return cy module.exports = { diff --git a/packages/driver/src/cypress/error_messages.coffee b/packages/driver/src/cypress/error_messages.coffee index d498a3ff38ac..7098362252ad 100644 --- a/packages/driver/src/cypress/error_messages.coffee +++ b/packages/driver/src/cypress/error_messages.coffee @@ -213,6 +213,18 @@ module.exports = { invalid_argument: "#{cmd('each')} must be passed a callback function." non_array: "#{cmd('each')} can only operate on an array like subject. Your subject was: '{{subject}}'" + events: + renamed_event: """The '{{oldEvent}}' event has been renamed to '{{newEvent}}'. + + Please change: + + {{object}}.{{method}}('{{oldEvent}}', ) + + to: + + {{object}}.{{method}}('{{newEvent}}', ) + """ + exec: failed: """#{cmd('exec', '\'{{cmd}}\'')} failed with the following error: @@ -848,6 +860,8 @@ module.exports = { When Cypress detects uncaught errors originating from your test code it will automatically fail the current test. """ + fromCypress: "" + viewport: bad_args: "#{cmd('viewport')} can only accept a string preset or a width and height as numbers." dimensions_out_of_range: "#{cmd('viewport')} width and height must be between 20px and 3000px." @@ -943,6 +957,21 @@ module.exports = { #{cmd('request')} will automatically get and set cookies and enable you to parse responses. """ + renamed_callback: """ + The '{{oldName}}' callback for #{cmd('visit')} has been renamed to '{{newName}}'. + + Please change: + + cy.visit({ + {{oldName}} () {} + }) + + to: + + cy.visit({ + {{newName}} () {} + }) + """ wait: alias_invalid: "'{{prop}}' is not a valid alias property. Are you trying to ask for the first request? If so write @{{str}}.request" diff --git a/packages/driver/src/cypress/events.coffee b/packages/driver/src/cypress/events.coffee index 6bc044cd7f0e..f491844121c2 100644 --- a/packages/driver/src/cypress/events.coffee +++ b/packages/driver/src/cypress/events.coffee @@ -1,17 +1,10 @@ -# _ = require("lodash") -# Backbone = require("backbone") - -## adds a custom lightweight event bus -## to the Cypress class - -# splice = (index) -> - # @_events.splice(index, 1) - _ = require("lodash") EE = require("eventemitter2") log = require("debug")("cypress:driver") Promise = require("bluebird") +$utils = require("./utils") + proxyFunctions = "emit emitThen emitMap".split(" ") withoutFunctions = (arr) -> @@ -108,8 +101,46 @@ module.exports = { return ret + events.emitToBackend = (eventName, args...) -> + args = _.reject(args, _.isFunction) + Cypress.backend("driver:event", eventName, args...) + _.extend(obj, events) ## return the events object return events + + throwOnRenamedEvent: (eventEmitter, name) -> + renamedEvents = { + "command:queue:before:end": "before:command:queue:end" + "fail": "test:fail" + "runnable:after:run:async": "after:runnable:run:async" + "scrolled": "internal:scrolled" + "test:after:run": "test:run:end" + "test:before:run": "test:run:start" + "test:before:run:async": "test:run:start:async" + "url:changed": "page:url:changed" + "window:alert": "page:alert" + "window:before:load": "page:start" + "window:before:unload": "before:window:unload" + "window:confirm": "page:confirm" + "window:unload": "page:end" + } + + methods = "addListener on once prependListener prependOnceListener".split(" ") + + _.each methods, (method) -> + eventEmitter[method] = _.wrap eventEmitter[method], (original, eventName, listener) -> + if renamedEvents[eventName] + $utils.throwErrByPath("events.renamed_event", { + args: { + oldEvent: eventName + newEvent: renamedEvents[eventName] + object: name + method: method + } + from: "cypress" + }) + else + original.call(@, eventName, listener) } diff --git a/packages/driver/src/cypress/log.coffee b/packages/driver/src/cypress/log.coffee index 372fd1487777..c479a57789ca 100644 --- a/packages/driver/src/cypress/log.coffee +++ b/packages/driver/src/cypress/log.coffee @@ -147,7 +147,7 @@ defaults = (state, config, obj) -> instrument: "command" url: state("url") hookName: state("hookName") - testId: state("runnable").id + testId: state("runnable")?.id viewportWidth: state("viewportWidth") viewportHeight: state("viewportHeight") referencesAlias: undefined diff --git a/packages/driver/src/cypress/runner.coffee b/packages/driver/src/cypress/runner.coffee index d375c9f80a9a..aefaedb1d727 100644 --- a/packages/driver/src/cypress/runner.coffee +++ b/packages/driver/src/cypress/runner.coffee @@ -10,8 +10,8 @@ mochaCtxKeysRe = /^(_runnable|test)$/ betweenQuotesRe = /\"(.+?)\"/ HOOKS = "beforeAll beforeEach afterEach afterAll".split(" ") -TEST_BEFORE_RUN_EVENT = "runner:test:before:run" -TEST_AFTER_RUN_EVENT = "runner:test:after:run" +TEST_RUN_START_EVENT = "runner:test:run:start" +TEST_RUN_END_EVENT = "runner:test:run:end" ERROR_PROPS = "message type name stack fileName lineNumber columnNumber host uncaught actual expected showDiff isPending".split(" ") RUNNABLE_LOGS = "routes agents commands".split(" ") @@ -77,18 +77,18 @@ fired = (event, runnable) -> testBeforeRunAsync = (test, Cypress) -> Promise.try -> - if not fired("runner:test:before:run:async", test) - fire("runner:test:before:run:async", test, Cypress) + if not fired("runner:test:run:start:async", test) + fire("runner:test:run:start:async", test, Cypress) runnableAfterRunAsync = (runnable, Cypress) -> Promise.try -> - if not fired("runner:runnable:after:run:async", runnable) - fire("runner:runnable:after:run:async", runnable, Cypress) + if not fired("runner:after:runnable:run:async", runnable) + fire("runner:after:runnable:run:async", runnable, Cypress) testAfterRun = (test, Cypress) -> - if not fired(TEST_AFTER_RUN_EVENT, test) + if not fired(TEST_RUN_END_EVENT, test) setWallClockDuration(test) - fire(TEST_AFTER_RUN_EVENT, test, Cypress) + fire(TEST_RUN_END_EVENT, test, Cypress) ## perf loop only through ## a tests OWN properties and not @@ -266,7 +266,7 @@ overrideRunnerHook = (Cypress, _runner, getTestById, getTest, setTest, getTests) return if not _runner.hook ## monkey patch the hook event so we can wrap - ## 'test:after:run' around all of + ## 'test:run:end' around all of ## the hooks surrounding a test runnable _runnerHook = _runner.hook @@ -511,7 +511,7 @@ _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, setTest, hook.ctx.currentTest = test ## make sure we set this test as the current now - ## else its possible that our TEST_AFTER_RUN_EVENT + ## else its possible that our TEST_RUN_END_EVENT ## will never fire if this failed in a before hook setTest(test) @@ -546,8 +546,8 @@ _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, setTest, ## do nothing if our test is skipped return if test._ALREADY_RAN - if not fired(TEST_BEFORE_RUN_EVENT, test) - fire(TEST_BEFORE_RUN_EVENT, test, Cypress) + if not fired(TEST_RUN_START_EVENT, test) + fire(TEST_RUN_START_EVENT, test, Cypress) test.state = "pending" @@ -560,12 +560,12 @@ _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, setTest, @emit("test", test) ## if this is not the last test amongst its siblings - ## then go ahead and fire its test:after:run event + ## then go ahead and fire its test:run:end event ## else this will not get called tests = getAllSiblingTests(test.parent, getTestById) if _.last(tests) isnt test - fire(TEST_AFTER_RUN_EVENT, test, Cypress) + fire(TEST_RUN_END_EVENT, test, Cypress) _runner.on "fail", (runnable, err) -> isHook = runnable.type is "hook" @@ -598,13 +598,13 @@ _runnerListeners = (_runner, Cypress, _emissions, getTestById, getTest, setTest, ## it means that this runnable likely failed due to ## a double done(err) callback, and we need to fire ## this again! - if fired(TEST_AFTER_RUN_EVENT, runnable) - fire(TEST_AFTER_RUN_EVENT, runnable, Cypress) + if fired(TEST_RUN_END_EVENT, runnable) + fire(TEST_RUN_END_EVENT, runnable, Cypress) if isHook ## if a hook fails (such as a before) then the test will never ## get run and we'll need to make sure we set the test so that - ## the TEST_AFTER_RUN_EVENT fires correctly + ## the TEST_RUN_END_EVENT fires correctly hookFailed(runnable, runnable.err, hookName, getTestById, getTest) create = (specWindow, mocha, Cypress, cy) -> @@ -753,7 +753,7 @@ create = (specWindow, mocha, Cypress, cy) -> ## closure for calculating the actual ## runtime of a runnables fn exection duration - ## and also the run of the runnable:after:run:async event + ## and also the run of the after:runnable:run:async event wallClockStartedAt = null wallClockEnd = null fnDurationStart = null @@ -779,8 +779,8 @@ create = (specWindow, mocha, Cypress, cy) -> ## that means that we need to reset the previous state ## of cy - since we now have a new 'test' and all of the ## associated _runnables will share this state - if not fired(TEST_BEFORE_RUN_EVENT, test) - fire(TEST_BEFORE_RUN_EVENT, test, Cypress) + if not fired(TEST_RUN_START_EVENT, test) + fire(TEST_RUN_START_EVENT, test, Cypress) ## extract out the next(fn) which mocha uses to ## move to the next runnable - this will be our async seam @@ -867,7 +867,7 @@ create = (specWindow, mocha, Cypress, cy) -> ## whenever any runnable is about to run ## we figure out what test its associated to ## if its a hook, and then we fire the - ## test:before:run:async action if its not + ## test:run:start:async action if its not ## been fired before for this test testBeforeRunAsync(test, Cypress) .catch (err) -> diff --git a/packages/driver/src/cypress/utils.coffee b/packages/driver/src/cypress/utils.coffee index 2ffb5c277a09..5bbc33c9face 100644 --- a/packages/driver/src/cypress/utils.coffee +++ b/packages/driver/src/cypress/utils.coffee @@ -95,6 +95,7 @@ module.exports = { command.error(err) err.onFail = onFail if onFail + err.from = options.from throw err @@ -117,7 +118,8 @@ module.exports = { err errMessageByPath: (errPath, args) -> - if not errMessage = @getObjValueByPath($errorMessages, errPath) + errMessage = @getObjValueByPath($errorMessages, errPath) + if not errMessage? throw new Error "Error message path '#{errPath}' does not exist" getMsg = -> diff --git a/packages/driver/test/cypress/fixtures/sinon.html b/packages/driver/test/cypress/fixtures/sinon.html index c149f8ad2167..68ef2b60f535 100644 --- a/packages/driver/test/cypress/fixtures/sinon.html +++ b/packages/driver/test/cypress/fixtures/sinon.html @@ -13,7 +13,7 @@ if (!Cypress) { throw new Error('Cypress must exist in the parent window!'); }; - Cypress.onBeforeLoad(window); + Cypress.onStart(window); diff --git a/packages/driver/test/cypress/fixtures/sync_error.html b/packages/driver/test/cypress/fixtures/sync_error.html index 045ce07347fd..e24eb294851b 100644 --- a/packages/driver/test/cypress/fixtures/sync_error.html +++ b/packages/driver/test/cypress/fixtures/sync_error.html @@ -15,7 +15,7 @@ if (!Cypress) { throw new Error('Cypress must exist in the parent window!'); }; - Cypress.onBeforeLoad(window); + Cypress.onStart(window); ` }, diff --git a/packages/server/test/e2e/6_visit_spec.coffee b/packages/server/test/e2e/6_visit_spec.coffee index 7dd39c3b5ccc..af2e96e61871 100644 --- a/packages/server/test/e2e/6_visit_spec.coffee +++ b/packages/server/test/e2e/6_visit_spec.coffee @@ -108,7 +108,7 @@ describe "e2e visit", -> expectedExitCode: 1 }) - it "calls onBeforeLoad when overwriting cy.visit", -> + it "calls onStart when overwriting cy.visit", -> e2e.exec(@, { spec: "issue_2196_spec.coffee" }) diff --git a/packages/server/test/e2e/background_driver_events_spec.coffee b/packages/server/test/e2e/background_driver_events_spec.coffee new file mode 100644 index 000000000000..17ffcfc18a11 --- /dev/null +++ b/packages/server/test/e2e/background_driver_events_spec.coffee @@ -0,0 +1,15 @@ +# path = require("path") + +e2e = require("../support/helpers/e2e") +Fixtures = require("../support/helpers/fixtures") + +describe "e2e plugins", -> + e2e.setup() + + it "sends driver events", -> + e2e.exec(@, { + spec: "background_driver_events_spec.coffee" + project: Fixtures.projectPath("background-driver-events") + snapshot: true + expectedExitCode: 1 + }) diff --git a/packages/server/test/integration/server_spec.coffee b/packages/server/test/integration/server_spec.coffee index afcf53706828..f30bfffbde94 100644 --- a/packages/server/test/integration/server_spec.coffee +++ b/packages/server/test/integration/server_spec.coffee @@ -136,7 +136,7 @@ describe "Server", -> expect(res.headers["cache-control"]).to.eq("no-cache, no-store, must-revalidate") expect(res.body).to.include("index.html content") expect(res.body).to.include("document.domain = 'localhost'") - expect(res.body).to.include("Cypress.action('app:window:before:load', window); \n ") + expect(res.body).to.include("Cypress.action('app:page:start', window); \n ") it "sends back the content type", -> @server._onResolveUrl("/assets/foo.json", {}, @automationRequest) @@ -321,7 +321,7 @@ describe "Server", -> expect(res.headers["cache-control"]).to.eq("no-cache, no-store, must-revalidate") expect(res.body).to.include("content") expect(res.body).to.include("document.domain = 'getbootstrap.com'") - expect(res.body).to.include("Cypress.action('app:window:before:load', window); content") + expect(res.body).to.include("Cypress.action('app:page:start', window); content") it "sends back the content type", -> nock("http://getbootstrap.com") @@ -381,7 +381,7 @@ describe "Server", -> expect(res.statusCode).to.eq(200) expect(res.body).to.include("content") expect(res.body).to.include("document.domain = 'go.com'") - expect(res.body).to.include("Cypress.action('app:window:before:load', window); content") + expect(res.body).to.include("Cypress.action('app:page:start', window); content") expect(@server._getRemoteState()).to.deep.eq({ auth: undefined @@ -459,7 +459,7 @@ describe "Server", -> expect(res.statusCode).to.eq(200) expect(res.body).to.include("document.domain") expect(res.body).to.include("go.com") - expect(res.body).to.include("Cypress.action('app:window:before:load', window); espn") + expect(res.body).to.include("Cypress.action('app:page:start', window); espn") expect(buffers.keys()).to.deep.eq([]) it "does not buffer 'bad' responses", -> @@ -616,7 +616,7 @@ describe "Server", -> expect(res.headers["cache-control"]).to.eq("no-cache, no-store, must-revalidate") expect(res.body).to.include("content") expect(res.body).to.include("document.domain = 'google.com'") - expect(res.body).to.include("Cypress.action('app:window:before:load', window); content") + expect(res.body).to.include("Cypress.action('app:page:start', window); content") it "passes auth through", -> username = "u" @@ -805,7 +805,7 @@ describe "Server", -> expect(res.statusCode).to.eq(200) expect(res.body).to.include("document.domain") expect(res.body).to.include("google.com") - expect(res.body).to.include("Cypress.action('app:window:before:load', window); google") + expect(res.body).to.include("Cypress.action('app:page:start', window); google") .then => expect(@server._getRemoteState()).to.deep.eq({ auth: undefined @@ -841,7 +841,7 @@ describe "Server", -> expect(res.statusCode).to.eq(200) expect(res.body).to.include("document.domain") expect(res.body).to.include("localhost") - expect(res.body).to.include("Cypress.action('app:window:before:load', window); \n ") + expect(res.body).to.include("Cypress.action('app:page:start', window); \n ") .then => expect(@server._getRemoteState()).to.deep.eq({ auth: undefined @@ -872,7 +872,7 @@ describe "Server", -> expect(res.statusCode).to.eq(200) expect(res.body).to.include("document.domain") expect(res.body).to.include("google.com") - expect(res.body).to.include("Cypress.action('app:window:before:load', window); google") + expect(res.body).to.include("Cypress.action('app:page:start', window); google") .then => expect(@server._getRemoteState()).to.deep.eq({ auth: undefined @@ -910,7 +910,7 @@ describe "Server", -> expect(res.statusCode).to.eq(200) expect(res.body).to.include("document.domain") expect(res.body).to.include("foobar.com") - expect(res.body).to.include("Cypress.action('app:window:before:load', window); https server") + expect(res.body).to.include("Cypress.action('app:page:start', window); https server") .then => expect(@server._getRemoteState()).to.deep.eq({ auth: undefined @@ -946,7 +946,7 @@ describe "Server", -> expect(res.statusCode).to.eq(200) expect(res.body).to.include("document.domain") expect(res.body).to.include("localhost") - expect(res.body).to.include("Cypress.action('app:window:before:load', window); \n ") + expect(res.body).to.include("Cypress.action('app:page:start', window); \n ") .then => expect(@server._getRemoteState()).to.deep.eq({ auth: undefined @@ -977,7 +977,7 @@ describe "Server", -> expect(res.statusCode).to.eq(200) expect(res.body).to.include("document.domain") expect(res.body).to.include("foobar.com") - expect(res.body).to.include("Cypress.action('app:window:before:load', window); https server") + expect(res.body).to.include("Cypress.action('app:page:start', window); https server") .then => expect(@server._getRemoteState()).to.deep.eq({ auth: undefined @@ -1060,7 +1060,7 @@ describe "Server", -> expect(res.statusCode).to.eq(200) expect(res.body).to.include("document.domain") expect(res.body).to.include("localhost") - expect(res.body).to.include("Cypress.action('app:window:before:load', window); \n ") + expect(res.body).to.include("Cypress.action('app:page:start', window); \n ") .then => expect(@server._getRemoteState()).to.deep.eq({ auth: undefined diff --git a/packages/server/test/support/fixtures/projects/background-driver-events/cypress.json b/packages/server/test/support/fixtures/projects/background-driver-events/cypress.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/packages/server/test/support/fixtures/projects/background-driver-events/cypress.json @@ -0,0 +1 @@ +{} diff --git a/packages/server/test/support/fixtures/projects/background-driver-events/cypress/background/index.js b/packages/server/test/support/fixtures/projects/background-driver-events/cypress/background/index.js new file mode 100644 index 000000000000..88cd82c50422 --- /dev/null +++ b/packages/server/test/support/fixtures/projects/background-driver-events/cypress/background/index.js @@ -0,0 +1,36 @@ +/* eslint-disable no-console */ + +module.exports = (on) => { + on('test:run:start', (test) => { + console.log('test:run:start:', test.title) + throw new Error('Error thrown synchronously from "test:run:start". Should be ignored.') + }) + + on('command:enqueued', (command) => { + console.log('command:enqueued:', command.name, command.args.join(', ')) + }) + + on('command:start', (command) => { + console.log('command:start:', command.name, command.args.join(', ')) + }) + + // only do this once or it's a lot of logging + let retryCalled = false + + on('command:retry', (retry) => { + if (retryCalled) return + + retryCalled = true + console.log('command:retry:', retry.name, retry.error.message) + }) + + on('command:end', (command) => { + console.log('command:end:', command.name, command.args.join(', ')) + }) + + on('test:run:end', (test) => { + console.log('test:run:end:', test.title) + + return Promise.reject(new Error('Error thrown in promise from "test:run:end". Should be ignored.')) + }) +} diff --git a/packages/server/test/support/fixtures/projects/background-driver-events/cypress/integration/background_driver_events_spec.coffee b/packages/server/test/support/fixtures/projects/background-driver-events/cypress/integration/background_driver_events_spec.coffee new file mode 100644 index 000000000000..744758cbd29a --- /dev/null +++ b/packages/server/test/support/fixtures/projects/background-driver-events/cypress/integration/background_driver_events_spec.coffee @@ -0,0 +1,3 @@ +it "fails to get", -> + cy.log("you had logs?") + cy.get("#non-existent") diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/async_timeouts_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/async_timeouts_spec.coffee index e54da4e1447a..e94ef935128d 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/async_timeouts_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/async_timeouts_spec.coffee @@ -2,7 +2,7 @@ describe "async", -> it.only "bar fails", (done) -> @timeout(100) - cy.on "fail", -> + cy.on "test:fail", -> ## async caught fail foo.bar() diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/caught_async_sync_test_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/caught_async_sync_test_spec.coffee index 2d6714688489..ff3cbf87958a 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/caught_async_sync_test_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/caught_async_sync_test_spec.coffee @@ -14,7 +14,7 @@ describe "foo", -> foo.bar() it "quux2 fails", (done) -> - cy.on "fail", -> + cy.on "test:fail", -> foo.bar() ## commands caught never calling done @@ -23,7 +23,7 @@ describe "foo", -> foo.bar() it "quux3 passes", (done) -> - cy.on "fail", -> + cy.on "test:fail", -> done() ## commands caught with a fail handler @@ -32,7 +32,7 @@ describe "foo", -> foo.bar() it "quux4 passes", -> - cy.on "fail", -> + cy.on "test:fail", -> ## commands caught with a fail handler ## and no done callback will pass if @@ -41,13 +41,13 @@ describe "foo", -> foo.bar() it "quux5 passes", -> - cy.on "fail", -> + cy.on "test:fail", -> ## no commands fail handler should pass foo.bar() it "quux6 passes", (done) -> - cy.on "fail", -> + cy.on "test:fail", -> done() ## no commands fail async handler should pass diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/hook_caught_error_failing_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/hook_caught_error_failing_spec.coffee index 06932c02e288..32196dd98f2e 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/hook_caught_error_failing_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/hook_caught_error_failing_spec.coffee @@ -1,7 +1,7 @@ -testAfterRuns = [] +testRunEnds = [] -Cypress.on "test:after:run", (test) -> - testAfterRuns.push(test.title) +Cypress.on "test:run:end", (test) -> + testRunEnds.push(test.title) ## this should run it "t1a", -> @@ -27,9 +27,9 @@ describe "s3a", -> throw new Error("s3a before hook failed") after -> - ## it should not have fired test:after:run + ## it should not have fired test:run:end ## for t8a yet - expect(testAfterRuns).to.deep.eq([ + expect(testRunEnds).to.deep.eq([ "t1a" "t2a" "t5a" @@ -47,8 +47,8 @@ describe "s4a", -> it "t10a", -> describe "s5a", -> - it "fires all test:after:run events", -> - expect(testAfterRuns).to.deep.eq([ + it "fires all test:run:end events", -> + expect(testRunEnds).to.deep.eq([ "t1a" "t2a" "t5a" diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/hook_uncaught_error_events_failing_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/hook_uncaught_error_events_failing_spec.coffee index 6e7b4931b8a7..80e36ff86919 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/hook_uncaught_error_events_failing_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/hook_uncaught_error_events_failing_spec.coffee @@ -4,11 +4,11 @@ afterVisitCommand = false runnableAfterRunAsync = [] testAfterRun = [] -Cypress.on "runnable:after:run:async", (obj, runnable) -> +Cypress.on "after:runnable:run:async", (obj, runnable) -> if obj.err runnableAfterRunAsync.push(obj.title) -Cypress.on "test:after:run", (test) -> +Cypress.on "test:run:end", (test) -> testAfterRun.push(test.title) describe "uncaught hook error should continue to fire all mocha events", -> @@ -44,10 +44,10 @@ describe "uncaught hook error should continue to fire all mocha events", -> '"before each" hook' ]) - ## our last test here has not yet pushed into test:after:run + ## our last test here has not yet pushed into test:run:end expect(testAfterRun).to.deep.eq([ ## even though the test code itself did not - ## run, we should still receive a test:after:run + ## run, we should still receive a test:run:end ## event for this "does not run", diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/iframe_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/iframe_spec.coffee index 554d9662f779..5ebb2dfc8916 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/iframe_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/iframe_spec.coffee @@ -2,7 +2,7 @@ count = 0 action = Cypress.action Cypress.action = (str) -> - if str is "app:window:before:load" + if str is "app:page:start" count += 1 action.apply(@, arguments) @@ -14,7 +14,7 @@ ensureWeCanTalkToTheIframe = ($iframe) -> expect($iframe.get(0).contentWindow.foo).to.eq("bar") - ## onBeforeLoad should only be called once + ## onStart should only be called once ## on the initial visit and not for the iframe ## ## the reason this number is still 1 instead of 2 diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/issue_2196_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/issue_2196_spec.coffee index 6c62904cd957..0791cfde735e 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/issue_2196_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/issue_2196_spec.coffee @@ -1,13 +1,13 @@ -onBeforeLoad = cy.stub() -onLoad = cy.stub() +onStart = cy.stub() +onReady = cy.stub() Cypress.Commands.overwrite "visit", (originalVisit, url, options) -> - return originalVisit(url, { onBeforeLoad, onLoad }) + return originalVisit(url, { onStart, onReady }) context "issue #2196: overwriting visit", -> - it "fires onBeforeLoad", -> + it "fires onStart", -> cy .visit("http://localhost:3434/index.html") .then -> - expect(onBeforeLoad).to.be.called - expect(onLoad).to.be.called + expect(onStart).to.be.called + expect(onReady).to.be.called diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/uncaught_during_hook_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/uncaught_during_hook_spec.coffee index 7dbeb737cdc9..7cdd335f9c37 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/uncaught_during_hook_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/uncaught_during_hook_spec.coffee @@ -1,6 +1,6 @@ testAfterRunEvent = false -Cypress.on "test:after:run", (obj) -> +Cypress.on "test:run:end", (obj) -> if obj.title is "does not run" testAfterRunEvent = true diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/visit_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/visit_spec.coffee index 04a660299b48..b4c8910f44b6 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/visit_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/visit_spec.coffee @@ -31,7 +31,7 @@ describe "visits", -> {origin} = Cypress.Location.create(window.location.href) - cy.on "window:load", -> + cy.on "page:ready", -> urls.push cy.getRemoteLocation("href") count += 1 diff --git a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/xhr_spec.coffee b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/xhr_spec.coffee index 5165968fc0d8..eddc1c07278a 100644 --- a/packages/server/test/support/fixtures/projects/e2e/cypress/integration/xhr_spec.coffee +++ b/packages/server/test/support/fixtures/projects/e2e/cypress/integration/xhr_spec.coffee @@ -109,7 +109,7 @@ describe "xhrs", -> .get("#create").click() .then -> ## simulate an open request which should become - ## aborted due to window:unload event - Cypress.action("app:window:unload", {}) + ## aborted due to page:end event + Cypress.action("app:page:end", {}) .wait("@createUser").its("aborted").should("be.true") diff --git a/packages/server/test/support/fixtures/projects/non-existent-spec/cypress/background/index.js b/packages/server/test/support/fixtures/projects/non-existent-spec/cypress/background/index.js index 8927c8e12bd6..a0c410cc43c0 100644 --- a/packages/server/test/support/fixtures/projects/non-existent-spec/cypress/background/index.js +++ b/packages/server/test/support/fixtures/projects/non-existent-spec/cypress/background/index.js @@ -1,3 +1,5 @@ module.exports = (on) => { - on('file:preprocessor', () => '/does/not/exist.js') + on('file:preprocessor', () => { + return '/does/not/exist.js' + }) } diff --git a/packages/server/test/support/fixtures/server/absolute_url_expected.html b/packages/server/test/support/fixtures/server/absolute_url_expected.html index 2a47de7764e0..96f9b61b3872 100644 --- a/packages/server/test/support/fixtures/server/absolute_url_expected.html +++ b/packages/server/test/support/fixtures/server/absolute_url_expected.html @@ -14,7 +14,7 @@ } absolute url test diff --git a/packages/server/test/support/fixtures/server/expected_head_inject.html b/packages/server/test/support/fixtures/server/expected_head_inject.html index 1e2cac8c2d11..25e2813d2475 100644 --- a/packages/server/test/support/fixtures/server/expected_head_inject.html +++ b/packages/server/test/support/fixtures/server/expected_head_inject.html @@ -9,7 +9,7 @@ throw new Error('Something went terribly wrong and we cannot proceed. We expected to find the global Cypress in the parent window but it is missing!. This should never happen and likely is a bug. Please open an issue!'); }; - Cypress.action('app:window:before:load', window); + Cypress.action('app:page:start', window); diff --git a/packages/server/test/support/fixtures/server/expected_https_inject.html b/packages/server/test/support/fixtures/server/expected_https_inject.html index 26b5f25aba37..a6558f7ad915 100644 --- a/packages/server/test/support/fixtures/server/expected_https_inject.html +++ b/packages/server/test/support/fixtures/server/expected_https_inject.html @@ -7,5 +7,5 @@ throw new Error('Something went terribly wrong and we cannot proceed. We expected to find the global Cypress in the parent window but it is missing!. This should never happen and likely is a bug. Please open an issue!'); }; - Cypress.action('app:window:before:load', window); + Cypress.action('app:page:start', window); https server diff --git a/packages/server/test/support/fixtures/server/expected_no_head_tag_inject.html b/packages/server/test/support/fixtures/server/expected_no_head_tag_inject.html index 1c2f09d60fe0..080850122225 100644 --- a/packages/server/test/support/fixtures/server/expected_no_head_tag_inject.html +++ b/packages/server/test/support/fixtures/server/expected_no_head_tag_inject.html @@ -9,7 +9,7 @@ throw new Error('Something went terribly wrong and we cannot proceed. We expected to find the global Cypress in the parent window but it is missing!. This should never happen and likely is a bug. Please open an issue!'); }; - Cypress.action('app:window:before:load', window); + Cypress.action('app:page:start', window); hello from bar! diff --git a/packages/server/test/unit/background/child/run_background_spec.coffee b/packages/server/test/unit/background/child/run_background_spec.coffee index 40a818fa7a3c..32ad894830c7 100644 --- a/packages/server/test/unit/background/child/run_background_spec.coffee +++ b/packages/server/test/unit/background/child/run_background_spec.coffee @@ -138,7 +138,7 @@ describe "lib/background/child/run_background", -> it "invokes registered function when invoked by preprocessor handler", -> @ipc.on.withArgs("execute").yield("file:preprocessor", @ids, []) - preprocessor.wrap.lastCall.args[1](2, ["one", "two"]) + preprocessor.wrap.lastCall.args[1](3, ["one", "two"]) expect(@onFilePreprocessor).to.be.calledWith("one", "two") context "before:browser:launch", -> @@ -158,7 +158,7 @@ describe "lib/background/child/run_background", -> it "invokes registered function when invoked by preprocessor handler", -> @ipc.on.withArgs("execute").yield("before:browser:launch", @ids, []) args = ["one", "two"] - util.wrapChildPromise.lastCall.args[1](3, args) + util.wrapChildPromise.lastCall.args[1](4, args) expect(@beforeBrowserLaunch).to.be.calledWith("one", "two") context "task", -> From d5bf6932ed5cd5e8222f561ff091a3f1c3f5b906 Mon Sep 17 00:00:00 2001 From: Lila Conlee Date: Wed, 5 Dec 2018 12:10:01 -0500 Subject: [PATCH 07/37] Upgrade to Chai 4 (#2862) * Initial upgrade changes * Some quick fixes * More fixes * Clean up exp logic and fix spread array failures * Remove caret from package.json * Add handling for proxies in isJquery * iterate on flaky test, increase default command timeout --- packages/driver/package.json | 2 +- packages/driver/src/cy/commands/asserting.coffee | 10 +++++++--- packages/driver/src/cy/commands/connectors.coffee | 5 ++++- packages/driver/src/dom/jquery.coffee | 5 ++++- .../cypress/integration/commands/agents_spec.coffee | 2 +- .../cypress/integration/commands/aliasing_spec.coffee | 4 ++-- .../integration/commands/assertions_spec.coffee | 8 ++++---- .../integration/commands/navigation_spec.coffee | 4 ++-- .../cypress/integration/commands/querying_spec.coffee | 10 +++++----- .../integration/commands/screenshot_spec.coffee | 2 +- .../test/cypress/integration/cypress/cy_spec.coffee | 8 ++++---- .../cypress/integration/cypress/cypress_spec.coffee | 2 +- 12 files changed, 36 insertions(+), 26 deletions(-) diff --git a/packages/driver/package.json b/packages/driver/package.json index f6e048086af3..b767b7dc41c5 100644 --- a/packages/driver/package.json +++ b/packages/driver/package.json @@ -30,7 +30,7 @@ "bootstrap": "^3.3.5", "bytes": "^3.0.0", "card": "^1.0.2", - "chai": "3.5.0", + "chai": "4.2.0", "chai-as-promised": "6.0.0", "chokidar-cli": "^1.2.0", "clone": "^2.1.1", diff --git a/packages/driver/src/cy/commands/asserting.coffee b/packages/driver/src/cy/commands/asserting.coffee index 386446597410..49dfb3ca738b 100644 --- a/packages/driver/src/cy/commands/asserting.coffee +++ b/packages/driver/src/cy/commands/asserting.coffee @@ -92,7 +92,7 @@ module.exports = (Commands, Cypress, cy, state, config) -> ## are we doing a length assertion? if reHaveLength.test(chainers) or reExistence.test(chainers) - exp.isCheckingExistence = true + isCheckingExistence = true applyChainer = (memo, value) -> if value is lastChainer @@ -108,6 +108,8 @@ module.exports = (Commands, Cypress, cy, state, config) -> throwAndLogErr(err) else throw err + else + memo[value] else memo[value] @@ -118,10 +120,10 @@ module.exports = (Commands, Cypress, cy, state, config) -> ## because its possible we're asserting about an ## element which has left the DOM and we always ## want to auto-fail on those - if not exp.isCheckingExistence and $dom.isElement(subject) + if not isCheckingExistence and $dom.isElement(subject) cy.ensureAttached(subject, "should") - _.reduce chainers, (memo, value) => + newExp = _.reduce chainers, (memo, value) => if value not of memo err = $utils.cypressErr("The chainer: '#{value}' was not found. Could not build assertion.") err.retry = false @@ -131,6 +133,8 @@ module.exports = (Commands, Cypress, cy, state, config) -> , exp + exp = newExp ? exp + Promise.try(applyChainers).then -> ## if the _obj has been mutated then we ## are chaining assertion properties and diff --git a/packages/driver/src/cy/commands/connectors.coffee b/packages/driver/src/cy/commands/connectors.coffee index b5d6894549d1..590c22558bf8 100644 --- a/packages/driver/src/cy/commands/connectors.coffee +++ b/packages/driver/src/cy/commands/connectors.coffee @@ -41,7 +41,10 @@ module.exports = (Commands, Cypress, cy, state, config) -> remoteSubject = cy.getRemotejQueryInstance(subject) args = remoteSubject or subject - args = if subject?._spreadArray then args else [args] + + try + hasSpreadArray = "_spreadArray" in subject or subject?._spreadArray + args = if hasSpreadArray then args else [args] ## name could be invoke or its! name = state("current").get("name") diff --git a/packages/driver/src/dom/jquery.coffee b/packages/driver/src/dom/jquery.coffee index 7173df102150..410b4253fae9 100644 --- a/packages/driver/src/dom/jquery.coffee +++ b/packages/driver/src/dom/jquery.coffee @@ -19,7 +19,10 @@ unwrap = (obj) -> isJquery = (obj) -> ## does it have the jquery property and is the ## constructor a function? - !!(obj and obj.jquery and _.isFunction(obj.constructor)) + try + hasJqueryProperty = "jquery" in obj or obj?.jquery + + !!(hasJqueryProperty and _.isFunction(obj.constructor)) ## doing a little jiggle wiggle here ## to avoid circular dependencies diff --git a/packages/driver/test/cypress/integration/commands/agents_spec.coffee b/packages/driver/test/cypress/integration/commands/agents_spec.coffee index 819d893bbdc1..8fc8bdeb1566 100644 --- a/packages/driver/test/cypress/integration/commands/agents_spec.coffee +++ b/packages/driver/test/cypress/integration/commands/agents_spec.coffee @@ -229,7 +229,7 @@ describe "src/cy/commands/agents", -> expect(@myStub.displayName).to.eq("myStub") it "stores the lookup as an alias", -> - expect(cy.state("aliases").myStub).to.be.defined + expect(cy.state("aliases").myStub).to.exist it "stores the agent as the subject", -> expect(cy.state("aliases").myStub.subject).to.eq(@stub) diff --git a/packages/driver/test/cypress/integration/commands/aliasing_spec.coffee b/packages/driver/test/cypress/integration/commands/aliasing_spec.coffee index 9a1912aba8e7..aa3ff4a02a08 100644 --- a/packages/driver/test/cypress/integration/commands/aliasing_spec.coffee +++ b/packages/driver/test/cypress/integration/commands/aliasing_spec.coffee @@ -27,7 +27,7 @@ describe "src/cy/commands/aliasing", -> it "stores the lookup as an alias", -> cy.get("body").as("b").then -> - expect(cy.state("aliases").b).to.be.defined + expect(cy.state("aliases").b).to.exist it "stores the resulting subject as the alias", -> $body = cy.$$("body") @@ -337,7 +337,7 @@ describe "src/cy/commands/aliasing", -> .get("input:first").as("firstInput") .get("div:last").as("lastDiv") .then -> - expect(cy.getAlias("@firstInput")).to.be.defined + expect(cy.getAlias("@firstInput")).to.exist describe "errors", -> it "throws when an alias cannot be found", (done) -> diff --git a/packages/driver/test/cypress/integration/commands/assertions_spec.coffee b/packages/driver/test/cypress/integration/commands/assertions_spec.coffee index 277af58e6d53..0ecffea0c253 100644 --- a/packages/driver/test/cypress/integration/commands/assertions_spec.coffee +++ b/packages/driver/test/cypress/integration/commands/assertions_spec.coffee @@ -598,7 +598,7 @@ describe "src/cy/commands/assertions", -> expect(log.invoke("consoleProps")).to.deep.eq { Command: "assert" subject: log.get("subject") - Message: "expected to have a property length" + Message: "expected to have property length" } done() @@ -705,7 +705,7 @@ describe "src/cy/commands/assertions", -> if attrs.name is "assert" cy.removeAllListeners("log:added") - expect(log.get("message")).to.eq "expected **