eslint-plugin-cypress 2.15.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ . "$(dirname -- "$0")/_/husky.sh"
3
+
4
+ npm run lint
package/.node-version ADDED
@@ -0,0 +1 @@
1
+ 20.12.2
package/.nvmrc ADDED
@@ -0,0 +1 @@
1
+ 20.12.2
@@ -0,0 +1,16 @@
1
+ # Contributing to cypress-io/eslint-plugin-cypress
2
+
3
+ Thanks for taking the time to contribute! :smile:
4
+
5
+ To add a new rule:
6
+ * Fork and clone this repository
7
+ * Generate a new rule (a [yeoman generator](https://github.com/eslint/generator-eslint) is available)
8
+ * Write test scenarios then implement logic
9
+ * Describe the rule in the generated `docs` file
10
+ * Run `npm test` to run [Jest](https://jestjs.io/) or
11
+ * Run `npm start` to run [Jest](https://jestjs.io/) in [watchAll](https://jestjs.io/docs/cli#--watchall) mode where it remains active and reruns when source changes are made
12
+ * Make sure all tests are passing
13
+ * Add the rule to the [README](README.md) file
14
+ * Create a PR
15
+
16
+ Use the following commit message conventions: https://github.com/semantic-release/semantic-release#commit-message-format
package/README.md CHANGED
@@ -6,6 +6,8 @@ Note: If you installed ESLint globally then you must also install `eslint-plugin
6
6
 
7
7
  ## Installation
8
8
 
9
+ Prerequisites: [ESLint](https://www.npmjs.com/package/eslint) `v7` or `v8`. ESLint `v9` is **not** supported yet.
10
+
9
11
  ```sh
10
12
  npm install eslint-plugin-cypress --save-dev
11
13
  ```
@@ -36,6 +38,7 @@ You can add rules:
36
38
  "cypress/assertion-before-screenshot": "warn",
37
39
  "cypress/no-force": "warn",
38
40
  "cypress/no-async-tests": "error",
41
+ "cypress/no-async-before": "error",
39
42
  "cypress/no-pause": "error"
40
43
  }
41
44
  }
@@ -114,8 +117,6 @@ These rules enforce some of the [best practices recommended for using Cypress](h
114
117
 
115
118
  Rules with a check mark (✅) are enabled by default while using the `plugin:cypress/recommended` config.
116
119
 
117
- **NOTE**: These rules currently require eslint 5.0 or greater. If you would like support added for eslint 4.x, please 👍 [this issue](https://github.com/cypress-io/eslint-plugin-cypress/issues/14).
118
-
119
120
  | | Rule ID | Description |
120
121
  | :-- | :------------------------------------------------------------------------- | :-------------------------------------------------------------- |
121
122
  | ✅ | [no-assigning-return-values](./docs/rules/no-assigning-return-values.md) | Prevent assigning return values of cy calls |
@@ -127,6 +128,44 @@ Rules with a check mark (✅) are enabled by default while using the `plugin:cyp
127
128
  | | [require-data-selectors](./docs/rules/require-data-selectors.md) | Only allow data-\* attribute selectors (require-data-selectors) |
128
129
  | | [no-pause](./docs/rules/no-pause.md) | Disallow `cy.pause()` parent command |
129
130
 
131
+ ## Mocha and Chai
132
+
133
+ Cypress is built on top of [Mocha](https://on.cypress.io/guides/references/bundled-libraries#Mocha) and [Chai](https://on.cypress.io/guides/references/bundled-libraries#Chai). See the following sections for information on using ESLint plugins [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) and [eslint-plugin-chai-friendly](https://www.npmjs.com/package/eslint-plugin-chai-friendly) together with `eslint-plugin-cypress`.
134
+
135
+ ## Mocha `.only` and `.skip`
136
+
137
+ During test spec development, [Mocha exclusive tests](https://mochajs.org/#exclusive-tests) `.only` or [Mocha inclusive tests](https://mochajs.org/#inclusive-tests) `.skip` may be used to control which tests are executed, as described in the Cypress documentation [Excluding and Including Tests](https://on.cypress.io/guides/core-concepts/writing-and-organizing-tests#Excluding-and-Including-Tests). To apply corresponding rules, you can install and use [eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha). The rule [mocha/no-exclusive-tests](https://github.com/lo1tuma/eslint-plugin-mocha/blob/main/docs/rules/no-exclusive-tests.md) detects the use of `.only` and the [mocha/no-skipped-tests](https://github.com/lo1tuma/eslint-plugin-mocha/blob/main/docs/rules/no-skipped-tests.md) rule detects the use of `.skip`:
138
+
139
+ ```sh
140
+ npm install --save-dev eslint-plugin-mocha
141
+ ```
142
+
143
+ In your `.eslintrc.json`:
144
+
145
+ ```json
146
+ {
147
+ "plugins": [
148
+ "cypress",
149
+ "mocha"
150
+ ],
151
+ "rules": {
152
+ "mocha/no-exclusive-tests": "warn",
153
+ "mocha/no-skipped-tests": "warn"
154
+ }
155
+ }
156
+ ```
157
+
158
+ Or you can simply use the `cypress/recommended` and `mocha/recommended` configurations together, for example:
159
+
160
+ ```json
161
+ {
162
+ "extends": [
163
+ "plugin:cypress/recommended",
164
+ "plugin:mocha/recommended"
165
+ ]
166
+ }
167
+ ```
168
+
130
169
  ## Chai and `no-unused-expressions`
131
170
 
132
171
  Using an assertion such as `expect(value).to.be.true` can fail the ESLint rule `no-unused-expressions` even though it's not an error in this case. To fix this, you can install and use [eslint-plugin-chai-friendly](https://www.npmjs.com/package/eslint-plugin-chai-friendly).
@@ -158,16 +197,6 @@ Or you can simply add its `recommended` config:
158
197
  }
159
198
  ```
160
199
 
161
- ## Contribution Guide
162
-
163
- To add a new rule:
164
- * Fork and clone this repository
165
- * Generate a new rule (a [yeoman generator](https://github.com/eslint/generator-eslint) is available)
166
- * Run `yarn start` or `npm start`
167
- * Write test scenarios then implement logic
168
- * Describe the rule in the generated `docs` file
169
- * Make sure all tests are passing
170
- * Add the rule to this README
171
- * Create a PR
200
+ ## Contributing
172
201
 
173
- Use the following commit message conventions: https://github.com/semantic-release/semantic-release#commit-message-format
202
+ Please see our [Contributing Guideline](./CONTRIBUTING.md) which explains how to contribute rules or other fixes and features to the repo.
package/circle.yml CHANGED
@@ -5,15 +5,13 @@ workflows:
5
5
  main:
6
6
  jobs:
7
7
  - lint
8
- - test-v4
9
- - test-v5
10
- - test-v6
8
+ - test-v7
9
+ - test-v8
11
10
  - release:
12
11
  requires:
13
12
  - lint
14
- - test-v4
15
- - test-v5
16
- - test-v6
13
+ - test-v7
14
+ - test-v8
17
15
  filters:
18
16
  branches:
19
17
  only:
@@ -22,60 +20,63 @@ workflows:
22
20
  jobs:
23
21
  lint:
24
22
  docker:
25
- - image: circleci/node:16
23
+ - image: cimg/node:20.12.2
26
24
  steps:
27
25
  - checkout
28
26
  - run:
29
27
  name: Install dependencies
30
- command: npm install
28
+ command: npm ci
29
+ - run:
30
+ name: Show ESLint version
31
+ command: npx eslint --version
31
32
  - run:
32
33
  name: Lint code
33
34
  command: npm run lint
34
35
 
35
- test-v4:
36
+ test-v7:
36
37
  docker:
37
- - image: circleci/node:16
38
+ - image: cimg/node:20.12.2
38
39
  steps:
39
40
  - checkout
40
41
  - run:
41
42
  name: Install dependencies
42
- command: npm install
43
+ command: npm ci
43
44
  - run:
44
- name: Test ESLint 4
45
- command: npm run test:v4
46
-
47
- test-v5:
48
- docker:
49
- - image: circleci/node:16
50
- steps:
51
- - checkout
45
+ name: Install ESLint 7
46
+ command: npm install eslint@7
52
47
  - run:
53
- name: Install dependencies
54
- command: npm install
48
+ name: Show ESLint version
49
+ command: npx eslint --version
55
50
  - run:
56
- name: Test ESLint 5
57
- command: npm run test
51
+ name: Test ESLint 7
52
+ command: npm test
58
53
 
59
- test-v6:
54
+ test-v8:
60
55
  docker:
61
- - image: circleci/node:16
56
+ - image: cimg/node:20.12.2
62
57
  steps:
63
58
  - checkout
64
59
  - run:
65
60
  name: Install dependencies
66
- command: npm install
61
+ command: npm ci
62
+ - run:
63
+ name: Install ESLint 8
64
+ command: npm install eslint@8
65
+ - run:
66
+ name: Show ESLint version
67
+ command: npx eslint --version
67
68
  - run:
68
- name: Test ESLint 6
69
- command: npm run test:v6
69
+ name: Test ESLint 8
70
+ command: npm test
70
71
 
71
72
  release:
72
73
  docker:
73
- - image: circleci/node:16
74
+ - image: cimg/node:20.12.2
74
75
  steps:
75
76
  - checkout
76
77
  - run:
77
78
  name: Install dependencies
78
- command: npm install
79
+ command: npm ci
79
80
  - run:
80
81
  name: Run semantic release
81
82
  command: npm run semantic-release
@@ -0,0 +1,52 @@
1
+ # Prevent using async/await in Cypress test cases (no-async-tests)
2
+
3
+ Cypress commands that return a promise may cause side effects in before/beforeEach hooks, possibly causing unexpected behavior.
4
+
5
+ ## Rule Details
6
+
7
+ This rule disallows using `async` `before` and `beforeEach` functions.
8
+
9
+ Examples of **incorrect** code for this rule:
10
+
11
+ ```js
12
+ describe('my feature', () => {
13
+ before('my test case', async () => {
14
+ await cy.get('.myClass')
15
+ // other operations
16
+ })
17
+ })
18
+ ```
19
+
20
+ ```js
21
+ describe('my feature', () => {
22
+ before('my test case', async () => {
23
+ cy
24
+ .get('.myClass')
25
+ .click()
26
+
27
+ await someAsyncFunction()
28
+ })
29
+ })
30
+ ```
31
+
32
+ Examples of **correct** code for this rule:
33
+
34
+ ```js
35
+ describe('my feature', () => {
36
+ before('my test case', () => {
37
+ cy.get('.myClass')
38
+ // other operations
39
+ })
40
+ })
41
+
42
+ ```
43
+
44
+ ## When Not To Use It
45
+
46
+ If there are genuine use-cases for using `async/await` in your before then you may not want to include this rule (or at least demote it to a warning).
47
+
48
+ ## Further Reading
49
+
50
+ - [Commands Are Asynchronous](https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Commands-Are-Asynchronous)
51
+ - [Commands Are Promises](https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Commands-Are-Promises)
52
+ - [Commands Are Not Promises](https://docs.cypress.io/guides/core-concepts/introduction-to-cypress.html#Commands-Are-Not-Promises)
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ meta: {
5
+ docs: {
6
+ description: 'Prevent using async/await in Cypress before methods',
7
+ category: 'Possible Errors',
8
+ recommended: true,
9
+ },
10
+ messages: {
11
+ unexpected: 'Avoid using async functions with Cypress before / beforeEach functions',
12
+ },
13
+ },
14
+
15
+ create (context) {
16
+ function isBeforeBlock (callExpressionNode) {
17
+ const { type, name } = callExpressionNode.callee
18
+
19
+ return type === 'Identifier'
20
+ && name === 'before' || name === 'beforeEach'
21
+ }
22
+
23
+ function isBeforeAsync (node) {
24
+ return node.arguments
25
+ && node.arguments.length >= 2
26
+ && node.arguments[1].async === true
27
+ }
28
+
29
+ return {
30
+ Identifier (node) {
31
+ if (node.name === 'cy' || node.name === 'Cypress') {
32
+ const ancestors = context.getAncestors()
33
+ const asyncTestBlocks = ancestors
34
+ .filter((n) => n.type === 'CallExpression')
35
+ .filter(isBeforeBlock)
36
+ .filter(isBeforeAsync)
37
+
38
+ if (asyncTestBlocks.length >= 1) {
39
+ asyncTestBlocks.forEach((node) => {
40
+ context.report({ node, messageId: 'unexpected' })
41
+ })
42
+ }
43
+ }
44
+ },
45
+ }
46
+ },
47
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-cypress",
3
- "version": "2.15.1",
3
+ "version": "3.0.0",
4
4
  "description": "An ESLint plugin for projects using Cypress",
5
5
  "main": "index.js",
6
6
  "author": "Cypress-io",
@@ -19,34 +19,32 @@
19
19
  },
20
20
  "homepage": "https://github.com/cypress-io/eslint-plugin-cypress#readme",
21
21
  "peerDependencies": {
22
- "eslint": ">= 3.2.1"
22
+ "eslint": ">=7 <9"
23
23
  },
24
24
  "dependencies": {
25
25
  "globals": "^13.20.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@cypress/eslint-plugin-dev": "3.2.0",
29
- "@cypress/eslint-plugin-json": "3.2.1",
30
- "condition-circle": "2.0.2",
31
- "eslint": "^5.7.0",
32
- "husky": "^3.0.0",
33
- "jest": "^24.8.0",
34
- "semantic-release": "15.13.18"
28
+ "@cypress/eslint-plugin-dev": "3.9.1",
29
+ "@cypress/eslint-plugin-json": "3.2.3",
30
+ "@typescript-eslint/eslint-plugin": "^4.33.0",
31
+ "@typescript-eslint/parser": "^4.33.0",
32
+ "eslint": "^7.32.0",
33
+ "eslint-plugin-mocha": "^6.3.0",
34
+ "husky": "^8.0.3",
35
+ "jest": "^29.7.0",
36
+ "semantic-release": "19.0.3"
37
+ },
38
+ "overrides": {
39
+ "eslint-plugin-mocha": "$eslint-plugin-mocha"
35
40
  },
36
41
  "scripts": {
37
- "precommit": "npm run lint",
38
- "lint": "eslint '*.js' '**/**/*.js'",
42
+ "lint": "eslint \"*.js\" \"**/**/*.js\"",
39
43
  "lint-fix": "npm run lint -- --fix",
40
44
  "semantic-release": "semantic-release",
41
- "start": "yarn run test-watch",
45
+ "start": "npm run test-watch",
42
46
  "test": "jest",
43
- "test:v4": "npm i eslint@4.x && npm run test",
44
- "test:v6": "npm i eslint@6.x && npm run test",
45
- "test-watch": "jest --watchAll"
46
- },
47
- "jest": {
48
- "testMatch": [
49
- "**/tests/**/*.js"
50
- ]
47
+ "test-watch": "jest --watchAll",
48
+ "prepare": "husky install"
51
49
  }
52
50
  }
@@ -0,0 +1,25 @@
1
+ 'use strict'
2
+
3
+ const rule = require('../../../lib/rules/no-async-before')
4
+ const RuleTester = require('eslint').RuleTester
5
+
6
+ const ruleTester = new RuleTester()
7
+
8
+ const errors = [{ messageId: 'unexpected' }]
9
+ // async functions are an ES2017 feature
10
+ const parserOptions = { ecmaVersion: 8 }
11
+
12
+ ruleTester.run('no-async-before', rule, {
13
+ valid: [
14
+ { code: 'before(\'a before case\', () => { cy.get(\'.someClass\'); })', parserOptions },
15
+ { code: 'before(\'a before case\', async () => { await somethingAsync(); })', parserOptions },
16
+ { code: 'async function nonTestFn () { return await somethingAsync(); }', parserOptions },
17
+ { code: 'const nonTestArrowFn = async () => { await somethingAsync(); }', parserOptions },
18
+ ],
19
+ invalid: [
20
+ { code: 'before(\'a test case\', async () => { cy.get(\'.someClass\'); })', parserOptions, errors },
21
+ { code: 'beforeEach(\'a test case\', async () => { cy.get(\'.someClass\'); })', parserOptions, errors },
22
+ { code: 'before(\'a test case\', async function () { cy.get(\'.someClass\'); })', parserOptions, errors },
23
+ { code: 'beforeEach(\'a test case\', async function () { cy.get(\'.someClass\'); })', parserOptions, errors },
24
+ ],
25
+ })