From cd4a16420971511b45a252fd688d0cd3f283e2e3 Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Mon, 3 Dec 2018 11:38:37 -0500 Subject: [PATCH 01/38] 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/38] 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 1e654ae4c95..07b52e35210 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 e76d3a22344..9ed7e5bdb3e 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 46bb20e65ec..c8231f70874 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 4822cf18ffd..250ec141ee8 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 094ab370343..2635c443859 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 f84fc4abd96..450fa6d7e2f 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 16a2479560b..d9922ce5426 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 d350ddcf6b9..3f87ed8d300 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 f053bb92b8e..39e528dcbf5 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 b69c9a1748a..119ff1638a6 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 401ea221e53..2a6b2bb52ac 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 59ef3e286fe..8d1a1b4359b 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 2fa9234c53b..3be054c27ef 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 3d1401eec3b..eaaf85db761 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 b68763ebe72..3c21851db72 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 87373537a42..394c5a191de 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 091c350559b..6825108489b 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 07b5c3e7a84..6e0b097e58a 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 6de9649b0b4..d4e5406a43c 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 3da1fa9a020..f30488387e9 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 04665cf09d3..835d6411b8b 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 78e77b6a33c..adda66ecadd 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 6d07c25a2ae..55265b22ae3 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 f72ecf5d44c..37df8907588 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 5e41ce0e1aa..f7385d35e49 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 475453d1f84..2cda3e6f48e 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 e46ef822b41..3de5d2dc61a 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 7ea59be2b14..80b431bbeb8 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 74872bcba0a..522d8532efc 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 79a5cae2869..39e48346cc6 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 b062a0776bc..12f2167e0dd 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 a2d4f8f8df9..efcd452e422 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 fd170fba691..c24345ace6c 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 2a0b2897b96..2a2566aa120 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 6a35607f5b0..0fa4945e4a1 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 ca97bf2d054..ba2b53fb12e 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 f83161e81f6..64e26ad2f23 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 16f62fe199b..ecfe9bdf67c 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 c8131c8f625..3dc45df70e5 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 e6be56584dc..1c3ab13001f 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 69ab538318e..2021873dfe3 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 4514809bad5..b14ffa5dfa4 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 54335fa32cc..023a0195902 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 dc571efad3e..f94f0967930 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 a1c89b7e5c5..56c94a44d08 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 00000000000..3125256ff87 --- /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 3c820a6df50..00000000000 --- 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 52061f4e9f4..199afc2081d 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 f9b775a5dc6..0150fa9f0f9 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 b8d13e1d407..f4b1c50080c 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 07361693502..c458db4921a 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 30ae3627088..5b6f065af41 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 8b956d3b0bc..7e51e3d5e5d 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 00000000000..0967ef424bc --- /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 00000000000..346e8e5a9db --- /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 00000000000..0c0c42d5b58 --- /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 eb208051ffc..0673b06fbad 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 00000000000..8c66f332da0 --- /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 2979d06e965..00000000000 --- 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 36c4bc6705c..704129728ae 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 c98ed7c0b3a..dd656e08406 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 b518660ca06..cb1f2b4bcb6 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 ea3a64145d0..1d6b8d335e1 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 8a030398dd3..40a818fa7a3 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 43013c65507..f4a1f6d4ae3 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 aecd6cb4d81..2243f82b60e 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 a5d83657a6b..c4cabca99b9 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 268128fb017..3c0d30664db 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 be273232e55..9a31fc073bf 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 fecd6391258..ca203167754 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 371a133173e..3e4b77f8484 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 4db1a000db1..d3e608238c8 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 ebcbf1d2003..be18eabdb68 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 64dcc8a13ea..08bbca6859c 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 d27c11cf826..68800cae3ad 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 064d8bcb706..6f671d9e856 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 8c2283362ce..622ff495045 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 59b1f0c2e80..1d82ded8759 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/38] 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 2964423657e..7b02c6f8b48 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 584de63b42a..e522abfef4c 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 8a80eda2abe..2f6b7ad2d7d 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 ec5dbc9a63d..d498a3ff38a 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 21df770d762..aabb7a210a0 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 15a96379d89..d375c9f80a9 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 d8b51dd1b2b..a2d89ce5548 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 cd165e95aec..cbfcd7f286c 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 9a10b99e877..1513bf7820b 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 73c02d9ccea..77507fb9b91 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 3ed987f861d..9d60c67e490 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 9eabcb08025..06858fd2977 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 07f47cef399..ad6cc66aad3 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 9db8da1481d..aeb6fa32c8d 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 3540916e29f..42542b1326f 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 c5c811d47d4..4cfa52092d1 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 00000000000..84271b37ff0 --- /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 1190c7f9a8e..ca32aaed8db 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/38] 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 6578adbc4d8..40f7a3009f0 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 b767fbcb536..b23d0bf22d5 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/38] 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 7b02c6f8b48..f6e048086af 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 abdcb8a9e78..c42d426cfca 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/38] 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 e29251778c8..edeadc88c28 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 ae407691ce8..5fd9d3181b5 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 b24f676b6e2..3b5c69a7fe3 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 7d660e29736..b50e8f4475e 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 4cfd0594b51..7771f18a0cf 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 a401b26467c..3b9acae6245 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 1b2964da1e3..85c36b3de78 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 2aff5be52e0..92ea126d06e 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 973e2622989..8dee580b151 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 ca764acc3b5..6278adbc178 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 0945bd3fa3f..d2d239e7296 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 7119313e222..1d887a5f7a0 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 05102051cb1..1c048fc5586 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 82a7cb636b3..74628871b96 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 18f7c2120cd..1eaee8b0290 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 fe5e43a524a..907d05c15ad 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 beb2d1bcbd2..6c9760ab5e4 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 e522abfef4c..f804629ca96 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 2f6b7ad2d7d..76577b81a65 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 d498a3ff38a..7098362252a 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 6bc044cd7f0..f491844121c 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 372fd148777..c479a57789c 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 d375c9f80a9..aefaedb1d72 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 2ffb5c277a0..5bbc33c9fac 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 c149f8ad216..68ef2b60f53 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 045ce07347f..e24eb294851 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 7dd39c3b5cc..af2e96e6187 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 00000000000..17ffcfc18a1 --- /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 afcf5370682..f30bfffbde9 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 00000000000..0967ef424bc --- /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 00000000000..88cd82c5042 --- /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 00000000000..744758cbd29 --- /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 e54da4e1447..e94ef935128 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 2d671468848..ff3cbf87958 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 06932c02e28..32196dd98f2 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 6e7b4931b8a..80e36ff8691 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 554d9662f77..5ebb2dfc891 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 6c62904cd95..0791cfde735 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 7dbeb737cdc..7cdd335f9c3 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 04a660299b4..b4c8910f44b 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 5165968fc0d..eddc1c07278 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 8927c8e12bd..a0c410cc43c 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 2a47de7764e..96f9b61b387 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 1e2cac8c2d1..25e2813d247 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 26b5f25aba3..a6558f7ad91 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 1c2f09d60fe..08085012222 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 40a818fa7a3..32ad894830c 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/38] 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 f6e048086af..b767b7dc41c 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 38644659741..49dfb3ca738 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 b5d6894549d..590c22558bf 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 7173df10215..410b4253fae 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 819d893bbdc..8fc8bdeb156 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 9a1912aba8e..aa3ff4a02a0 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 277af58e6d5..0ecffea0c25 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 **