From d07ad9afc8198ed81aa918fbfd24dfe55c08ee7a Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Fri, 13 Oct 2017 10:58:30 -0400 Subject: [PATCH 01/31] add api docs for plugins and preprocessors --- source/_data/sidebar.yml | 3 ++ source/api/plugins/preprocessors.md | 84 +++++++++++++++++++++++++++++ source/api/plugins/top-level-api.md | 46 ++++++++++++++++ themes/cypress/languages/en.yml | 3 ++ 4 files changed, 136 insertions(+) create mode 100644 source/api/plugins/preprocessors.md create mode 100644 source/api/plugins/top-level-api.md diff --git a/source/_data/sidebar.yml b/source/_data/sidebar.yml index e971ffe03f..19abd06d07 100644 --- a/source/_data/sidebar.yml +++ b/source/_data/sidebar.yml @@ -143,6 +143,9 @@ api: env: env.html cypress-log: cypress-log.html cypress-server: cypress-server.html + plugins: + top-level-api: top-level-api.html + preprocessors: preprocessors.html examples: recipes: diff --git a/source/api/plugins/preprocessors.md b/source/api/plugins/preprocessors.md new file mode 100644 index 0000000000..20af1895c0 --- /dev/null +++ b/source/api/plugins/preprocessors.md @@ -0,0 +1,84 @@ +--- +title: Preprocessors API +comments: false +--- + +A preprocessor is a [plugin](./top-level-api.html) that runs when the support file or a spec file is required by the test runner. + +It can compile/transpile that file from another language (e.g. CoffeeScript, ClojureScript) to JavaScript or from a newer version of JavaScript (e.g. ES2017) to a version that has more browser compatibility (ES5). + +It can also watch the source file for changes, re-process it, and tell Cypress to re-run the tests. + +See the following preprocessors as examples. The code contains comments that explain how it utilizes the preprocessor API. + +* [Browserify Preprocessor](https://github.com/cypress-io/cypress-browserify-preprocessor) +* [Webpack Preprocessor](https://github.com/cypress-io/cypress-webpack-preprocessor) + +Setting a preprocessor involves registering the `on:spec:file:preprocessor` event in the *plugins file* (`cypress/plugins/index.js` by default), like so: + +```javascript +// plugins file +module.exports = (register, config) => { + register('on:spec:file:preprocessor', (filePath, util) => { + // ... + }) +} +``` + +The callback function should return one of the following: + +* The path to the **output file**\* +* A promise\*\* that resolves the path to the **output file**\* +* A promise\*\* that rejects with an error that occurred during processing + +\* The **output file** is the file that is created by the processing and will be served to the browser. If, for example, the source file is CoffeeScript (e.g. `spec.coffee`), the preprocessor should compile the CoffeeScript into JavaScript (e.g. `spec.js`), write that JavaScript file to disk, and return or resolve the full path to that file (e.g. `/Users/foo/tmp/spec.js`). + +\*\* The promise should resolve only after the file has completed writing to disk. The promise resolving is a signal that the file is ready to be served to the browser. + +{% note warning %} +This function can and will be called multiple times with the same filePath, because it is called any time the file is requested by the browser (i.e. on each run of the tests). Make sure not to start a new watcher each time it is called. Instead, cache the watcher and, on subsequent calls, return a promise that resolves when the latest version of the file has been processed. +{% endnote %} + +The callback function is called with the following arguments: + +## filePath + +The full path to the source file. + +## util + +An object of the following utility functions: + +### util.getOutputPath(filePath) + +Takes the `filePath` passed into the preprocessor function and returns a path for saving the preprocessed file to disk. A preprocessor can choose to write the file elsewhere, but this provides a convenient place to put the file (alongside other Cypress app data). + +```javascript +// example +util.getOutputPath(filePath) +// => /Users/jane-lane/Library/Application Support/Cypress/cy/production/projects/sample-project-fc17bd175cded40c4feec4861b699fc2/bundles/cypress/integration/example_spec.js +``` + +### util.fileUpdated(filePath) + +If watching for file changes, this function should be called (with the source `filePath`) after a file has finished being processed to let Cypress know to re-run the tests. + +```javascript +// example +fs.watch(filePath, () => { + util.fileUpdated(filePath) +}) +``` + +### util.onClose(function) + +This registers a function that will be called if the spec being run is closed or the project is closed. The preprocessor should do any necessary cleanup in this function, like closing the watcher when watching. + +```javascript +// example +const watcher = fs.watch(filePath, /* ... */) + +util.onClose(() => { + watcher.close() +}) +``` diff --git a/source/api/plugins/top-level-api.md b/source/api/plugins/top-level-api.md new file mode 100644 index 0000000000..0e6b2157f2 --- /dev/null +++ b/source/api/plugins/top-level-api.md @@ -0,0 +1,46 @@ +--- +title: Plugins Top-Level API +comments: false +--- + +Cypress provides a way for hooking into and extending its behavior via the Plugins API. The API can be utilized within the *plugins file*, which is `cypress/plugins/index.js` by default. + +{% note info %} +The *plugins file* will be required by [Cypress's server](https://github.com/cypress-io/cypress/tree/master/packages/server), so it must be compatible with the [version of node that Cypress uses](https://github.com/cypress-io/cypress/blob/master/.node-version). +{% endnote %} + +The *plugins file* should export a function with the following signature: + +```javascript +module.exports = (register, config) => { + +} +``` + +The exported function is called whenever a project is opened (or at the beginning of a run if running headless) and takes 2 arguments, `register` and `config`: + +## register + +`register` is a function used to register events that occur during the course of running Cypress. The function registered is what we call a *plugin*. + +Using it looks like this: + +```javascript +module.exports = (register, config) => { + register('', (arg1, arg2) => { + // plugin stuff here + }) +} +``` + +The arguments received by the callback functions and the requirements for what the plugin should do depend on the event. + +The following events are available: + +### on:spec:file:preprocessor + +Occurs when a spec or spec-related file is needed. Read the [Preprocessor API doc](./preprocessors.html) for more details. + +## config + +`config` is the resolved Cypress configuration, a combination of the default config and what the user has configured in their `cypress.json`. Some plugins may require this to be passed into them, so they can take certain actions based on the configuration. diff --git a/themes/cypress/languages/en.yml b/themes/cypress/languages/en.yml index 4eade6d4d6..0b4266edde 100644 --- a/themes/cypress/languages/en.yml +++ b/themes/cypress/languages/en.yml @@ -167,6 +167,9 @@ sidebar: dom: dom cypress-log: log cypress-server: Server + plugins: Plugins + top-level-api: Top Level API + preprocessors: Preprocessors examples: recipes: Recipes unit-testing-recipe: Unit Testing From 2cf33314fb6da16eb1ce26fc63c314c189197f73 Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Mon, 16 Oct 2017 15:03:51 -0400 Subject: [PATCH 02/31] rename top-level to plugins --- source/_data/sidebar.yml | 2 +- source/api/plugins/{top-level-api.md => plugins.md} | 4 ++-- source/api/plugins/preprocessors.md | 3 +++ themes/cypress/languages/en.yml | 1 - 4 files changed, 6 insertions(+), 4 deletions(-) rename source/api/plugins/{top-level-api.md => plugins.md} (97%) diff --git a/source/_data/sidebar.yml b/source/_data/sidebar.yml index 19abd06d07..bd91170063 100644 --- a/source/_data/sidebar.yml +++ b/source/_data/sidebar.yml @@ -144,7 +144,7 @@ api: cypress-log: cypress-log.html cypress-server: cypress-server.html plugins: - top-level-api: top-level-api.html + plugins: plugins.html preprocessors: preprocessors.html examples: diff --git a/source/api/plugins/top-level-api.md b/source/api/plugins/plugins.md similarity index 97% rename from source/api/plugins/top-level-api.md rename to source/api/plugins/plugins.md index 0e6b2157f2..cf13f6cda8 100644 --- a/source/api/plugins/top-level-api.md +++ b/source/api/plugins/plugins.md @@ -1,5 +1,5 @@ --- -title: Plugins Top-Level API +title: Plugins API comments: false --- @@ -13,7 +13,7 @@ The *plugins file* should export a function with the following signature: ```javascript module.exports = (register, config) => { - + // configure plugins here } ``` diff --git a/source/api/plugins/preprocessors.md b/source/api/plugins/preprocessors.md index 20af1895c0..2dac246e8e 100644 --- a/source/api/plugins/preprocessors.md +++ b/source/api/plugins/preprocessors.md @@ -13,6 +13,9 @@ See the following preprocessors as examples. The code contains comments that exp * [Browserify Preprocessor](https://github.com/cypress-io/cypress-browserify-preprocessor) * [Webpack Preprocessor](https://github.com/cypress-io/cypress-webpack-preprocessor) +* [Watch Preprocessor](https://github.com/cypress-io/cypress-watch-preprocessor) + +Preprocessors should be published to [npm](https://www.npmjs.com/) with the name being `cypress-*-preprocessor` (e.g. cypress-clojurescript-preprocessor). Use the following npm keywords: `cypress`, `cypress-plugin`, `cypress-preprocessor`. Setting a preprocessor involves registering the `on:spec:file:preprocessor` event in the *plugins file* (`cypress/plugins/index.js` by default), like so: diff --git a/themes/cypress/languages/en.yml b/themes/cypress/languages/en.yml index 0b4266edde..1f1f2bda4a 100644 --- a/themes/cypress/languages/en.yml +++ b/themes/cypress/languages/en.yml @@ -168,7 +168,6 @@ sidebar: cypress-log: log cypress-server: Server plugins: Plugins - top-level-api: Top Level API preprocessors: Preprocessors examples: recipes: Recipes From e4f356534b4b5c9c7158910e49046a5b35e59d1e Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Mon, 16 Oct 2017 15:04:14 -0400 Subject: [PATCH 03/31] first draft of plugins guide --- source/_data/sidebar.yml | 1 + source/guides/guides/plugins.md | 57 +++++++++++++++++++++++++++++++++ themes/cypress/languages/en.yml | 1 + 3 files changed, 59 insertions(+) create mode 100644 source/guides/guides/plugins.md diff --git a/source/_data/sidebar.yml b/source/_data/sidebar.yml index bd91170063..3ad7a767ae 100644 --- a/source/_data/sidebar.yml +++ b/source/_data/sidebar.yml @@ -22,6 +22,7 @@ guides: stubs-spies-and-clocks: stubs-spies-and-clocks.html web-security: web-security.html reporters: reporters.html + plugins: plugins.html # advanced-cypress: # the-cypress-workflow: the-cypress-workflow.html # coming-from-selenium: coming-from-selenium.html diff --git a/source/guides/guides/plugins.md b/source/guides/guides/plugins.md new file mode 100644 index 0000000000..dca60c31b9 --- /dev/null +++ b/source/guides/guides/plugins.md @@ -0,0 +1,57 @@ +--- +title: Plugins +comments: false +--- + +Cypress provides a way for hooking into and extending its behavior via plugins. Plugins can be configured within the *plugins file*, which is `cypress/plugins/index.js` by default. + +You can configure a different location for the *plugins file* in your `cypress.json` via the `pluginsFile` option. + +## Installation + +Installing a plugin requires [node.js](https://nodejs.org) (version 6.5.0 or greater). + +```shell +npm install --save-dev +``` + +## Usage + +```javascript +module.exports = (register, config) => { + register('', (arg1, arg2) => { + // plugin stuff here + }) +} +``` + +The event depends on the type of plugin you would like to utilize. The exact usage depends on the plugin itself, so refer to any given plugin's documentation for details on that usage. + +For example, here's how to use the [webpack preprocessor](https://github.com/cypress-io/cypress-webpack-preprocessor): + +```javascript +const webpack = require('@cypress/webpack-preprocessor') + +module.exports = (register, config) => { + register('on:spec:file:preprocessor', webpack(config)) +} +``` + +## Plugin Types + +### Preprocessors + +Preprocessors are plugins that can process your support file and spec files before they're served to the browser. They are also responsible for watching files for changes and notifying Cypress to re-run tests. + +* Event: `on:spec:file:preprocessor` +* Examples: [browserify](https://github.com/cypress-io/cypress-browserify-preprocessor),[webpack](https://github.com/cypress-io/cypress-webpack-preprocessor), [watch](https://github.com/cypress-io/cypress-watch-preprocessor) + +```javascript +// the plugins file +const webpack = require('@cypress/webpack-preprocessor') + +module.exports = (register, config) => { + // register the webpack plugin, using its default options + register('on:spec:file:preprocessor', webpack(config)) +} +``` diff --git a/themes/cypress/languages/en.yml b/themes/cypress/languages/en.yml index 1f1f2bda4a..45dcd962be 100644 --- a/themes/cypress/languages/en.yml +++ b/themes/cypress/languages/en.yml @@ -63,6 +63,7 @@ sidebar: roadmap: Roadmap cypress-api-design: API Design all-videos: Videos + plugins: Plugins api: introduction: Introduction api: API From 468046420ecf7f92698f4b9a925eeb2f3f4d5742 Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Tue, 17 Oct 2017 14:33:00 -0400 Subject: [PATCH 04/31] add pluginsFile to configuration doc --- source/guides/references/configuration.md | 1 + 1 file changed, 1 insertion(+) diff --git a/source/guides/references/configuration.md b/source/guides/references/configuration.md index 079cfb433d..1b11f7c486 100644 --- a/source/guides/references/configuration.md +++ b/source/guides/references/configuration.md @@ -50,6 +50,7 @@ Option | Default | Description `fileServerFolder` | root project folder |Path to folder where application files will attempt to be served from `fixturesFolder` | `cypress/fixtures` | Path to folder containing fixture files (Pass `false` to disable) `integrationFolder` | `cypress/integration` | Path to folder containing integration test files +`pluginsFile` | `cypress/plugins` | Path to plugins file. (Pass `false` to disable) `screenshotsFolder` | `cypress/screenshots` | Path to folder where screenshots will be saved from {% url `cy.screenshot()` screenshot %} command or after a headless or CI run's test failure `supportFile` | `cypress/support` | Path to file to load before test files load. This file is compiled and bundled. (Pass `false` to disable) `videosFolder` | `cypress/videos` | Path to folder where videos will be saved after a headless or CI run From a875c292248665c085e9d102cd90a409268b405e Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Wed, 18 Oct 2017 14:21:34 -0400 Subject: [PATCH 05/31] move clearfixes into mixin --- themes/cypress/source/css/_partial/base.scss | 41 ++++------------- .../cypress/source/css/_partial/footer.scss | 11 +---- themes/cypress/source/css/_partial/page.scss | 46 +++---------------- themes/cypress/source/css/_partial/toc.scss | 11 +---- 4 files changed, 17 insertions(+), 92 deletions(-) diff --git a/themes/cypress/source/css/_partial/base.scss b/themes/cypress/source/css/_partial/base.scss index 5d737e96fd..f5f65edc66 100644 --- a/themes/cypress/source/css/_partial/base.scss +++ b/themes/cypress/source/css/_partial/base.scss @@ -60,9 +60,7 @@ button, select, input, input[type="submit"]::-moz-focus-inner, input[type="butto border: 0; } -.wrapper { - margin: 0 auto; - +@mixin clearfix { &:before { content: ""; display: table; @@ -75,16 +73,13 @@ button, select, input, input[type="submit"]::-moz-focus-inner, input[type="butto } } +.wrapper { + margin: 0 auto; + @include clearfix; +} + .inner { - &:before { - content: ""; - display: table; - } - &:after { - content: ""; - display: table; - clear: both; - } + @include clearfix; } #content-wrap { @@ -139,28 +134,10 @@ button, select, input, input[type="submit"]::-moz-focus-inner, input[type="butto // border-left: 1px solid #eee; // margin-top: -50px; position: relative; - - &:before { - content: ""; - display: table; - } - - &:after { - content: ""; - display: table; - clear: both; - } + @include clearfix; } #content-inner { - &:before { - content: ""; - display: table; - } - &:after { - content: ""; - display: table; - clear: both; - } + @include clearfix; } #container { diff --git a/themes/cypress/source/css/_partial/footer.scss b/themes/cypress/source/css/_partial/footer.scss index 8a95d97903..b76ab42b41 100644 --- a/themes/cypress/source/css/_partial/footer.scss +++ b/themes/cypress/source/css/_partial/footer.scss @@ -8,16 +8,7 @@ font-size: 14px; clear: both; - &:before { - content: ""; - display: table; - } - - &:after { - content: ""; - display: table; - clear: both; - } + @include clearfix; a { color: inherit; diff --git a/themes/cypress/source/css/_partial/page.scss b/themes/cypress/source/css/_partial/page.scss index 00fe3b8e39..21801e6710 100644 --- a/themes/cypress/source/css/_partial/page.scss +++ b/themes/cypress/source/css/_partial/page.scss @@ -460,16 +460,7 @@ position: relative; overflow: auto; - &:before { - content: ""; - display: table; - } - - &:after { - content: ""; - display: table; - clear: both; - } + @include clearfix; } .article-footer-prev, .article-footer-next { @@ -516,30 +507,13 @@ padding-top: 2em; position: relative; - &:before { - content: ""; - display: table; - } - - &:after { - content: ""; - display: table; - clear: both; - } + @include clearfix; } .article-header { margin: 0 0 15px 0; border-bottom: 1px solid #ddd; - &:before { - content: ""; - display: table; - } - &:after { - content: ""; - display: table; - clear: both; - } + @include clearfix; } .article-title { @@ -553,24 +527,16 @@ } .article-inner { - &:before { - content: ""; - display: table; - } - &:after { - content: ""; - display: table; - clear: both; - } + @include clearfix; } -.embed-container { +.embed-container { position: relative; padding-bottom: 56.25%; height: 0; max-width: 100%; height: auto; -} +} .embed-container iframe { position: absolute; diff --git a/themes/cypress/source/css/_partial/toc.scss b/themes/cypress/source/css/_partial/toc.scss index 51cb238b9a..40c8a9e3fa 100644 --- a/themes/cypress/source/css/_partial/toc.scss +++ b/themes/cypress/source/css/_partial/toc.scss @@ -34,16 +34,7 @@ margin-top: 0; } - &:before { - content: ""; - display: table; - } - - &:after { - content: ""; - display: table; - clear: both; - } + @include clearfix; } .toc-link { From 9db28ec3c28a7f8ef00eb5039cd4c401025a85b5 Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Wed, 18 Oct 2017 14:22:34 -0400 Subject: [PATCH 06/31] add plugins page --- source/_data/main-menu.yml | 1 + source/_data/plugins.yml | 11 +++++++ source/plugins/index.md | 5 ++++ themes/cypress/languages/en.yml | 1 + themes/cypress/layout/plugins.swig | 29 +++++++++++++++++++ .../source/css/_partial/media_queries.scss | 10 +++++++ .../cypress/source/css/_partial/plugins.scss | 19 ++++++++++++ themes/cypress/source/css/cypress.scss | 1 + 8 files changed, 77 insertions(+) create mode 100644 source/_data/plugins.yml create mode 100644 source/plugins/index.md create mode 100644 themes/cypress/layout/plugins.swig create mode 100644 themes/cypress/source/css/_partial/plugins.scss diff --git a/source/_data/main-menu.yml b/source/_data/main-menu.yml index 6d224ba16c..306ccf299f 100644 --- a/source/_data/main-menu.yml +++ b/source/_data/main-menu.yml @@ -1,5 +1,6 @@ guides: /guides/getting-started/why-cypress.html api: /api/introduction/api.html +plugins: /plugins/ examples: /examples/recipes/unit-testing-recipe.html dashboard: /dashboard/overview/features-dashboard.html faq: /faq/questions/general-questions-faq.html diff --git a/source/_data/plugins.yml b/source/_data/plugins.yml new file mode 100644 index 0000000000..c9e8720519 --- /dev/null +++ b/source/_data/plugins.yml @@ -0,0 +1,11 @@ +- name: Preprocessors + plugins: + - name: Browserify + description: For bundling JavaScript via browserify + link: https://github.com/cypress-io/cypress-browserify-preprocessor + - name: Webpack + description: For bundling JavaScript via webpack + link: https://github.com/cypress-io/cypress-webpack-preprocessor + - name: Watch + description: Simple preprocessor that only watches files + link: https://github.com/cypress-io/cypress-watch-preprocessor diff --git a/source/plugins/index.md b/source/plugins/index.md new file mode 100644 index 0000000000..88dff01208 --- /dev/null +++ b/source/plugins/index.md @@ -0,0 +1,5 @@ +--- +title: Plugins +layout: plugins +comments: false +--- diff --git a/themes/cypress/languages/en.yml b/themes/cypress/languages/en.yml index 45dcd962be..3d078945b2 100644 --- a/themes/cypress/languages/en.yml +++ b/themes/cypress/languages/en.yml @@ -1,6 +1,7 @@ menu: guides: Guides api: API + plugins: Plugins faq: FAQ examples: Examples dashboard: Dashboard diff --git a/themes/cypress/layout/plugins.swig b/themes/cypress/layout/plugins.swig new file mode 100644 index 0000000000..46d4dd235f --- /dev/null +++ b/themes/cypress/layout/plugins.swig @@ -0,0 +1,29 @@ +
+
+
+

{{ page.title }}

+ {{ __('page.improve') }} +
+
+

To submit a plugin, submit a pull request updating plugins.yml with the name, description, and a link to it on GitHub. + + {% for pluginType in site.data.plugins %} +

{{ pluginType.name }}

+
    + {% for plugin in pluginType.plugins %} +
  • +

    {{ plugin.name }}

    +

    {{ plugin.description }}

    +
  • + {% endfor %} +
+ {% endfor %} +
+
+ {{ page_nav() }} +
+ +
+
diff --git a/themes/cypress/source/css/_partial/media_queries.scss b/themes/cypress/source/css/_partial/media_queries.scss index c8cc74de0e..9b9d58144c 100644 --- a/themes/cypress/source/css/_partial/media_queries.scss +++ b/themes/cypress/source/css/_partial/media_queries.scss @@ -232,4 +232,14 @@ } } } + + ul.plugins-list li { + width: 50%; + } +} + +@media screen and(max-width: 500px) { + ul.plugins-list li { + width: 100%; + } } diff --git a/themes/cypress/source/css/_partial/plugins.scss b/themes/cypress/source/css/_partial/plugins.scss new file mode 100644 index 0000000000..e238be514f --- /dev/null +++ b/themes/cypress/source/css/_partial/plugins.scss @@ -0,0 +1,19 @@ +.plugins { + .wrapper { + padding: 0 40px; + } +} + +ul.plugins-list { + display: flex; + flex-wrap: wrap; + margin: 0; + padding: 0; + + li { + box-sizing: border-box; + list-style: none; + padding: 1em; + width: 33%; + } +} diff --git a/themes/cypress/source/css/cypress.scss b/themes/cypress/source/css/cypress.scss index 04718f791e..288c22f3f5 100644 --- a/themes/cypress/source/css/cypress.scss +++ b/themes/cypress/source/css/cypress.scss @@ -11,4 +11,5 @@ @import "_partial/footer"; @import "_partial/highlight"; @import "_partial/examples"; +@import "_partial/plugins"; @import "_partial/media_queries"; From 22aa5559cac0ae9791e5b28eb1ff6c646183d2cd Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Wed, 18 Oct 2017 14:27:14 -0400 Subject: [PATCH 07/31] register -> on & on:spec:file:preprocessor -> file:preprocessor --- source/api/plugins/plugins.md | 14 +++++++------- source/api/plugins/preprocessors.md | 6 +++--- source/guides/guides/plugins.md | 14 +++++++------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/source/api/plugins/plugins.md b/source/api/plugins/plugins.md index cf13f6cda8..707b305dda 100644 --- a/source/api/plugins/plugins.md +++ b/source/api/plugins/plugins.md @@ -12,22 +12,22 @@ The *plugins file* will be required by [Cypress's server](https://github.com/cyp The *plugins file* should export a function with the following signature: ```javascript -module.exports = (register, config) => { +module.exports = (on, config) => { // configure plugins here } ``` -The exported function is called whenever a project is opened (or at the beginning of a run if running headless) and takes 2 arguments, `register` and `config`: +The exported function is called whenever a project is opened (or at the beginning of a run if running headless) and takes 2 arguments, `on` and `config`: -## register +## on -`register` is a function used to register events that occur during the course of running Cypress. The function registered is what we call a *plugin*. +`on` is a function used to on events that occur during the course of running Cypress. The function registered is what we call a *plugin*. Using it looks like this: ```javascript -module.exports = (register, config) => { - register('', (arg1, arg2) => { +module.exports = (on, config) => { + on('', (arg1, arg2) => { // plugin stuff here }) } @@ -37,7 +37,7 @@ The arguments received by the callback functions and the requirements for what t The following events are available: -### on:spec:file:preprocessor +### file:preprocessor Occurs when a spec or spec-related file is needed. Read the [Preprocessor API doc](./preprocessors.html) for more details. diff --git a/source/api/plugins/preprocessors.md b/source/api/plugins/preprocessors.md index 2dac246e8e..adc86949b8 100644 --- a/source/api/plugins/preprocessors.md +++ b/source/api/plugins/preprocessors.md @@ -17,12 +17,12 @@ See the following preprocessors as examples. The code contains comments that exp Preprocessors should be published to [npm](https://www.npmjs.com/) with the name being `cypress-*-preprocessor` (e.g. cypress-clojurescript-preprocessor). Use the following npm keywords: `cypress`, `cypress-plugin`, `cypress-preprocessor`. -Setting a preprocessor involves registering the `on:spec:file:preprocessor` event in the *plugins file* (`cypress/plugins/index.js` by default), like so: +Setting a preprocessor involves listening to the `file:preprocessor` event in the *plugins file* (`cypress/plugins/index.js` by default), like so: ```javascript // plugins file -module.exports = (register, config) => { - register('on:spec:file:preprocessor', (filePath, util) => { +module.exports = (on, config) => { + on('file:preprocessor', (filePath, util) => { // ... }) } diff --git a/source/guides/guides/plugins.md b/source/guides/guides/plugins.md index dca60c31b9..c33bbe60fc 100644 --- a/source/guides/guides/plugins.md +++ b/source/guides/guides/plugins.md @@ -18,8 +18,8 @@ npm install --save-dev ## Usage ```javascript -module.exports = (register, config) => { - register('', (arg1, arg2) => { +module.exports = (on, config) => { + on('', (arg1, arg2) => { // plugin stuff here }) } @@ -32,8 +32,8 @@ For example, here's how to use the [webpack preprocessor](https://github.com/cyp ```javascript const webpack = require('@cypress/webpack-preprocessor') -module.exports = (register, config) => { - register('on:spec:file:preprocessor', webpack(config)) +module.exports = (on, config) => { + on('file:preprocessor', webpack(config)) } ``` @@ -43,15 +43,15 @@ module.exports = (register, config) => { Preprocessors are plugins that can process your support file and spec files before they're served to the browser. They are also responsible for watching files for changes and notifying Cypress to re-run tests. -* Event: `on:spec:file:preprocessor` +* Event: `file:preprocessor` * Examples: [browserify](https://github.com/cypress-io/cypress-browserify-preprocessor),[webpack](https://github.com/cypress-io/cypress-webpack-preprocessor), [watch](https://github.com/cypress-io/cypress-watch-preprocessor) ```javascript // the plugins file const webpack = require('@cypress/webpack-preprocessor') -module.exports = (register, config) => { +module.exports = (on, config) => { // register the webpack plugin, using its default options - register('on:spec:file:preprocessor', webpack(config)) + on('file:preprocessor', webpack(config)) } ``` From eacbdbacbf802929359a6afbe020238cc8dfffcc Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Fri, 3 Nov 2017 14:06:56 -0400 Subject: [PATCH 08/31] fix plugins.yml link --- themes/cypress/layout/plugins.swig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/themes/cypress/layout/plugins.swig b/themes/cypress/layout/plugins.swig index 46d4dd235f..0d072ce56b 100644 --- a/themes/cypress/layout/plugins.swig +++ b/themes/cypress/layout/plugins.swig @@ -5,7 +5,7 @@ {{ __('page.improve') }}
-

To submit a plugin, submit a pull request updating plugins.yml with the name, description, and a link to it on GitHub. +

To submit a plugin, submit a pull request updating plugins.yml with the name, description, and a link to it on GitHub. {% for pluginType in site.data.plugins %}

{{ pluginType.name }}

From 8e9ea2daa3c1ed4563413713934e1818c3e665a5 Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Fri, 3 Nov 2017 14:07:17 -0400 Subject: [PATCH 09/31] clarify what config is --- source/api/plugins/plugins.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/api/plugins/plugins.md b/source/api/plugins/plugins.md index 707b305dda..459be13bd0 100644 --- a/source/api/plugins/plugins.md +++ b/source/api/plugins/plugins.md @@ -43,4 +43,4 @@ Occurs when a spec or spec-related file is needed. Read the [Preprocessor API do ## config -`config` is the resolved Cypress configuration, a combination of the default config and what the user has configured in their `cypress.json`. Some plugins may require this to be passed into them, so they can take certain actions based on the configuration. +`config` is the resolved [Cypress configuration](https://on.cypress.io/guides/configuration), a combination of the default config and what the user has configured via `cypress.json`, `cypress.env.json`, command line options, and/or environment variables. Some plugins may require this to be passed along to them, so they can take certain actions based on the configuration. From 1d0606ccf3f290df27056c5c388f89e1a99dbc97 Mon Sep 17 00:00:00 2001 From: Chris Breiding Date: Fri, 3 Nov 2017 14:07:27 -0400 Subject: [PATCH 10/31] update preprocessor doc with latest api --- source/api/plugins/preprocessors.md | 50 ++++++++++++++--------------- themes/cypress/languages/en.yml | 2 ++ 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/source/api/plugins/preprocessors.md b/source/api/plugins/preprocessors.md index adc86949b8..46f2b99b77 100644 --- a/source/api/plugins/preprocessors.md +++ b/source/api/plugins/preprocessors.md @@ -15,14 +15,14 @@ See the following preprocessors as examples. The code contains comments that exp * [Webpack Preprocessor](https://github.com/cypress-io/cypress-webpack-preprocessor) * [Watch Preprocessor](https://github.com/cypress-io/cypress-watch-preprocessor) -Preprocessors should be published to [npm](https://www.npmjs.com/) with the name being `cypress-*-preprocessor` (e.g. cypress-clojurescript-preprocessor). Use the following npm keywords: `cypress`, `cypress-plugin`, `cypress-preprocessor`. +Publish preprocessors to [npm](https://www.npmjs.com/) with the naming convention `cypress-*-preprocessor` (e.g. cypress-clojurescript-preprocessor). Use the following npm keywords: `cypress`, `cypress-plugin`, `cypress-preprocessor`. -Setting a preprocessor involves listening to the `file:preprocessor` event in the *plugins file* (`cypress/plugins/index.js` by default), like so: +A user will configure a preprocessor by listening to the `file:preprocessor` event in the *plugins file* (`cypress/plugins/index.js` by default), like so: ```javascript // plugins file -module.exports = (on, config) => { - on('file:preprocessor', (filePath, util) => { +module.exports = (on) => { + on('file:preprocessor', (config) => { // ... }) } @@ -42,46 +42,46 @@ The callback function should return one of the following: This function can and will be called multiple times with the same filePath, because it is called any time the file is requested by the browser (i.e. on each run of the tests). Make sure not to start a new watcher each time it is called. Instead, cache the watcher and, on subsequent calls, return a promise that resolves when the latest version of the file has been processed. {% endnote %} -The callback function is called with the following arguments: +## Config object properties -## filePath +The `config` object passed to the callback function has the following properties: + +### filePath The full path to the source file. -## util +### outputPath -An object of the following utility functions: +A path unique to the source file for saving the preprocessed file to disk. A preprocessor can choose to write the file elsewhere, but this provides a convenient default path for the file (alongside other Cypress app data). -### util.getOutputPath(filePath) +### shouldWatch -Takes the `filePath` passed into the preprocessor function and returns a path for saving the preprocessed file to disk. A preprocessor can choose to write the file elsewhere, but this provides a convenient place to put the file (alongside other Cypress app data). +A boolean indicating whether the preprocessor should watch for file changes or not. -```javascript -// example -util.getOutputPath(filePath) -// => /Users/jane-lane/Library/Application Support/Cypress/cy/production/projects/sample-project-fc17bd175cded40c4feec4861b699fc2/bundles/cypress/integration/example_spec.js -``` +## Config object events -### util.fileUpdated(filePath) +The `config` object passed to the callback function is an [Event Emitter](https://nodejs.org/api/events.html#events_class_eventemitter). -If watching for file changes, this function should be called (with the source `filePath`) after a file has finished being processed to let Cypress know to re-run the tests. +### Receiving 'close' event + +When the spec being run is closed or the project is closed, the 'close' event will be emitted. The preprocessor should do any necessary cleanup in this function, like closing the watcher when watching. ```javascript // example -fs.watch(filePath, () => { - util.fileUpdated(filePath) +const watcher = fs.watch(filePath, /* ... */) + +config.on('close', () => { + watcher.close() }) ``` -### util.onClose(function) +### Sending 'rerun' event -This registers a function that will be called if the spec being run is closed or the project is closed. The preprocessor should do any necessary cleanup in this function, like closing the watcher when watching. +If watching for file changes, emit 'rerun' after a file has finished being processed to let Cypress know to rerun the tests. ```javascript // example -const watcher = fs.watch(filePath, /* ... */) - -util.onClose(() => { - watcher.close() +fs.watch(filePath, () => { + config.emit('rerun') }) ``` diff --git a/themes/cypress/languages/en.yml b/themes/cypress/languages/en.yml index db89d85c75..cc79f7259f 100644 --- a/themes/cypress/languages/en.yml +++ b/themes/cypress/languages/en.yml @@ -159,6 +159,8 @@ sidebar: removelistener: removeListener removealllisteners: removeAllListeners utilities: Utilities + plugins: Plugins + preprocessors: Preprocessors _: _ $: $ minimatch: minimatch From ecf83659529211aa1557a97a3147613b4cb1f264 Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Wed, 8 Nov 2017 11:07:04 -0500 Subject: [PATCH 11/31] fix failed build --- source/faq/questions/using-cypress-faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/faq/questions/using-cypress-faq.md b/source/faq/questions/using-cypress-faq.md index 2504bdb5d0..762b0a2771 100644 --- a/source/faq/questions/using-cypress-faq.md +++ b/source/faq/questions/using-cypress-faq.md @@ -137,7 +137,7 @@ This is documented in detail on the {% url "Catalog Of Events" catalog-of-events ## {% fa fa-angle-right %} I'm trying to test a chat application. Can I run more than one browser at a time with Cypress? -{% url "We've answered this question in detail here." trade-offs#Multiple-Browsers %} +{% url "We've answered this question in detail here." trade-offs#Multiple-browsers %} ## {% fa fa-angle-right %} Can I make cy.request() poll until a condition is met? From c1bb57288efa2c2d9b6b804546ddc62850c263da Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Wed, 8 Nov 2017 15:32:16 -0500 Subject: [PATCH 12/31] fixed duplicate titles in en.yml file --- themes/cypress/languages/en.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/themes/cypress/languages/en.yml b/themes/cypress/languages/en.yml index 32e4878cdf..2d17598135 100644 --- a/themes/cypress/languages/en.yml +++ b/themes/cypress/languages/en.yml @@ -160,8 +160,6 @@ sidebar: removelistener: removeListener removealllisteners: removeAllListeners utilities: Utilities - plugins: Plugins - preprocessors: Preprocessors _: _ $: $ minimatch: minimatch From ecba4e31fd09aeabdd03989641a4ffbd9d17594d Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Wed, 8 Nov 2017 16:00:02 -0500 Subject: [PATCH 13/31] rename plugin files/sidebar definitions so they don't conflict --- source/_data/sidebar.yml | 6 +++--- source/api/plugins/{plugins.md => plugins-api.md} | 0 .../api/plugins/{preprocessors.md => preprocessors-api.md} | 0 source/guides/guides/{plugins.md => plugins-guide.md} | 0 themes/cypress/languages/en.yml | 5 +++-- 5 files changed, 6 insertions(+), 5 deletions(-) rename source/api/plugins/{plugins.md => plugins-api.md} (100%) rename source/api/plugins/{preprocessors.md => preprocessors-api.md} (100%) rename source/guides/guides/{plugins.md => plugins-guide.md} (100%) diff --git a/source/_data/sidebar.yml b/source/_data/sidebar.yml index fb16cb6cd9..1b39cbd837 100644 --- a/source/_data/sidebar.yml +++ b/source/_data/sidebar.yml @@ -26,7 +26,7 @@ guides: launching-browsers: launching-browsers.html web-security: web-security.html reporters: reporters.html - plugins: plugins.html + plugins-guide: plugins-guide.html # advanced-cypress: # the-cypress-workflow: the-cypress-workflow.html # coming-from-selenium: coming-from-selenium.html @@ -149,8 +149,8 @@ api: cypress-log: cypress-log.html cypress-server: cypress-server.html plugins: - plugins: plugins.html - preprocessors: preprocessors.html + plugins-api: plugins-api.html + preprocessors-api: preprocessors-api.html tutorials: test-a-react-todo-app: diff --git a/source/api/plugins/plugins.md b/source/api/plugins/plugins-api.md similarity index 100% rename from source/api/plugins/plugins.md rename to source/api/plugins/plugins-api.md diff --git a/source/api/plugins/preprocessors.md b/source/api/plugins/preprocessors-api.md similarity index 100% rename from source/api/plugins/preprocessors.md rename to source/api/plugins/preprocessors-api.md diff --git a/source/guides/guides/plugins.md b/source/guides/guides/plugins-guide.md similarity index 100% rename from source/guides/guides/plugins.md rename to source/guides/guides/plugins-guide.md diff --git a/themes/cypress/languages/en.yml b/themes/cypress/languages/en.yml index 2d17598135..81b7a215ec 100644 --- a/themes/cypress/languages/en.yml +++ b/themes/cypress/languages/en.yml @@ -69,7 +69,7 @@ sidebar: roadmap: Roadmap cypress-api-design: API Design all-videos: Videos - plugins: Plugins + plugins-guide: Plugins api: introduction: Introduction api: API @@ -175,7 +175,8 @@ sidebar: cypress-log: log cypress-server: Server plugins: Plugins - preprocessors: Preprocessors + plugins-api: Plugins + preprocessors-api: Preprocessors tutorials: test-a-react-todo-app: Test a React Todo App introduction-to-tutorials: Introduction From 83e454d8065ce429b87a46becfcd4c4cbbc8b2cd Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Thu, 9 Nov 2017 13:18:10 -0500 Subject: [PATCH 14/31] Added section to 'writing / organizing tests' to indicate plugins/index.js is added --- .../writing-and-organizing-tests.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/source/guides/core-concepts/writing-and-organizing-tests.md b/source/guides/core-concepts/writing-and-organizing-tests.md index 0e93ba64b6..0334303119 100644 --- a/source/guides/core-concepts/writing-and-organizing-tests.md +++ b/source/guides/core-concepts/writing-and-organizing-tests.md @@ -24,6 +24,9 @@ After adding a new project, Cypress will automatically scaffold out a suggested /integration - example_spec.js + /plugins + - index.js + /support - commands.js - index.js @@ -35,6 +38,12 @@ While Cypress allows to configure where your tests, fixtures, and support files You can modify the folder configuration in your `cypress.json`. See {% url 'configuration' configuration %} for more detail. +## Fixture Files + +Fixtures are used as external pieces of static data that can be used by your tests. + +You would typically use them with the {% url `cy.fixture()` fixture %} command and most often when you're stubbing {% url 'Network Requests' network-requests %}. + ## Test Files Test files may be written as: @@ -54,6 +63,12 @@ To see an example of every command used in Cypress, open the {% url "`example_sp To start writing tests for your app, simply create a new file like `app_spec.js` within your `cypress/integration` folder. Refresh your tests list in the Cypress Test Runner and your new file should have appeared in the list. +## Plugin Files + +By default Cypress will automatically include the plugins file `cypress/plugins/index.js` **before** every single spec file it runs. We do this purely as a convenience mechanism so you don't have to import this file in every single one of your spec files. + +{% url "Read more about using plugins to extend Cypress behavior." plugins-guide %} + ## Support Files By default Cypress will automatically include the support file `cypress/support/index.js` **before** every single spec file it runs. We do this purely as a convenience mechanism so you don't have to import this file in every single one of your spec files. @@ -68,11 +83,7 @@ We automatically seed you an example support file, which has several commented o Our {% url 'Extending Cypress recipes' extending-cypress-recipe %} show you how to modify the support file. {% endnote %} -## Fixture Files -Fixtures are used as external pieces of static data that can be used by your tests. - -You would typically use them with the {% url `cy.fixture()` fixture %} command and most often when you're stubbing {% url 'Network Requests' network-requests %}. # How to Write Tests From 00c4792253038e0b4ce9f030ca1d5f8aba484003 Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Thu, 9 Nov 2017 13:18:32 -0500 Subject: [PATCH 15/31] replace example record keys with to figure it out. --- source/guides/core-concepts/dashboard-service.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/guides/core-concepts/dashboard-service.md b/source/guides/core-concepts/dashboard-service.md index 8b5c024eed..bd704da0c5 100644 --- a/source/guides/core-concepts/dashboard-service.md +++ b/source/guides/core-concepts/dashboard-service.md @@ -79,12 +79,12 @@ Make sure you {% url "install" installing-cypress %} and {% url "open" installin 10. Within {% url 'Continuous Integration' continuous-integration %}, or from your local computer's terminal, pass the displayed {% urlHash "Record Key" Identification %} while running the {% url '`cypress run`' command-line#cypress-run %} command. - Provide record key directly: ```shell - cypress run --record --key abc-key-123 + cypress run --record --key <record key> ``` - Or set record key as environment variable ```shell - export CYPRESS_RECORD_KEY=abc-key-123 + export CYPRESS_RECORD_KEY=<record key> ``` ```shell cypress run --record From 4c0d8e9d2e4f352f2b9b1f1d0279a5e3dc031fb9 Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Thu, 9 Nov 2017 13:32:36 -0500 Subject: [PATCH 16/31] Update title of section in config to Folders / Files - update links to config#Folders - update files options to specify the exact file (yes I know this is unnecessary in node, but it is more explicit) --- source/api/commands/fixture.md | 4 ++-- source/api/commands/screenshot.md | 2 +- source/guides/references/changelog.md | 8 ++++---- source/guides/references/configuration.md | 6 +++--- source/guides/references/error-messages.md | 8 ++++---- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/source/api/commands/fixture.md b/source/api/commands/fixture.md index b7e2271974..c1f5c68b92 100644 --- a/source/api/commands/fixture.md +++ b/source/api/commands/fixture.md @@ -29,7 +29,7 @@ cy.fixture('logo.png').then((logo) => { **{% fa fa-angle-right %} filePath** ***(String)*** -A path to a file within the {% url `fixturesFolder` configuration#Folders %} , which defaults to `cypress/fixtures`. +A path to a file within the {% url `fixturesFolder` configuration#Folders-Files %} , which defaults to `cypress/fixtures`. You can nest fixtures within folders and reference them by defining the path from the fixturesFolder: @@ -77,7 +77,7 @@ cy.fixture('users.json').as('usersData') ***Omit the fixture file's extension*** -When no extension is passed to `cy.fixture()`, Cypress will search for files with the specified name within the {% url `fixturesFolder` configuration#Folders %} (which defaults to `cypress/fixtures`) and resolve the first one. +When no extension is passed to `cy.fixture()`, Cypress will search for files with the specified name within the {% url `fixturesFolder` configuration#Folders-Files %} (which defaults to `cypress/fixtures`) and resolve the first one. ```javascript cy.fixture('admin').as('adminJSON') diff --git a/source/api/commands/screenshot.md b/source/api/commands/screenshot.md index e2cf566726..7455d94329 100644 --- a/source/api/commands/screenshot.md +++ b/source/api/commands/screenshot.md @@ -45,7 +45,7 @@ Option | Default | Description The screenshot will be stored in the `cypress/screenshots` folder by default. -You can change the directory where screenshots are saved in your {% url 'configuration' configuration#Folders %}. +You can change the directory where screenshots are saved in your {% url 'configuration' configuration#Folders-Files %}. ## No Args diff --git a/source/guides/references/changelog.md b/source/guides/references/changelog.md index f9fec1ddd8..da1e83d5ac 100644 --- a/source/guides/references/changelog.md +++ b/source/guides/references/changelog.md @@ -597,7 +597,7 @@ Fixed {% url "`.type()`" type %} not firing `input` event for {% url "React" htt **Breaking Changes:** -- Previously, we auto-magically included all files within {% url '`cypress/support`' writing-and-organizing-tests#Folder-Structure %}. This has now {% url 'gone away' error-messages %} and we've simplified this to automatically including a single `cypress/support/index.js` file. That single file acts as the entry point meaning you should `import` or `require` the other support files you'd like to include. Although this is still "automatic" it's much less magical and we'll be updating all of our docs to reflect this. The purpose of `cypress/support` hasn't really changed, just the implementation of it has. We will automatically seed a `cypress/support/index.js` file for you (even on existing projects). The file location of `cypress/support/index.js` can be changed with the new {% url `supportFile` configuration#Folders %} option in your `cypress.json`. This feature can also be turned off by specifying `supportFile: false`. +- Previously, we auto-magically included all files within {% url '`cypress/support`' writing-and-organizing-tests#Folder-Structure %}. This has now {% url 'gone away' error-messages %} and we've simplified this to automatically including a single `cypress/support/index.js` file. That single file acts as the entry point meaning you should `import` or `require` the other support files you'd like to include. Although this is still "automatic" it's much less magical and we'll be updating all of our docs to reflect this. The purpose of `cypress/support` hasn't really changed, just the implementation of it has. We will automatically seed a `cypress/support/index.js` file for you (even on existing projects). The file location of `cypress/support/index.js` can be changed with the new {% url `supportFile` configuration#Folders-Files %} option in your `cypress.json`. This feature can also be turned off by specifying `supportFile: false`. **Features:** @@ -609,7 +609,7 @@ Fixed {% url "`.type()`" type %} not firing `input` event for {% url "React" htt - We improved the logic around when and if we scaffold files on a new project. We're much smarter about this and not generating these forcibly every time. Fixes {% issue 285 '#285' %}. - Simplified handling of support files and made them less "magical". Fixes {% issue 286 '#286' %}. -- Renamed `supportFolder` to {% url `supportFile` configuration#Folders %} in `cypress.json`. We will automatically rename your `cypress.json` if this property was present on update. +- Renamed `supportFolder` to {% url `supportFile` configuration#Folders-Files %} in `cypress.json`. We will automatically rename your `cypress.json` if this property was present on update. # 0.17.12 @@ -1162,9 +1162,9 @@ Fixed {% url "`.type()`" type %} not firing `input` event for {% url "React" htt **Breaking Changes:** - Cypress no longer looks at your `tests` directory for test files. Now, by default, it looks in the `cypress/integration` directory. -- We've removed the configuration option `testFolder` and renamed it to {% url `integrationFolder` configuration#Folders %} inside of the `cypress.json`. +- We've removed the configuration option `testFolder` and renamed it to {% url `integrationFolder` configuration#Folders-Files %} inside of the `cypress.json`. - We've renamed the `cypress` npm package to be `cypress-cli`. You'll see a giant deprecation warning until your scripts have been updated to reference `cypress-cli`.. You can also uninstall the `cypress` npm package. -- Added new {% url `fileServerFolder` configuration#Folders %} configuration option that can mount a directory other than your project root when using Cypress as a web server. +- Added new {% url `fileServerFolder` configuration#Folders-Files %} configuration option that can mount a directory other than your project root when using Cypress as a web server. **Misc:** diff --git a/source/guides/references/configuration.md b/source/guides/references/configuration.md index 4679ba8771..f052573518 100644 --- a/source/guides/references/configuration.md +++ b/source/guides/references/configuration.md @@ -43,16 +43,16 @@ Option | Default | Description `requestTimeout` | `5000` | Time, in milliseconds, to wait for an XHR request to go out in a {% url `cy.wait()` wait %} command `responseTimeout` | `30000` | Time, in milliseconds, to wait until a response in a {% url `cy.request()` request %}, {% url `cy.wait()` wait %}, {% url `cy.fixture()` fixture %}, {% url `cy.getCookie()` getcookie %}, {% url `cy.getCookies()` getcookies %}, {% url `cy.setCookie()` setcookie %}, {% url `cy.clearCookie()` clearcookie %}, {% url `cy.clearCookies()` clearcookies %}, and {% url `cy.screenshot()` screenshot %} commands -## Folders +## Folders / Files Option | Default | Description ----- | ---- | ---- `fileServerFolder` | root project folder |Path to folder where application files will attempt to be served from `fixturesFolder` | `cypress/fixtures` | Path to folder containing fixture files (Pass `false` to disable) `integrationFolder` | `cypress/integration` | Path to folder containing integration test files -`pluginsFile` | `cypress/plugins` | Path to plugins file. (Pass `false` to disable) +`pluginsFile` | `cypress/plugins/index.js` | Path to plugins file. (Pass `false` to disable) `screenshotsFolder` | `cypress/screenshots` | Path to folder where screenshots will be saved from {% url `cy.screenshot()` screenshot %} command or after a headless or CI run's test failure -`supportFile` | `cypress/support` | Path to file to load before test files load. This file is compiled and bundled. (Pass `false` to disable) +`supportFile` | `cypress/support/index.js` | Path to file to load before test files load. This file is compiled and bundled. (Pass `false` to disable) `videosFolder` | `cypress/videos` | Path to folder where videos will be saved after a headless or CI run ## Screenshots diff --git a/source/guides/references/error-messages.md b/source/guides/references/error-messages.md index 6c7b16bea2..4433746745 100644 --- a/source/guides/references/error-messages.md +++ b/source/guides/references/error-messages.md @@ -29,7 +29,7 @@ When the error is fixed in your test file, your tests will automatically re-run. ## {% fa fa-exclamation-triangle red %} Support file missing or invalid -The `supportFolder` option was removed from Cypress in version {% url `0.18.0` changelog#0-18-0 %} and was replaced by module support and the {% url `supportFile` configuration#Folders %} configuration option. +The `supportFolder` option was removed from Cypress in version {% url `0.18.0` changelog#0-18-0 %} and was replaced by module support and the {% url `supportFile` configuration#Folders-Files %} configuration option. Cypress used to automatically include any scripts in the `supportFolder` before your test files. However, automatically including all the files in a certain directory is somewhat magical and unintuitive, and requires creating globals for the purpose of utility functions. @@ -49,14 +49,14 @@ it('uses modules', function () { ***Use supportFile to load scripts before your test code*** -It's still useful to load a setup file before your test code. If you are setting Cypress defaults or utilizing custom Cypress commands, instead of needing to import/require those defaults/commands in every test file, you can use the {% url `supportFile` configuration#Folders %} configuration option. +It's still useful to load a setup file before your test code. If you are setting Cypress defaults or utilizing custom Cypress commands, instead of needing to import/require those defaults/commands in every test file, you can use the {% url `supportFile` configuration#Folders-Files %} configuration option. -To include code before your test files, set the {% url `supportFile` configuration#Folders %} path. By default, {% url `supportFile` configuration#Folders %} is set to look for one of the following files: +To include code before your test files, set the {% url `supportFile` configuration#Folders-Files %} path. By default, {% url `supportFile` configuration#Folders-Files %} is set to look for one of the following files: * `cypress/support/index.js` * `cypress/support/index.coffee` -Just like with your test files, the {% url `supportFile` configuration#Folders %} can use ES2015+ (or CoffeeScript) and modules, so you can import/require other files as needed. +Just like with your test files, the {% url `supportFile` configuration#Folders-Files %} can use ES2015+ (or CoffeeScript) and modules, so you can import/require other files as needed. # Command Errors From 373e6f677334c39de371b71f5badc61caaba4f9d Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Thu, 9 Nov 2017 13:32:56 -0500 Subject: [PATCH 17/31] Update to show up in shell - some wording/styling updates --- source/guides/guides/plugins-guide.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/source/guides/guides/plugins-guide.md b/source/guides/guides/plugins-guide.md index c33bbe60fc..2ac24ea25c 100644 --- a/source/guides/guides/plugins-guide.md +++ b/source/guides/guides/plugins-guide.md @@ -3,16 +3,18 @@ title: Plugins comments: false --- -Cypress provides a way for hooking into and extending its behavior via plugins. Plugins can be configured within the *plugins file*, which is `cypress/plugins/index.js` by default. +Plugins provides a way for hooking into and extending the behavior of Cypress. Plugins can be configured within the plugins file, which will be searched for at `cypress/plugins/index.js` by default. -You can configure a different location for the *plugins file* in your `cypress.json` via the `pluginsFile` option. +{% note info %} +You can configure a different location for the plugins file in your `cypress.json` via the {% url "`pluginsFile`" configuration#Folders-Files %} option. +{% endnote %} ## Installation -Installing a plugin requires [node.js](https://nodejs.org) (version 6.5.0 or greater). +Installing a plugin requires [node.js](https://nodejs.org) (version 6.5.0+). ```shell -npm install --save-dev +npm install <plugin name> --save-dev ``` ## Usage From 0375d93b51c80cdb5f35ff5f40a0b3c09b7b05f4 Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Thu, 9 Nov 2017 14:55:36 -0500 Subject: [PATCH 18/31] reroute for plugins/index.html --- _config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_config.yml b/_config.yml index 263ac1a254..755452f34e 100644 --- a/_config.yml +++ b/_config.yml @@ -57,6 +57,8 @@ alias: tutorials/test-a-react-todo-app/: tutorials/test-a-react-todo-app/introduction-to-tutorials.html tutorials/: tutorials/test-a-react-todo-app/introduction-to-tutorials.html + plugins/: plugins/index.html + examples/index.html: examples/recipes/unit-testing-recipe.html dashboard/index.html: guides/core-concepts/dashboard-service.html From ec96eb186f41c29e47d881c9bea7d0212cf646d8 Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Thu, 9 Nov 2017 14:56:02 -0500 Subject: [PATCH 19/31] added keywords to plugins --- source/_data/plugins.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/source/_data/plugins.yml b/source/_data/plugins.yml index c9e8720519..6feb05ca77 100644 --- a/source/_data/plugins.yml +++ b/source/_data/plugins.yml @@ -1,11 +1,16 @@ - name: Preprocessors plugins: - name: Browserify - description: For bundling JavaScript via browserify + description: For bundling JavaScript via browserify. link: https://github.com/cypress-io/cypress-browserify-preprocessor + keywords: [browserify] + - name: Webpack - description: For bundling JavaScript via webpack + description: For bundling JavaScript via webpack. link: https://github.com/cypress-io/cypress-webpack-preprocessor + keywords: [webpack] + - name: Watch - description: Simple preprocessor that only watches files + description: Simple preprocessor that only watches files. link: https://github.com/cypress-io/cypress-watch-preprocessor + keywords: [file-watcher] From 5fd964c81f53d23a0d85f4fc7dbd50f45b811331 Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Thu, 9 Nov 2017 14:56:21 -0500 Subject: [PATCH 20/31] added plugins to sidebar so that url linking to 'plugins' works --- source/_data/sidebar.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/_data/sidebar.yml b/source/_data/sidebar.yml index 1b39cbd837..87b587cd74 100644 --- a/source/_data/sidebar.yml +++ b/source/_data/sidebar.yml @@ -160,6 +160,9 @@ tutorials: react-todo-form-submission: react-todo-form-submission.html react-todo-app-init: react-todo-app-init.html +plugins: + plugins: index.html + examples: recipes: unit-testing-recipe: unit-testing-recipe.html From 915276fd5ed65e7dfa2e834f9a9267524d7b87ca Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Thu, 9 Nov 2017 14:56:45 -0500 Subject: [PATCH 21/31] Update styles of main plugins list --- themes/cypress/layout/plugins.swig | 53 ++++++++++--------- .../cypress/source/css/_partial/plugins.scss | 42 +++++++++++++-- 2 files changed, 66 insertions(+), 29 deletions(-) diff --git a/themes/cypress/layout/plugins.swig b/themes/cypress/layout/plugins.swig index 0d072ce56b..23415bd56f 100644 --- a/themes/cypress/layout/plugins.swig +++ b/themes/cypress/layout/plugins.swig @@ -1,29 +1,32 @@
-
-

{{ page.title }}

- {{ __('page.improve') }} -
-
-

To submit a plugin, submit a pull request updating plugins.yml with the name, description, and a link to it on GitHub. - - {% for pluginType in site.data.plugins %} -

{{ pluginType.name }}

-
    - {% for plugin in pluginType.plugins %} -
  • -

    {{ plugin.name }}

    -

    {{ plugin.description }}

    -
  • - {% endfor %} -
- {% endfor %} -
-
- {{ page_nav() }} -
- +
+
+

{{ page.title }}

+ {{ __('page.improve') }} +
+
+ {{ (page.content) }} + {% for pluginType in site.data.plugins %} +

{{ pluginType.name }}

+
    + {% for plugin in pluginType.plugins %} +
  • +

    + {{ plugin.name }} +

    +

    {{ plugin.description }}

    + {% for keyword in plugin.keywords %} + #{{ keyword }} + {% endfor %} +
  • + {% endfor %} +
+ {% endfor %} +
+ +
diff --git a/themes/cypress/source/css/_partial/plugins.scss b/themes/cypress/source/css/_partial/plugins.scss index e238be514f..77608556a9 100644 --- a/themes/cypress/source/css/_partial/plugins.scss +++ b/themes/cypress/source/css/_partial/plugins.scss @@ -2,18 +2,52 @@ .wrapper { padding: 0 40px; } + + h2 { + border-bottom: 0; + margin-bottom: 0; + } + + h3 { + font-size: 1.3em; + margin: 0.6em 0; + + a { + + border-bottom: 0; + &:hover { + border-bottom: 0; + } + } + + + + } } ul.plugins-list { display: flex; - flex-wrap: wrap; - margin: 0; + flex-flow: row wrap; + margin: 0 -20px; padding: 0; li { box-sizing: border-box; list-style: none; - padding: 1em; - width: 33%; + padding: 20px; + width: 30%; + margin: 20px; + border: 1px solid #e8e8e8; + box-shadow: 0px 1px 1px 0px rgba(0,0,0,0.15); + + p { + margin-bottom: 0.5em; + } + } + + .keyword { + font-weight: 300; + font-size: 0.9em; + color: #777; } } From e1802b0b53599023ecf1f285312f2a1feae9f62e Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Thu, 9 Nov 2017 14:57:11 -0500 Subject: [PATCH 22/31] More plugin submission instructions to a Contributing doc --- CONTRIBUTING.md | 9 +++++---- source/plugins/index.md | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ace6778262..e8b1ab1a82 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -61,7 +61,7 @@ variable set `DEBUG=docs npm run build` ### Adding Examples - To add an blog, talk, or podcast to our docs, just add your data to the corresponding [blogs.yml](https://github.com/cypress-io/cypress-documentation/blob/develop/source/_data/blogs.yml), [talks.yml](https://github.com/cypress-io/cypress-documentation/blob/develop/source/_data/talks.yml), or [podcasts.yml](https://github.com/cypress-io/cypress-documentation/blob/develop/source/_data/podcasts.yml) file. + To add an blog, talk, or podcast to our docs, submit a [pull request](#Pull-Requests) with your data added to the corresponding [blogs.yml](https://github.com/cypress-io/cypress-documentation/blob/develop/source/_data/blogs.yml), [talks.yml](https://github.com/cypress-io/cypress-documentation/blob/develop/source/_data/talks.yml), or [podcasts.yml](https://github.com/cypress-io/cypress-documentation/blob/develop/source/_data/podcasts.yml) file. Add an associating image with the example within the [`source/img/examples`](/source/img/examples) directory. Each image should be resolution **715w x 480h**. Reference the image in the markdown document as follows: @@ -69,7 +69,9 @@ Add an associating image with the example within the [`source/img/examples`](/so {% img /img/examples/name-of-file.jpg "alt text describing img" %} ``` -To add anything else to an example page, the documents outlining examples are within the [`source/examples`](/source/examples) directory. Each document is written in markdown with a little bit of [Hexo flair](https://hexo.io/docs/tag-plugins.html). To add an example to a document, just try to follow the formatting of any previous examples in the markdown file. +### Adding Plugins + +To add a plugin, submit a [pull request](#Pull-Requests) with the corresponding data added to the [plugins.yml](https://github.com/cypress-io/cypress-documentation/blob/develop/source/_data/plugins.yml) file. Your plugin should have a name, description, link to the plugins code, and any keywords. ## Commiting Code @@ -80,8 +82,7 @@ Danger 📛: because we are minifying client side code using a [Hexo plugin](htt ### Pull Requests -You should push your local changes to your forked GitHub repository and then -open a pull request from your repo to the `cypress-io/cypress-documentation` repo. +You should push your local changes to your forked GitHub repository and then open a pull request from your repo to the `cypress-io/cypress-documentation` repo. - The pull request should be from your repository to the `develop` branch in `cypress-io/cypress-documentation` - When opening a PR for a specific issue already open, please use the `address #[issue number]` or `closes #[issue number]` syntax in the pull request description. diff --git a/source/plugins/index.md b/source/plugins/index.md index 88dff01208..15c7860932 100644 --- a/source/plugins/index.md +++ b/source/plugins/index.md @@ -3,3 +3,5 @@ title: Plugins layout: plugins comments: false --- + +Plugins provide a way to extend the behavior of Cypress. To submit your own plugin, [follow these instructions](https://github.com/cypress-io/cypress-documentation/blob/develop/CONTRIBUTING.md#adding-plugins). From 2cbf3ae1d0209c27d2d2d30ac6c0aace1cba850b Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Thu, 9 Nov 2017 14:57:19 -0500 Subject: [PATCH 23/31] General editing --- source/api/plugins/plugins-api.md | 28 ++++---- source/api/plugins/preprocessors-api.md | 64 +++++++++++-------- .../writing-and-organizing-tests.md | 4 +- source/guides/guides/plugins-guide.md | 20 +++--- source/guides/references/best-practices.md | 2 +- 5 files changed, 67 insertions(+), 51 deletions(-) diff --git a/source/api/plugins/plugins-api.md b/source/api/plugins/plugins-api.md index 459be13bd0..68da79af3b 100644 --- a/source/api/plugins/plugins-api.md +++ b/source/api/plugins/plugins-api.md @@ -3,13 +3,17 @@ title: Plugins API comments: false --- -Cypress provides a way for hooking into and extending its behavior via the Plugins API. The API can be utilized within the *plugins file*, which is `cypress/plugins/index.js` by default. +The Plugins API allows you to hook into and extend Cypress behavior. + +# pluginsFile + +The API can be utilized within the plugins file, which will be searched for at `cypress/plugins/index.js` by default. Users can configure a different location for the plugins file in their `cypress.json` via the {% url "`pluginsFile`" configuration#Folders-Files %} option. {% note info %} -The *plugins file* will be required by [Cypress's server](https://github.com/cypress-io/cypress/tree/master/packages/server), so it must be compatible with the [version of node that Cypress uses](https://github.com/cypress-io/cypress/blob/master/.node-version). +The plugins file will be required by [Cypress' server](https://github.com/cypress-io/cypress/tree/master/packages/server), so it must be compatible with the [version of node that Cypress uses](https://github.com/cypress-io/cypress/blob/master/.node-version). {% endnote %} -The *plugins file* should export a function with the following signature: +The plugins file should export a function with the following signature: ```javascript module.exports = (on, config) => { @@ -17,13 +21,13 @@ module.exports = (on, config) => { } ``` -The exported function is called whenever a project is opened (or at the beginning of a run if running headless) and takes 2 arguments, `on` and `config`: +The exported function is called whenever a project is opened (or at the beginning of a run if running tests headlessly) and takes 2 arguments, `on` and `config`: -## on +# on -`on` is a function used to on events that occur during the course of running Cypress. The function registered is what we call a *plugin*. +`on` is a function used on **events** that occur during the course of running Cypress. The function registered is what we call a *plugin*. -Using it looks like this: +{% url "Using it looks like this:" plugins-guide %} ```javascript module.exports = (on, config) => { @@ -33,14 +37,12 @@ module.exports = (on, config) => { } ``` -The arguments received by the callback functions and the requirements for what the plugin should do depend on the event. - -The following events are available: +The arguments received by the callback functions and the requirements for what the plugin should do depend on the **event**. -### file:preprocessor +***The following events are available:*** -Occurs when a spec or spec-related file is needed. Read the [Preprocessor API doc](./preprocessors.html) for more details. +* `file:preprocessor` Occurs when a spec or spec-related file is needed. Read the [Preprocessor API doc](./preprocessors.html) for more details. -## config +# config `config` is the resolved [Cypress configuration](https://on.cypress.io/guides/configuration), a combination of the default config and what the user has configured via `cypress.json`, `cypress.env.json`, command line options, and/or environment variables. Some plugins may require this to be passed along to them, so they can take certain actions based on the configuration. diff --git a/source/api/plugins/preprocessors-api.md b/source/api/plugins/preprocessors-api.md index 46f2b99b77..1eb379a52e 100644 --- a/source/api/plugins/preprocessors-api.md +++ b/source/api/plugins/preprocessors-api.md @@ -3,21 +3,23 @@ title: Preprocessors API comments: false --- -A preprocessor is a [plugin](./top-level-api.html) that runs when the support file or a spec file is required by the test runner. +A preprocessor is a {% url "plugin" plugins-api %} that runs when the {% url "support file" writing-and-organizing-tests#Support-file %} or {% url "test files" writing-and-organizing-tests#Test-files %} is required by the Test Runner. -It can compile/transpile that file from another language (e.g. CoffeeScript, ClojureScript) to JavaScript or from a newer version of JavaScript (e.g. ES2017) to a version that has more browser compatibility (ES5). +It can compile or transpile that file from another language (e.g. CoffeeScript, ClojureScript) to JavaScript or from a newer version of JavaScript (e.g. ES2017) to a version that has more browser compatibility (ES5). It can also watch the source file for changes, re-process it, and tell Cypress to re-run the tests. +# Examples + See the following preprocessors as examples. The code contains comments that explain how it utilizes the preprocessor API. * [Browserify Preprocessor](https://github.com/cypress-io/cypress-browserify-preprocessor) * [Webpack Preprocessor](https://github.com/cypress-io/cypress-webpack-preprocessor) * [Watch Preprocessor](https://github.com/cypress-io/cypress-watch-preprocessor) -Publish preprocessors to [npm](https://www.npmjs.com/) with the naming convention `cypress-*-preprocessor` (e.g. cypress-clojurescript-preprocessor). Use the following npm keywords: `cypress`, `cypress-plugin`, `cypress-preprocessor`. +# Usage -A user will configure a preprocessor by listening to the `file:preprocessor` event in the *plugins file* (`cypress/plugins/index.js` by default), like so: +A user will configure a preprocessor by listening to the `file:preprocessor` event in their {% url "`plugins file`" configuration#Folders-Files %} (`cypress/plugins/index.js` by default), like so: ```javascript // plugins file @@ -28,41 +30,35 @@ module.exports = (on) => { } ``` -The callback function should return one of the following: +***The callback function should return one of the following:*** -* The path to the **output file**\* -* A promise\*\* that resolves the path to the **output file**\* -* A promise\*\* that rejects with an error that occurred during processing +* The path to the **output file**\*. +* A promise\*\* that resolves the path to the **output file**\*. +* A promise\*\* that rejects with an error that occurred during processing. -\* The **output file** is the file that is created by the processing and will be served to the browser. If, for example, the source file is CoffeeScript (e.g. `spec.coffee`), the preprocessor should compile the CoffeeScript into JavaScript (e.g. `spec.js`), write that JavaScript file to disk, and return or resolve the full path to that file (e.g. `/Users/foo/tmp/spec.js`). +\* *The output file is the file that is created by the processing and will be served to the browser. If, for example, the source file is CoffeeScript (e.g. `spec.coffee`), the preprocessor should compile the CoffeeScript into JavaScript (e.g. `spec.js`), write that JavaScript file to disk, and return or resolve the full path to that file (e.g. `/Users/foo/tmp/spec.js`).* -\*\* The promise should resolve only after the file has completed writing to disk. The promise resolving is a signal that the file is ready to be served to the browser. +\*\* *The promise should resolve only after the file has completed writing to disk. The promise resolving is a signal that the file is ready to be served to the browser.* {% note warning %} -This function can and will be called multiple times with the same filePath, because it is called any time the file is requested by the browser (i.e. on each run of the tests). Make sure not to start a new watcher each time it is called. Instead, cache the watcher and, on subsequent calls, return a promise that resolves when the latest version of the file has been processed. +This function can and *will* be called multiple times with the same `filePath`, because it is called any time the file is requested by the browser (i.e. on each run of the tests). Make sure not to start a new watcher each time it is called. Instead, cache the watcher and, on subsequent calls, return a promise that resolves when the latest version of the file has been processed. {% endnote %} -## Config object properties +# Config object properties The `config` object passed to the callback function has the following properties: -### filePath - -The full path to the source file. - -### outputPath - -A path unique to the source file for saving the preprocessed file to disk. A preprocessor can choose to write the file elsewhere, but this provides a convenient default path for the file (alongside other Cypress app data). - -### shouldWatch - -A boolean indicating whether the preprocessor should watch for file changes or not. +Property | Description +--------- | ---------- +`filePath` | The full path to the source file. +`outputPath` | A path unique to the source file for saving the preprocessed file to disk. A preprocessor can choose to write the file elsewhere, but this provides a convenient default path for the file (alongside other Cypress app data). +`shouldWatch` | A boolean indicating whether the preprocessor should watch for file changes or not. -## Config object events +# Config object events The `config` object passed to the callback function is an [Event Emitter](https://nodejs.org/api/events.html#events_class_eventemitter). -### Receiving 'close' event +***Receiving 'close' event*** When the spec being run is closed or the project is closed, the 'close' event will be emitted. The preprocessor should do any necessary cleanup in this function, like closing the watcher when watching. @@ -75,7 +71,7 @@ config.on('close', () => { }) ``` -### Sending 'rerun' event +***Sending 'rerun' event*** If watching for file changes, emit 'rerun' after a file has finished being processed to let Cypress know to rerun the tests. @@ -85,3 +81,19 @@ fs.watch(filePath, () => { config.emit('rerun') }) ``` + +# Publishing + +Publish preprocessors to [npm](https://www.npmjs.com/) with the naming convention `cypress-*-preprocessor` (e.g. cypress-clojurescript-preprocessor). + +Use the following npm keywords: + +```json +"keywords": [ + "cypress", + "cypress-plugin", + "cypress-preprocessor" +] +``` + +Feel free to submit your published plugins to our {% url "list of plugins" plugins %}. diff --git a/source/guides/core-concepts/writing-and-organizing-tests.md b/source/guides/core-concepts/writing-and-organizing-tests.md index 0334303119..22e88d753a 100644 --- a/source/guides/core-concepts/writing-and-organizing-tests.md +++ b/source/guides/core-concepts/writing-and-organizing-tests.md @@ -44,7 +44,7 @@ Fixtures are used as external pieces of static data that can be used by your tes You would typically use them with the {% url `cy.fixture()` fixture %} command and most often when you're stubbing {% url 'Network Requests' network-requests %}. -## Test Files +## Test files Test files may be written as: @@ -69,7 +69,7 @@ By default Cypress will automatically include the plugins file `cypress/plugins/ {% url "Read more about using plugins to extend Cypress behavior." plugins-guide %} -## Support Files +## Support file By default Cypress will automatically include the support file `cypress/support/index.js` **before** every single spec file it runs. We do this purely as a convenience mechanism so you don't have to import this file in every single one of your spec files. diff --git a/source/guides/guides/plugins-guide.md b/source/guides/guides/plugins-guide.md index 2ac24ea25c..65eeef2de9 100644 --- a/source/guides/guides/plugins-guide.md +++ b/source/guides/guides/plugins-guide.md @@ -9,15 +9,17 @@ Plugins provides a way for hooking into and extending the behavior of Cypress. P You can configure a different location for the plugins file in your `cypress.json` via the {% url "`pluginsFile`" configuration#Folders-Files %} option. {% endnote %} -## Installation +# Installation -Installing a plugin requires [node.js](https://nodejs.org) (version 6.5.0+). +See the list of available {% url "plugins" plugins %} to install. ```shell npm install <plugin name> --save-dev ``` -## Usage +Installing a plugin requires [node.js](https://nodejs.org) (version 6.5.0+). + +# Usage ```javascript module.exports = (on, config) => { @@ -27,7 +29,7 @@ module.exports = (on, config) => { } ``` -The event depends on the type of plugin you would like to utilize. The exact usage depends on the plugin itself, so refer to any given plugin's documentation for details on that usage. +The **event** depends on the {% urlHash "type of plugin" Plugin-types %} you are using. The exact usage depends on the plugin itself, so refer to any given plugin's documentation for details on its usage. For example, here's how to use the [webpack preprocessor](https://github.com/cypress-io/cypress-webpack-preprocessor): @@ -39,14 +41,14 @@ module.exports = (on, config) => { } ``` -## Plugin Types +# Plugin types -### Preprocessors +## Preprocessors -Preprocessors are plugins that can process your support file and spec files before they're served to the browser. They are also responsible for watching files for changes and notifying Cypress to re-run tests. +Preprocessors are plugins that can process your {% url "support file" writing-and-organizing-tests#Support-file %} and {% url "test files" writing-and-organizing-tests#Test-files %} before they are served to the browser. They are also responsible for watching files for changes and notifying Cypress to re-run tests. -* Event: `file:preprocessor` -* Examples: [browserify](https://github.com/cypress-io/cypress-browserify-preprocessor),[webpack](https://github.com/cypress-io/cypress-webpack-preprocessor), [watch](https://github.com/cypress-io/cypress-watch-preprocessor) +* **Event:** `file:preprocessor` +* **Examples:** {% url "browserify-preprocessor" https://github.com/cypress-io/cypress-browserify-preprocessor %}, {% url "webpack-preprocessor" https://github.com/cypress-io/cypress-webpack-preprocessor %}, {% url "watch-preprocessor" https://github.com/cypress-io/cypress-watch-preprocessor %} ```javascript // the plugins file diff --git a/source/guides/references/best-practices.md b/source/guides/references/best-practices.md index cc37f0e680..2689b1eeca 100644 --- a/source/guides/references/best-practices.md +++ b/source/guides/references/best-practices.md @@ -426,7 +426,7 @@ The simplest solution here is to move your reset code to **before** the test run Code put in a `before` or `beforeEach` hook will **always** run prior to the test - even if you refreshed Cypress in the middle of an existing one! -This is also a great opportunity to use {%url 'root level hooks in mocha' https://github.com/mochajs/mochajs.github.io/blob/master/index.md#root-level-hooks %}. A perfect place to put these is in the {% url "`cypress/support/index.js` file" writing-and-organizing-tests#Support-Files %} because it is always evaluated before any test code from your spec files. +This is also a great opportunity to use {%url 'root level hooks in mocha' https://github.com/mochajs/mochajs.github.io/blob/master/index.md#root-level-hooks %}. A perfect place to put these is in the {% url "`cypress/support/index.js` file" writing-and-organizing-tests#Support-file %} because it is always evaluated before any test code from your spec files. **Hooks you add to the root will always run on all suites!** From c7117a51da93fe8f516f512a360c547d622b4034 Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Thu, 9 Nov 2017 15:02:45 -0500 Subject: [PATCH 24/31] Add main link to plugins guide on plugins. --- CONTRIBUTING.md | 1 + source/plugins/index.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e8b1ab1a82..b49fc6eaa6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,6 +9,7 @@ Thanks for taking the time to contribute! :smile: - [Writing Documentation](#writing-documentation) - [Links](#links) - [Adding Examples](#adding-examples) + - [Adding Plugins](#adding-plugins) - [Committing Code](#committing-code) - [Linting](#linting) - [Pull Requests](#pull-requests) diff --git a/source/plugins/index.md b/source/plugins/index.md index 15c7860932..676366b392 100644 --- a/source/plugins/index.md +++ b/source/plugins/index.md @@ -4,4 +4,4 @@ layout: plugins comments: false --- -Plugins provide a way to extend the behavior of Cypress. To submit your own plugin, [follow these instructions](https://github.com/cypress-io/cypress-documentation/blob/develop/CONTRIBUTING.md#adding-plugins). +{% url "Plugins" plugins-guide %} provide a way to extend the behavior of Cypress. To submit your own plugin, [follow these instructions](https://github.com/cypress-io/cypress-documentation/blob/develop/CONTRIBUTING.md#adding-plugins). From 9ebcf35874ff1fb49f2d10c01c2300a8b273ee8c Mon Sep 17 00:00:00 2001 From: Brian Mann Date: Fri, 17 Nov 2017 17:57:52 -0500 Subject: [PATCH 25/31] rename plugins-api to writing-a-plugin --- source/_data/sidebar.yml | 2 +- source/api/plugins/preprocessors-api.md | 2 +- source/api/plugins/{plugins-api.md => writing-a-plugin.md} | 2 +- themes/cypress/languages/en.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename source/api/plugins/{plugins-api.md => writing-a-plugin.md} (98%) diff --git a/source/_data/sidebar.yml b/source/_data/sidebar.yml index 87b587cd74..61db00741f 100644 --- a/source/_data/sidebar.yml +++ b/source/_data/sidebar.yml @@ -149,7 +149,7 @@ api: cypress-log: cypress-log.html cypress-server: cypress-server.html plugins: - plugins-api: plugins-api.html + writing-a-plugin: writing-a-plugin.html preprocessors-api: preprocessors-api.html tutorials: diff --git a/source/api/plugins/preprocessors-api.md b/source/api/plugins/preprocessors-api.md index 1eb379a52e..1d5eec8826 100644 --- a/source/api/plugins/preprocessors-api.md +++ b/source/api/plugins/preprocessors-api.md @@ -3,7 +3,7 @@ title: Preprocessors API comments: false --- -A preprocessor is a {% url "plugin" plugins-api %} that runs when the {% url "support file" writing-and-organizing-tests#Support-file %} or {% url "test files" writing-and-organizing-tests#Test-files %} is required by the Test Runner. +A preprocessor is a {% url "plugin" writing-a-plugin %} that runs when the {% url "support file" writing-and-organizing-tests#Support-file %} or {% url "test files" writing-and-organizing-tests#Test-files %} is required by the Test Runner. It can compile or transpile that file from another language (e.g. CoffeeScript, ClojureScript) to JavaScript or from a newer version of JavaScript (e.g. ES2017) to a version that has more browser compatibility (ES5). diff --git a/source/api/plugins/plugins-api.md b/source/api/plugins/writing-a-plugin.md similarity index 98% rename from source/api/plugins/plugins-api.md rename to source/api/plugins/writing-a-plugin.md index 68da79af3b..e6585a69e0 100644 --- a/source/api/plugins/plugins-api.md +++ b/source/api/plugins/writing-a-plugin.md @@ -1,5 +1,5 @@ --- -title: Plugins API +title: Writing a Plugin comments: false --- diff --git a/themes/cypress/languages/en.yml b/themes/cypress/languages/en.yml index 81b7a215ec..6342ad101e 100644 --- a/themes/cypress/languages/en.yml +++ b/themes/cypress/languages/en.yml @@ -175,7 +175,7 @@ sidebar: cypress-log: log cypress-server: Server plugins: Plugins - plugins-api: Plugins + writing-a-plugin: Writing a Plugin preprocessors-api: Preprocessors tutorials: test-a-react-todo-app: Test a React Todo App From c7ca25f1c183b0ef0694409e176b868f319dfebc Mon Sep 17 00:00:00 2001 From: Brian Mann Date: Fri, 17 Nov 2017 17:57:59 -0500 Subject: [PATCH 26/31] add link to plugins API docs --- source/api/introduction/api.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/api/introduction/api.md b/source/api/introduction/api.md index 1c802fb3de..c638dbd401 100644 --- a/source/api/introduction/api.md +++ b/source/api/introduction/api.md @@ -13,6 +13,8 @@ comments: false - **{% url 'Cypress API:' custom-commands %}** Configure the behavior of how Cypress works internally. You can do things like access Environment Variables, change configuration, create custom commands, and more. +- **{% url 'Plugins:' writing-a-plugin %}** Write a plugin to modify and extend the behavior of Cypress. + # Rules Each document attempts to cover the essentials of each method including: From 57c162e225d87c596d6788c6783188c36e1aa20c Mon Sep 17 00:00:00 2001 From: Brian Mann Date: Fri, 17 Nov 2017 17:58:13 -0500 Subject: [PATCH 27/31] rewrite plugins guide to better explain what plugins are, what you can do with them, and how to get started --- source/guides/guides/plugins-guide.md | 92 ++++++++++++++++++--------- 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/source/guides/guides/plugins-guide.md b/source/guides/guides/plugins-guide.md index 65eeef2de9..b9c9f5e92c 100644 --- a/source/guides/guides/plugins-guide.md +++ b/source/guides/guides/plugins-guide.md @@ -3,59 +3,91 @@ title: Plugins comments: false --- -Plugins provides a way for hooking into and extending the behavior of Cypress. Plugins can be configured within the plugins file, which will be searched for at `cypress/plugins/index.js` by default. +Plugins enable you to tap into, modify, or extend the internal behavior of Cypress. -{% note info %} -You can configure a different location for the plugins file in your `cypress.json` via the {% url "`pluginsFile`" configuration#Folders-Files %} option. +Normally, as a user all of your test code, your application, and commands are executed in the browser. But Cypress is also a **Node.js** process which plugins can use. + +> Plugins enable you to tap into the `node` process running outside of the browser. + +Plugins are a "seam" for you to write your own custom code that executes during particular stages of the Cypress lifecycle. + +{% note info "New Projects" %} +When new projects are added to Cypress we will automatically seed them with a basic plugins file. + +By default Cypress will create a plugins file at: `cypress/plugins/index.js`. + +This is configurable in your `cypress.json` with the {% url "`pluginsFile`" configuration#Folders-Files %} option. {% endnote %} -# Installation +# Plugin Types + +## Preprocessors + +As of today we offer a single plugin event: `file:preprocessor`. This event is used to customize how your test code is transpiled and sent to the browser. By default Cypress handles `coffeescript` and `ES6` using `babel` and then uses `browserify` to package it for the browser. -See the list of available {% url "plugins" plugins %} to install. +You can use the `file:preprocessor` event to do things like: + +- Add `Typescript` support +- Add the latest ES* support +- Write your test code in `Clojurescript` +- Customize the `babel` settings to add your own plugins +- Swap out `browserify` for `webpack` or anything else + +Check out our {% url 'File Preprocessor API docs' preprocessors-api %} which describe how to use this event. + +# List of Plugins + +Cypress maintains an official list of plugins created by us as well as the community. You can NPM install any of the plugins listed below: + +{% url 'Here is our official list of Cypress plugins.' plugins %} + +# Installing Plugins + +Plugins that we and other contributors write are just NPM modules. This enables them to be versioned and updated separately without needing to update Cypress itself. + +You can install any published plugin with NPM: ```shell npm install <plugin name> --save-dev ``` -Installing a plugin requires [node.js](https://nodejs.org) (version 6.5.0+). +# Using a Plugin -# Usage +Whether you install an NPM module, or just want to write your own code - you do all of that in this file: -```javascript -module.exports = (on, config) => { - on('', (arg1, arg2) => { - // plugin stuff here - }) -} +```text +cypress/plugins/index.js ``` -The **event** depends on the {% urlHash "type of plugin" Plugin-types %} you are using. The exact usage depends on the plugin itself, so refer to any given plugin's documentation for details on its usage. +{% note info %} +By default Cypress seeds this file for new projects, but if you have an existing project just create this file yourself. +{% endnote %} -For example, here's how to use the [webpack preprocessor](https://github.com/cypress-io/cypress-webpack-preprocessor): +Inside of this file, you'll export a function. Cypress will call this function, pass you the project's configuration, and enable you to bind to the events we expose. ```javascript -const webpack = require('@cypress/webpack-preprocessor') +// cypress/plugins/index.js +// export a function module.exports = (on, config) => { - on('file:preprocessor', webpack(config)) + + // bind to the event we care about + on('', (arg1, arg2) => { + // plugin stuff here + }) } ``` -# Plugin types +Check out our {% url 'Writing a Plugin API docs' writing-a-plugin %} which describes how to write plugins. -## Preprocessors +{% note warning "Node Version" %} -Preprocessors are plugins that can process your {% url "support file" writing-and-organizing-tests#Support-file %} and {% url "test files" writing-and-organizing-tests#Test-files %} before they are served to the browser. They are also responsible for watching files for changes and notifying Cypress to re-run tests. +Keep in mind - code executed in plugins is executed **by the node version** that comes bundled in Cypress itself. -* **Event:** `file:preprocessor` -* **Examples:** {% url "browserify-preprocessor" https://github.com/cypress-io/cypress-browserify-preprocessor %}, {% url "webpack-preprocessor" https://github.com/cypress-io/cypress-webpack-preprocessor %}, {% url "watch-preprocessor" https://github.com/cypress-io/cypress-watch-preprocessor %} +This version of node has **nothing to do** with your locally installed versions. Therefore you have to write node code which is compatible with this version. -```javascript -// the plugins file -const webpack = require('@cypress/webpack-preprocessor') +Currently the node version we use is `6.5.0`. -module.exports = (on, config) => { - // register the webpack plugin, using its default options - on('file:preprocessor', webpack(config)) -} -``` +This gets regularly updated (next version will be in the `8.x.x` range) so you'll likely be able to use all the latest ES7 features. + +{% endnote %} From 816b7cbe24be5b8a2847902266a4a73320051e6a Mon Sep 17 00:00:00 2001 From: Brian Mann Date: Fri, 17 Nov 2017 18:55:39 -0500 Subject: [PATCH 28/31] updated writing a plugin guide content - explain requiring npm modules - error handling - file watching --- source/api/plugins/writing-a-plugin.md | 122 ++++++++++++++++++++++--- source/guides/guides/plugins-guide.md | 2 +- 2 files changed, 111 insertions(+), 13 deletions(-) diff --git a/source/api/plugins/writing-a-plugin.md b/source/api/plugins/writing-a-plugin.md index e6585a69e0..5a61b7583d 100644 --- a/source/api/plugins/writing-a-plugin.md +++ b/source/api/plugins/writing-a-plugin.md @@ -5,29 +5,42 @@ comments: false The Plugins API allows you to hook into and extend Cypress behavior. -# pluginsFile +{% note info %} +**Note:** This document assumes you have read the {% url 'Plugins Guide' plugins-guide %}. +{% endnote %} + +# Plugins API -The API can be utilized within the plugins file, which will be searched for at `cypress/plugins/index.js` by default. Users can configure a different location for the plugins file in their `cypress.json` via the {% url "`pluginsFile`" configuration#Folders-Files %} option. +To get started, open up this file: + +```text +cypress/plugins/index.js +``` {% note info %} -The plugins file will be required by [Cypress' server](https://github.com/cypress-io/cypress/tree/master/packages/server), so it must be compatible with the [version of node that Cypress uses](https://github.com/cypress-io/cypress/blob/master/.node-version). +By default Cypress seeds this file for new projects, but if you have an existing project just create this file yourself. {% endnote %} -The plugins file should export a function with the following signature: +The plugins file must export a function with the following signature: ```javascript +// cypress/plugins/index.js + +// export a function module.exports = (on, config) => { // configure plugins here } ``` -The exported function is called whenever a project is opened (or at the beginning of a run if running tests headlessly) and takes 2 arguments, `on` and `config`: +The exported function is called whenever a project is opened either with `cypress open` or `cypress run`. -# on +Your function will receive 2 arguments: `on` and `config`. -`on` is a function used on **events** that occur during the course of running Cypress. The function registered is what we call a *plugin*. +## on -{% url "Using it looks like this:" plugins-guide %} +`on` is a function that you will use to register to various **events** that Cypress exposes. + +Registering to an event looks like this: ```javascript module.exports = (on, config) => { @@ -37,12 +50,97 @@ module.exports = (on, config) => { } ``` -The arguments received by the callback functions and the requirements for what the plugin should do depend on the **event**. +Each event documents its own argument signature. To understand how to use them, please {% urlHash 'refer to docs for each one' 'List-of-Events' %}. + +## config + +`config` is the resolved [Cypress configuration](https://on.cypress.io/guides/configuration) of the opened project. + +This configuration contains all of the values that get passed into the browser for your project. + +Some plugins may utilize or require these values, so they can take certain actions based on the configuration. + +{% url 'For a comprehensive list of all configuration values look here.' https://github.com/cypress-io/cypress/blob/master/packages/server/lib/config.coffee %} + +## List of Events ***The following events are available:*** -* `file:preprocessor` Occurs when a spec or spec-related file is needed. Read the [Preprocessor API doc](./preprocessors.html) for more details. +Event | Description +--- | --- +{% url `file:preprocessor` preprocessors-api %} | Occurs when a spec or spec-related file needs to be transpiled for the browser. + +{% note warning "More Coming Soon" %} +The Plugins API is brand new. + +We have many new plugin events {% issue 684 'we are adding' %}. +{% endnote %} + +# Execution Context + +Your `pluginsFile` is invoked when Cypress opens a project. + +Cypress does this by spawning an independent `child_process` which then `requires` in your `pluginsFile`. This is similar to the way Visual Studio Code or Atom works. + +You'll need to keep in mind it is **Cypress who is requiring your file** - not your local project, not your local node version, and not anything else you control. + +Because of this, this global context and the version of node is controlled by Cypress. + +{% note warning %} +Your code must be compatible with the version of node that comes with Cypress! +{% endnote %} + +Currently the node version we use is {% url `6.5.0` 'https://github.com/cypress-io/cypress/blob/master/.node-version' %}. + +This node version gets updated regularly (next version will be in the `8.x.x` range) so you'll likely be able to use all the latest ES7 features. + +## NPM Modules + +When Cypress executes your `pluginsFile` it will execute with `process.cwd()` set to your project's path. Additionally - you'll be able to `require` **any node module** you have installed. + +Additionally you can also `require` local files relative to your project. + +If your `package.json` looked like this: + +```js +{ + "name": "My Project", + "dependencies": { + "debug": "x.x.x" + }, + "devDependencies": { + "lodash": "x.x.x" + } +} +``` + +Then you could do any of the following in your `pluginsFile`: + +```js +// cypress/plugins/index.js + +const _ = require('lodash') // yup, dev dependencies +const path = require('path') // yup, built in node modules +const debug = require('debug') // yup, dependencies +const User = require('../../lib/models/user') // yup, relative local modules + +console.log(__dirname) // /Users/bmann/Dev/my-project/cypress/plugins/index.js + +console.log(process.cwd()) // /Users/bmann/Dev/my-project +``` + +# Error Handling + +Cypress spawns your `pluginsFile` in its own child process so it's isolated away from the context that Cypress itself runs in. That means you cannot accidentally modify or change Cypress's own execution in any way. + +If your `pluginsFile` has an uncaught exception, an unhandled rejection from a promise, a syntax error, or anything else - we'll automatically catch those and display them to you inside of the console and even in the Cypress GUI itself. + +Errors from your plugins will not crash Cypress. + +# File Changes + +Normally when writing node code, you typically have to restart the process after changing any files. -# config +With Cypress, we automatically watch your `pluginsFile` and any changes to it will take effect immediately. We'll read the file in and execute the exported function again. -`config` is the resolved [Cypress configuration](https://on.cypress.io/guides/configuration), a combination of the default config and what the user has configured via `cypress.json`, `cypress.env.json`, command line options, and/or environment variables. Some plugins may require this to be passed along to them, so they can take certain actions based on the configuration. +This enables you to iterate on plugin code even with Cypress already running. diff --git a/source/guides/guides/plugins-guide.md b/source/guides/guides/plugins-guide.md index b9c9f5e92c..34102e4f6d 100644 --- a/source/guides/guides/plugins-guide.md +++ b/source/guides/guides/plugins-guide.md @@ -88,6 +88,6 @@ This version of node has **nothing to do** with your locally installed versions. Currently the node version we use is `6.5.0`. -This gets regularly updated (next version will be in the `8.x.x` range) so you'll likely be able to use all the latest ES7 features. +This node version gets updated regularly (next version will be in the `8.x.x` range) so you'll likely be able to use all the latest ES7 features. {% endnote %} From d7bc348ea884e38e97683b966dbd74e597f0c57f Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Sat, 18 Nov 2017 10:23:08 -0500 Subject: [PATCH 29/31] Minor updates - grammar - added more links - link directly to our node version instead of hardcoding - sentence case all headings --- source/api/plugins/writing-a-plugin.md | 42 +++++++++++++------------- source/guides/guides/plugins-guide.md | 40 ++++++++++++------------ 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/source/api/plugins/writing-a-plugin.md b/source/api/plugins/writing-a-plugin.md index 5a61b7583d..67aae9e1e2 100644 --- a/source/api/plugins/writing-a-plugin.md +++ b/source/api/plugins/writing-a-plugin.md @@ -32,7 +32,7 @@ module.exports = (on, config) => { } ``` -The exported function is called whenever a project is opened either with `cypress open` or `cypress run`. +The exported function is called whenever a project is opened either with {% url "`cypress open`" command-line#cypress-open %} or {% url "`cypress run`" command-line#cypress-run %}. Your function will receive 2 arguments: `on` and `config`. @@ -50,7 +50,7 @@ module.exports = (on, config) => { } ``` -Each event documents its own argument signature. To understand how to use them, please {% urlHash 'refer to docs for each one' 'List-of-Events' %}. +Each event documents its own argument signature. To understand how to use them, please {% urlHash 'refer to docs for each one' 'List-of-events' %}. ## config @@ -62,7 +62,7 @@ Some plugins may utilize or require these values, so they can take certain actio {% url 'For a comprehensive list of all configuration values look here.' https://github.com/cypress-io/cypress/blob/master/packages/server/lib/config.coffee %} -## List of Events +## List of events ***The following events are available:*** @@ -76,31 +76,31 @@ The Plugins API is brand new. We have many new plugin events {% issue 684 'we are adding' %}. {% endnote %} -# Execution Context +# Execution context Your `pluginsFile` is invoked when Cypress opens a project. Cypress does this by spawning an independent `child_process` which then `requires` in your `pluginsFile`. This is similar to the way Visual Studio Code or Atom works. -You'll need to keep in mind it is **Cypress who is requiring your file** - not your local project, not your local node version, and not anything else you control. +You will need to keep in mind it is **Cypress who is requiring your file** - not your local project, not your local node version, and not anything else under your control. Because of this, this global context and the version of node is controlled by Cypress. {% note warning %} -Your code must be compatible with the version of node that comes with Cypress! +Your code must be compatible with the {% url 'version of node' https://github.com/cypress-io/cypress/blob/master/.node-version %} that comes with Cypress! {% endnote %} -Currently the node version we use is {% url `6.5.0` 'https://github.com/cypress-io/cypress/blob/master/.node-version' %}. +You can find the current node version we use {% url 'here' https://github.com/cypress-io/cypress/blob/master/.node-version %}. This node version gets updated regularly (next version will be in the `8.x.x` range) so you'll likely be able to use all the latest ES7 features. -## NPM Modules +## NPM modules -When Cypress executes your `pluginsFile` it will execute with `process.cwd()` set to your project's path. Additionally - you'll be able to `require` **any node module** you have installed. +When Cypress executes your `pluginsFile` it will execute with `process.cwd()` set to your project's path. Additionally - you will be able to `require` **any node module** you have installed. -Additionally you can also `require` local files relative to your project. +You can also `require` local files relative to your project. -If your `package.json` looked like this: +**For example, if your `package.json` looked like this:** ```js { @@ -114,7 +114,7 @@ If your `package.json` looked like this: } ``` -Then you could do any of the following in your `pluginsFile`: +**Then you could do any of the following in your `pluginsFile`:** ```js // cypress/plugins/index.js @@ -124,23 +124,23 @@ const path = require('path') // yup, built in node modules const debug = require('debug') // yup, dependencies const User = require('../../lib/models/user') // yup, relative local modules -console.log(__dirname) // /Users/bmann/Dev/my-project/cypress/plugins/index.js +console.log(__dirname) // /Users/janelane/Dev/my-project/cypress/plugins/index.js -console.log(process.cwd()) // /Users/bmann/Dev/my-project +console.log(process.cwd()) // /Users/janelane/Dev/my-project ``` -# Error Handling +# Error handling -Cypress spawns your `pluginsFile` in its own child process so it's isolated away from the context that Cypress itself runs in. That means you cannot accidentally modify or change Cypress's own execution in any way. +Cypress spawns your `pluginsFile` in its own child process so it is isolated away from the context that Cypress itself runs in. That means you cannot accidentally modify or change Cypress' own execution in any way. -If your `pluginsFile` has an uncaught exception, an unhandled rejection from a promise, a syntax error, or anything else - we'll automatically catch those and display them to you inside of the console and even in the Cypress GUI itself. +If your `pluginsFile` has an uncaught exception, an unhandled rejection from a promise, a syntax error, or anything else - we will automatically catch those and display them to you inside of the console and even in the Test Runner itself. -Errors from your plugins will not crash Cypress. +Errors from your plugins *will not crash* Cypress. -# File Changes +# File changes -Normally when writing node code, you typically have to restart the process after changing any files. +Normally when writing code in Node, you typically have to restart the process after changing any files. -With Cypress, we automatically watch your `pluginsFile` and any changes to it will take effect immediately. We'll read the file in and execute the exported function again. +With Cypress, we automatically watch your `pluginsFile` and any changes made will take effect immediately. We will read the file in and execute the exported function again. This enables you to iterate on plugin code even with Cypress already running. diff --git a/source/guides/guides/plugins-guide.md b/source/guides/guides/plugins-guide.md index 34102e4f6d..c70b7db487 100644 --- a/source/guides/guides/plugins-guide.md +++ b/source/guides/guides/plugins-guide.md @@ -5,7 +5,7 @@ comments: false Plugins enable you to tap into, modify, or extend the internal behavior of Cypress. -Normally, as a user all of your test code, your application, and commands are executed in the browser. But Cypress is also a **Node.js** process which plugins can use. +Normally, as a user, all of your test code, your application, and Cypress commands are executed in the browser. But Cypress is also a **Node.js** process that plugins can use. > Plugins enable you to tap into the `node` process running outside of the browser. @@ -19,41 +19,41 @@ By default Cypress will create a plugins file at: `cypress/plugins/index.js`. This is configurable in your `cypress.json` with the {% url "`pluginsFile`" configuration#Folders-Files %} option. {% endnote %} -# Plugin Types +# Plugin types ## Preprocessors -As of today we offer a single plugin event: `file:preprocessor`. This event is used to customize how your test code is transpiled and sent to the browser. By default Cypress handles `coffeescript` and `ES6` using `babel` and then uses `browserify` to package it for the browser. +As of today we offer a single plugin event: `file:preprocessor`. This event is used to customize how your test code is transpiled and sent to the browser. By default Cypress handles CoffeeScript and ES6 using `babel` and then uses `browserify` to package it for the browser. You can use the `file:preprocessor` event to do things like: -- Add `Typescript` support -- Add the latest ES* support -- Write your test code in `Clojurescript` -- Customize the `babel` settings to add your own plugins -- Swap out `browserify` for `webpack` or anything else +- Add TypeScript support. +- Add the latest ES* support. +- Write your test code in ClosureScript. +- Customize the `babel` settings to add your own plugins. +- Swap out `browserify` for `webpack` or anything else. Check out our {% url 'File Preprocessor API docs' preprocessors-api %} which describe how to use this event. -# List of Plugins +# List of plugins -Cypress maintains an official list of plugins created by us as well as the community. You can NPM install any of the plugins listed below: +Cypress maintains an official list of plugins created by us and the community. You can `npm install` any of the plugins listed below: -{% url 'Here is our official list of Cypress plugins.' plugins %} +{% url 'Our official list of Cypress plugins.' plugins %} -# Installing Plugins +# Installing plugins -Plugins that we and other contributors write are just NPM modules. This enables them to be versioned and updated separately without needing to update Cypress itself. +Plugins from our {% url 'official list' plugins %} are just NPM modules. This enables them to be versioned and updated separately without needing to update Cypress itself. -You can install any published plugin with NPM: +You can install any published plugin using NPM: ```shell npm install <plugin name> --save-dev ``` -# Using a Plugin +# Using a plugin -Whether you install an NPM module, or just want to write your own code - you do all of that in this file: +Whether you install an NPM module, or just want to write your own code - you should do all of that in this file: ```text cypress/plugins/index.js @@ -63,7 +63,7 @@ cypress/plugins/index.js By default Cypress seeds this file for new projects, but if you have an existing project just create this file yourself. {% endnote %} -Inside of this file, you'll export a function. Cypress will call this function, pass you the project's configuration, and enable you to bind to the events we expose. +Inside of this file, you will export a function. Cypress will call this function, pass you the project's configuration, and enable you to bind to the events exposed. ```javascript // cypress/plugins/index.js @@ -78,15 +78,15 @@ module.exports = (on, config) => { } ``` -Check out our {% url 'Writing a Plugin API docs' writing-a-plugin %} which describes how to write plugins. +Check out our {% url 'Writing a Plugin doc' writing-a-plugin %} which describes how to write plugins. -{% note warning "Node Version" %} +{% note warning "Node version" %} Keep in mind - code executed in plugins is executed **by the node version** that comes bundled in Cypress itself. This version of node has **nothing to do** with your locally installed versions. Therefore you have to write node code which is compatible with this version. -Currently the node version we use is `6.5.0`. +You can find the current node version we use {% url 'here' https://github.com/cypress-io/cypress/blob/master/.node-version %}. This node version gets updated regularly (next version will be in the `8.x.x` range) so you'll likely be able to use all the latest ES7 features. From e11061d93c6bbd01622ad673ac660b59d93794d5 Mon Sep 17 00:00:00 2001 From: Brian Mann Date: Sun, 19 Nov 2017 22:17:52 -0500 Subject: [PATCH 30/31] clarify defaults and examples --- source/_data/plugins.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/_data/plugins.yml b/source/_data/plugins.yml index 6feb05ca77..0f43dd5027 100644 --- a/source/_data/plugins.yml +++ b/source/_data/plugins.yml @@ -1,7 +1,7 @@ - name: Preprocessors plugins: - name: Browserify - description: For bundling JavaScript via browserify. + description: For bundling JavaScript via browserify. This is the default preprocessor that's built into Cypress. link: https://github.com/cypress-io/cypress-browserify-preprocessor keywords: [browserify] @@ -11,6 +11,6 @@ keywords: [webpack] - name: Watch - description: Simple preprocessor that only watches files. + description: Simple preprocessor that only watches files. Useful as an example reference. link: https://github.com/cypress-io/cypress-watch-preprocessor keywords: [file-watcher] From b6a4aea1d7f4505ad10b14140be3dbc2d7d8ced9 Mon Sep 17 00:00:00 2001 From: Brian Mann Date: Sun, 19 Nov 2017 22:18:51 -0500 Subject: [PATCH 31/31] provide more context for why you'd use the preprocessor API. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - talk about modifying the browserify defaults - call out the steps for working with the API - rename confusing ‘config’ argument --- source/api/plugins/preprocessors-api.md | 87 ++++++++++++++++++------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/source/api/plugins/preprocessors-api.md b/source/api/plugins/preprocessors-api.md index 1d5eec8826..1125e36399 100644 --- a/source/api/plugins/preprocessors-api.md +++ b/source/api/plugins/preprocessors-api.md @@ -3,28 +3,55 @@ title: Preprocessors API comments: false --- -A preprocessor is a {% url "plugin" writing-a-plugin %} that runs when the {% url "support file" writing-and-organizing-tests#Support-file %} or {% url "test files" writing-and-organizing-tests#Test-files %} is required by the Test Runner. +A preprocessor is the plugin responsible for preparing a {% url "support file" writing-and-organizing-tests#Support-file %} or a {% url "test file" writing-and-organizing-tests#Test-files %} for the browser. -It can compile or transpile that file from another language (e.g. CoffeeScript, ClojureScript) to JavaScript or from a newer version of JavaScript (e.g. ES2017) to a version that has more browser compatibility (ES5). +A preprocessor could transpile your file from another language (CoffeeScript or ClojureScript) or from a newer version of JavaScript (ES2017). -It can also watch the source file for changes, re-process it, and tell Cypress to re-run the tests. +A preprocessor also typically watches the source files for changes, processes them again, and then notifies Cypress to re-run the tests. # Examples -See the following preprocessors as examples. The code contains comments that explain how it utilizes the preprocessor API. +We've created three preprocessors as examples for you to look at. These are fully functioning preprocessors. -* [Browserify Preprocessor](https://github.com/cypress-io/cypress-browserify-preprocessor) -* [Webpack Preprocessor](https://github.com/cypress-io/cypress-webpack-preprocessor) -* [Watch Preprocessor](https://github.com/cypress-io/cypress-watch-preprocessor) +The code contains comments that explain how it utilizes the preprocessor API. + +* {% url 'Browserify Preprocessor' https://github.com/cypress-io/cypress-browserify-preprocessor %} +* {% url 'Webpack Preprocessor' https://github.com/cypress-io/cypress-webpack-preprocessor %} +* {% url 'Watch Preprocessor' https://github.com/cypress-io/cypress-watch-preprocessor %} + +# Defaults + +By default, Cypress comes packaged with the **Browserify Preprocessor** already installed. + +The Browserify Preprocessor handles: + +- CoffeeScript `1.x.x` +- ES2015 via Babel +- JSX and CJSX +- Watching and caching files + +The exact default configuration options {% url 'can be found here' https://github.com/cypress-io/cypress-browserify-preprocessor#browserifyoptions %}. + +{% note info %} +Are you looking to change the **default options** for Browserify? +{% endnote %} + +Changing the Browserify options lets you: + +- Add your own Babel plugins +- Add support for Typescript +- Add support for CoffeeScript `2.x.x` + +Please read this link in the {% url 'browserify preprocessor' https://github.com/cypress-io/cypress-browserify-preprocessor#modifying-default-options %} repo for instructions on modifying these. # Usage -A user will configure a preprocessor by listening to the `file:preprocessor` event in their {% url "`plugins file`" configuration#Folders-Files %} (`cypress/plugins/index.js` by default), like so: +The use a preprocessor, you should bind to the `file:preprocessor` event in your {% url "`pluginsFile`" configuration#Folders-Files %}: ```javascript // plugins file -module.exports = (on) => { - on('file:preprocessor', (config) => { +module.exports = (on, config) => { + on('file:preprocessor', (file) => { // ... }) } @@ -32,53 +59,63 @@ module.exports = (on) => { ***The callback function should return one of the following:*** -* The path to the **output file**\*. -* A promise\*\* that resolves the path to the **output file**\*. -* A promise\*\* that rejects with an error that occurred during processing. +* A promise\* that eventually resolves the path to the **built file**\*\*. +* A promise\* that eventually rejects with an error that occurred during processing. + +> \* The promise should resolve only after the file has completed writing to disk. The promise resolving is a signal that the file is ready to be served to the browser. -\* *The output file is the file that is created by the processing and will be served to the browser. If, for example, the source file is CoffeeScript (e.g. `spec.coffee`), the preprocessor should compile the CoffeeScript into JavaScript (e.g. `spec.js`), write that JavaScript file to disk, and return or resolve the full path to that file (e.g. `/Users/foo/tmp/spec.js`).* +--- + +> \*\* The built file is the file that is created by the preprocessor that will eventually be served to the browser. -\*\* *The promise should resolve only after the file has completed writing to disk. The promise resolving is a signal that the file is ready to be served to the browser.* +> If, for example, the source file is `spec.coffee`, the preprocessor should: +1. Compile the CoffeeScript into JavaScript `spec.js` +2. Write that JavaScript file to disk (example: `/Users/foo/tmp/spec.js`) +3. Resolve with the absolute path to that file: `/Users/foo/tmp/spec.js` {% note warning %} -This function can and *will* be called multiple times with the same `filePath`, because it is called any time the file is requested by the browser (i.e. on each run of the tests). Make sure not to start a new watcher each time it is called. Instead, cache the watcher and, on subsequent calls, return a promise that resolves when the latest version of the file has been processed. +This callback function can and *will* be called multiple times with the same `filePath`. + +The callback function is called any time a file is requested by the browser. This happens on each run of the tests. + +Make sure not to start a new watcher each time it is called. Instead, cache the watcher and, on subsequent calls, return a promise that resolves when the latest version of the file has been processed. {% endnote %} -# Config object properties +# Req object -The `config` object passed to the callback function has the following properties: +The `file` object passed to the callback function has the following properties: Property | Description --------- | ---------- `filePath` | The full path to the source file. -`outputPath` | A path unique to the source file for saving the preprocessed file to disk. A preprocessor can choose to write the file elsewhere, but this provides a convenient default path for the file (alongside other Cypress app data). +`outputPath` | The suggested path for saving the preprocessed file to disk. This is unique to the source file. A preprocessor can choose to write the file elsewhere, but Cypress automatically provides you this value as a convenient default. `shouldWatch` | A boolean indicating whether the preprocessor should watch for file changes or not. -# Config object events +# Req events -The `config` object passed to the callback function is an [Event Emitter](https://nodejs.org/api/events.html#events_class_eventemitter). +The `file` object passed to the callback function is an [Event Emitter](https://nodejs.org/api/events.html#events_class_eventemitter). ***Receiving 'close' event*** -When the spec being run is closed or the project is closed, the 'close' event will be emitted. The preprocessor should do any necessary cleanup in this function, like closing the watcher when watching. +When the spec being run is closed or the project is closed, the `close` event will be emitted. The preprocessor should do any necessary cleanup in this function, like closing the watcher when watching. ```javascript // example const watcher = fs.watch(filePath, /* ... */) -config.on('close', () => { +file.on('close', () => { watcher.close() }) ``` ***Sending 'rerun' event*** -If watching for file changes, emit 'rerun' after a file has finished being processed to let Cypress know to rerun the tests. +If watching for file changes, emit `rerun` after a file has finished being processed to let Cypress know to rerun the tests. ```javascript // example fs.watch(filePath, () => { - config.emit('rerun') + file.emit('rerun') }) ```