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.
- package/.husky/pre-commit +4 -0
- package/.node-version +1 -0
- package/.nvmrc +1 -0
- package/CONTRIBUTING.md +16 -0
- package/README.md +43 -14
- package/circle.yml +31 -30
- package/docs/rules/no-async-before.md +52 -0
- package/lib/rules/no-async-before.js +47 -0
- package/package.json +18 -20
- package/tests/lib/rules/no-async-before.js +25 -0
package/.node-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
20.12.2
|
package/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
20.12.2
|
package/CONTRIBUTING.md
ADDED
|
@@ -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
|
-
##
|
|
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
|
-
|
|
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-
|
|
9
|
-
- test-
|
|
10
|
-
- test-v6
|
|
8
|
+
- test-v7
|
|
9
|
+
- test-v8
|
|
11
10
|
- release:
|
|
12
11
|
requires:
|
|
13
12
|
- lint
|
|
14
|
-
- test-
|
|
15
|
-
- test-
|
|
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:
|
|
23
|
+
- image: cimg/node:20.12.2
|
|
26
24
|
steps:
|
|
27
25
|
- checkout
|
|
28
26
|
- run:
|
|
29
27
|
name: Install dependencies
|
|
30
|
-
command: npm
|
|
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-
|
|
36
|
+
test-v7:
|
|
36
37
|
docker:
|
|
37
|
-
- image:
|
|
38
|
+
- image: cimg/node:20.12.2
|
|
38
39
|
steps:
|
|
39
40
|
- checkout
|
|
40
41
|
- run:
|
|
41
42
|
name: Install dependencies
|
|
42
|
-
command: npm
|
|
43
|
+
command: npm ci
|
|
43
44
|
- run:
|
|
44
|
-
name:
|
|
45
|
-
command: npm
|
|
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:
|
|
54
|
-
command:
|
|
48
|
+
name: Show ESLint version
|
|
49
|
+
command: npx eslint --version
|
|
55
50
|
- run:
|
|
56
|
-
name: Test ESLint
|
|
57
|
-
command: npm
|
|
51
|
+
name: Test ESLint 7
|
|
52
|
+
command: npm test
|
|
58
53
|
|
|
59
|
-
test-
|
|
54
|
+
test-v8:
|
|
60
55
|
docker:
|
|
61
|
-
- image:
|
|
56
|
+
- image: cimg/node:20.12.2
|
|
62
57
|
steps:
|
|
63
58
|
- checkout
|
|
64
59
|
- run:
|
|
65
60
|
name: Install dependencies
|
|
66
|
-
command: npm
|
|
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
|
|
69
|
-
command: npm
|
|
69
|
+
name: Test ESLint 8
|
|
70
|
+
command: npm test
|
|
70
71
|
|
|
71
72
|
release:
|
|
72
73
|
docker:
|
|
73
|
-
- image:
|
|
74
|
+
- image: cimg/node:20.12.2
|
|
74
75
|
steps:
|
|
75
76
|
- checkout
|
|
76
77
|
- run:
|
|
77
78
|
name: Install dependencies
|
|
78
|
-
command: npm
|
|
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": "
|
|
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": ">=
|
|
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.
|
|
29
|
-
"@cypress/eslint-plugin-json": "3.2.
|
|
30
|
-
"
|
|
31
|
-
"eslint": "^
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
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
|
-
"
|
|
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": "
|
|
45
|
+
"start": "npm run test-watch",
|
|
42
46
|
"test": "jest",
|
|
43
|
-
"test
|
|
44
|
-
"
|
|
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
|
+
})
|