eslint-plugin-cypress 3.1.1 → 3.3.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/CONTRIBUTING.md +45 -11
- package/FLAT-CONFIG.md +146 -0
- package/README.md +5 -2
- package/circle.yml +21 -1
- package/eslint.config.mjs +29 -0
- package/jest.config-legacy.js +6 -0
- package/lib/flat.js +66 -0
- package/package.json +13 -6
- package/tests/config.js +6 -6
- package/tests/lib/rules/assertion-before-screenshot.js +18 -19
- package/tests/lib/rules/no-assigning-return-values.js +19 -20
- package/tests/lib/rules/no-async-before.js +8 -10
- package/tests/lib/rules/no-async-tests.js +8 -10
- package/tests/lib/rules/no-force.js +24 -34
- package/tests/lib/rules/no-pause.js +9 -23
- package/tests/lib/rules/no-unnecessary-waiting.js +31 -55
- package/tests/lib/rules/require-data-selectors.js +14 -15
- package/tests/lib/rules/unsafe-to-chain-command.js +8 -30
- package/tests-legacy/config.js +26 -0
- package/tests-legacy/lib/rules/assertion-before-screenshot.js +35 -0
- package/tests-legacy/lib/rules/no-assigning-return-values.js +38 -0
- package/tests-legacy/lib/rules/no-async-before.js +25 -0
- package/tests-legacy/lib/rules/no-async-tests.js +25 -0
- package/tests-legacy/lib/rules/no-force.js +49 -0
- package/tests-legacy/lib/rules/no-pause.js +37 -0
- package/tests-legacy/lib/rules/no-unnecessary-waiting.js +71 -0
- package/tests-legacy/lib/rules/require-data-selectors.js +31 -0
- package/tests-legacy/lib/rules/unsafe-to-chain-command.js +56 -0
- package/.eslintrc.js +0 -30
- /package/{index.js → legacy.js} +0 -0
package/CONTRIBUTING.md
CHANGED
|
@@ -2,15 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
Thanks for taking the time to contribute! :smile:
|
|
4
4
|
|
|
5
|
+
## Preparation
|
|
6
|
+
|
|
7
|
+
* Fork and clone this repository
|
|
8
|
+
* Branch from the default `master` branch using a descriptive new branch name
|
|
9
|
+
* Install dependencies with `npm ci`
|
|
10
|
+
|
|
11
|
+
## Rule references
|
|
12
|
+
|
|
13
|
+
* Refer to the [ESLint documentation](https://eslint.org/docs/latest/) and the [Custom Rules](https://eslint.org/docs/latest/extend/custom-rules) page
|
|
14
|
+
|
|
15
|
+
## New rule
|
|
16
|
+
|
|
5
17
|
To add a new rule:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
|
|
19
|
+
* Follow the instructions in the ESLint [generator-eslint](https://www.npmjs.com/package/generator-eslint) documentation to install [Yeoman](https://www.npmjs.com/package/yo) and the generator
|
|
20
|
+
* Run the new rule generator `yo eslint:rule` and answer the questions
|
|
21
|
+
- select "ESLint Plugin"
|
|
22
|
+
- for "Type a short description of this rule" provide text which starts with one of "enforce", "require" or "disallow" (all lower case)
|
|
23
|
+
* Yeoman creates three boilerplate files:
|
|
24
|
+
- `docs/rules/<rule-id>.md`
|
|
25
|
+
- `lib/rules/<rule-id>.js`
|
|
26
|
+
- `test/rules/<rule-id>.js`
|
|
27
|
+
* Run `npm run lint-fix`
|
|
28
|
+
* Address the linting errors by editing `lib/rules/<rule-id>.js`
|
|
29
|
+
- Add a `meta.messages` property (see [MessageIds](https://eslint.org/docs/latest/extend/custom-rules#messageids))
|
|
30
|
+
- Select the appropriate `meta.type` property using `problem`, `suggestion`, or `layout`
|
|
31
|
+
* Complete the new rule by adding content to the three files previously created
|
|
32
|
+
* Run `eslint-doc-generator` to generate automated documentation sections (see [Document generation](#document-generation) below)
|
|
33
|
+
* Review documentation changes
|
|
34
|
+
* Run `npm run lint`
|
|
35
|
+
* Run `npm test` to run [Jest](https://jestjs.io/) (or 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)
|
|
36
|
+
* Make sure all tests are passing
|
|
37
|
+
* Add the rule to [legacy.js](https://github.com/cypress-io/eslint-plugin-cypress/blob/master/legacy.js) and to [flat.js](https://github.com/cypress-io/eslint-plugin-cypress/blob/master/lib/flat.js)
|
|
38
|
+
* Create a git commit with a commit message similar to: `feat: add rule <description>` (see [commit message conventions](https://github.com/semantic-release/semantic-release#commit-message-format))
|
|
39
|
+
* Create a PR from your branch
|
|
40
|
+
|
|
41
|
+
## Document generation
|
|
42
|
+
|
|
43
|
+
This plugin uses the ESLint [eslint-doc-generator](https://www.npmjs.com/package/eslint-doc-generator) to generate consistent documentation.
|
|
44
|
+
* Install with `npm install eslint-doc-generator -g`
|
|
45
|
+
* Run `eslint-doc-generator` in the root directory of the plugin
|
|
46
|
+
|
|
47
|
+
## Legacy tests
|
|
48
|
+
|
|
49
|
+
* The directory [tests-legacy](https://github.com/cypress-io/eslint-plugin-cypress/tree/master/tests-legacy) contains tests which are compatible with the legacy [ESLint v8 RuleTester](https://eslint.org/docs/v8.x/integrate/nodejs-api#ruletester) utility. It is not expected to add new rules to this set of tests.
|
|
50
|
+
* The directory [tests](https://github.com/cypress-io/eslint-plugin-cypress/tree/master/tests) is for tests compatible with the current [ESLint RuleTester](https://eslint.org/docs/latest/integrate/nodejs-api#ruletester).
|
package/FLAT-CONFIG.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Cypress ESLint Plugin - Flat Config
|
|
2
|
+
|
|
3
|
+
This document supplements the [README](README.md) document and describes how to use the Cypress ESLint Plugin (`eslint-plugin-cypress`) in an ESLint flat config environment.
|
|
4
|
+
|
|
5
|
+
Usage with ESLint `8.57.0` and ESLint `9.x` is described.
|
|
6
|
+
|
|
7
|
+
## Introduction
|
|
8
|
+
|
|
9
|
+
[ESLint v9.0.0](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/) was released on April 5, 2024, establishing flat config as the default for this version.
|
|
10
|
+
|
|
11
|
+
Previously, ESLint had announced in their blog post [Flat config rollout plans](https://eslint.org/blog/2023/10/flat-config-rollout-plans/) in October 2023 that flat config was planned to be the default in ESLint `v9.0.0` and that the eslintrc configuration system is planned to be removed in the future ESLint `v10.0.0`.
|
|
12
|
+
|
|
13
|
+
Cypress ESLint Plugin (`eslint-plugin-cypress`) in release [3.2.0](https://github.com/cypress-io/eslint-plugin-cypress/releases/tag/v3.2.0) offered the first support of ESLint `9.x` flat config files using the [Backwards compatibility utility](https://eslint.org/blog/2022/08/new-config-system-part-2/#backwards-compatibility-utility). Current releases have removed the dependency on this utility and the examples in this document have been updated correspondingly.
|
|
14
|
+
|
|
15
|
+
The following information details installation and usage examples for `eslint-plugin-cypress` together with related plugins in an ESLint flat config environment.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
It is recommended to use a minimum ESLint `8.x` version [eslint@8.57.0](https://github.com/eslint/eslint/releases/tag/v8.57.0) or ESLint `9.x`.
|
|
20
|
+
|
|
21
|
+
```shell
|
|
22
|
+
npm install eslint eslint-plugin-cypress --save-dev
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
or
|
|
26
|
+
|
|
27
|
+
```shell
|
|
28
|
+
yarn add eslint eslint-plugin-cypress --dev
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage examples
|
|
32
|
+
|
|
33
|
+
Add a flat configuration file `eslint.config.mjs` to the root directory of your Cypress project and include the following instructions to import the available flat configurations using:
|
|
34
|
+
|
|
35
|
+
```shell
|
|
36
|
+
import pluginCypress from 'eslint-plugin-cypress/flat'
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
There are two specific flat configurations available:
|
|
40
|
+
|
|
41
|
+
| Configuration | Content |
|
|
42
|
+
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
43
|
+
| `configs.globals` | defines globals `cy`, `Cypress`, `expect`, `assert` and `chai` used in Cypress test specs as well as `globals.browser` and `globals.mocha` from [globals](https://www.npmjs.com/package/globals). Additionally, `languageOptions` of `ecmaVersion: 2019` and `sourceType: 'module'` for backwards compatibility with earlier versions of this plugin are defined. There are no default rules enabled in this configuration. |
|
|
44
|
+
| `configs.recommended` | enables [recommended Rules](README.md#rules). It includes also `configs.global` (see above) |
|
|
45
|
+
|
|
46
|
+
In the following sections, different examples of possible configuration file contents are given, together with some brief explanations. Adapt these examples according to your needs.
|
|
47
|
+
|
|
48
|
+
### Cypress
|
|
49
|
+
|
|
50
|
+
All rules from `eslint-plugin-cypress` are available through `eslint-plugin-cypress/flat`.
|
|
51
|
+
- [cypress/unsafe-to-chain-command](https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/unsafe-to-chain-command.md) is active and set to `error`
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
import pluginCypress from 'eslint-plugin-cypress/flat'
|
|
55
|
+
export default [
|
|
56
|
+
{
|
|
57
|
+
plugins: {
|
|
58
|
+
cypress: pluginCypress
|
|
59
|
+
},
|
|
60
|
+
rules: {
|
|
61
|
+
'cypress/unsafe-to-chain-command': 'error'
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Cypress recommended
|
|
68
|
+
|
|
69
|
+
The `eslint-plugin-cypress` [recommended rules](README.md#rules) `configs.recommended` are activated, except for
|
|
70
|
+
- [cypress/no-unnecessary-waiting](https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/no-unnecessary-waiting.md) set to `off`
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
import pluginCypress from 'eslint-plugin-cypress/flat'
|
|
74
|
+
export default [
|
|
75
|
+
pluginCypress.configs.recommended,
|
|
76
|
+
{
|
|
77
|
+
rules: {
|
|
78
|
+
'cypress/no-unnecessary-waiting': 'off'
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Cypress globals
|
|
85
|
+
|
|
86
|
+
The `configs.globals` are activated.
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
import pluginCypress from 'eslint-plugin-cypress/flat'
|
|
90
|
+
export default [
|
|
91
|
+
pluginCypress.configs.globals
|
|
92
|
+
]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Cypress and Mocha recommended
|
|
96
|
+
|
|
97
|
+
[eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) is added to the example [Cypress recommended](#cypress-recommended). This plugin offers a flat file recommended option `configs.flat.recommended`.
|
|
98
|
+
|
|
99
|
+
The settings for individual `mocha` rules from the `configs.flat.recommended` option are changed.
|
|
100
|
+
- [mocha/no-exclusive-tests](https://github.com/lo1tuma/eslint-plugin-mocha/blob/main/docs/rules/no-exclusive-tests.md) and [mocha/no-skipped-tests](https://github.com/lo1tuma/eslint-plugin-mocha/blob/main/docs/rules/no-skipped-tests.md) are set to `error` instead of `warn`
|
|
101
|
+
- [mocha/no-mocha-arrows](https://github.com/lo1tuma/eslint-plugin-mocha/blob/main/docs/rules/no-mocha-arrows.md) is set to `off` instead of `error`
|
|
102
|
+
|
|
103
|
+
```shell
|
|
104
|
+
npm install eslint-plugin-mocha@^10.4.3 --save-dev
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
import pluginMocha from 'eslint-plugin-mocha'
|
|
109
|
+
import pluginCypress from 'eslint-plugin-cypress/flat'
|
|
110
|
+
export default [
|
|
111
|
+
pluginMocha.configs.flat.recommended,
|
|
112
|
+
pluginCypress.configs.recommended,
|
|
113
|
+
{
|
|
114
|
+
rules: {
|
|
115
|
+
'mocha/no-exclusive-tests': 'warn',
|
|
116
|
+
'mocha/no-skipped-tests': 'warn',
|
|
117
|
+
'mocha/no-mocha-arrows': 'off',
|
|
118
|
+
'cypress/no-unnecessary-waiting': 'off'
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Cypress and Chai recommended
|
|
125
|
+
|
|
126
|
+
[eslint-plugin-chai-friendly](https://www.npmjs.com/package/eslint-plugin-chai-friendly) (minimum version [eslint-plugin-chai-friendly@0.8.0](https://github.com/ihordiachenko/eslint-plugin-chai-friendly/releases/tag/v0.8.0) required for ESLint v9 support and flat config support) is combined with the Cypress plugin `eslint-plugin-cypress`.
|
|
127
|
+
|
|
128
|
+
The recommended rules for both plugins are used: `pluginCypress.configs.recommended` and `pluginChaiFriendly.configs.recommended`:
|
|
129
|
+
|
|
130
|
+
```shell
|
|
131
|
+
npm install eslint-plugin-chai-friendly@^0.8.0 --save-dev
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
import pluginCypress from 'eslint-plugin-cypress/flat'
|
|
136
|
+
import pluginChaiFriendly from 'eslint-plugin-chai-friendly'
|
|
137
|
+
export default [
|
|
138
|
+
pluginCypress.configs.recommended,
|
|
139
|
+
pluginChaiFriendly.configs.recommended,
|
|
140
|
+
{
|
|
141
|
+
rules: {
|
|
142
|
+
'cypress/no-unnecessary-waiting': 'off',
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
```
|
package/README.md
CHANGED
|
@@ -6,7 +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
|
|
9
|
+
Prerequisites: [ESLint](https://www.npmjs.com/package/eslint) `v7`, `v8` or `v9`.
|
|
10
|
+
This plugin supports the use of [Flat config files](https://eslint.org/docs/latest/use/configure/configuration-files) with ESLint `8.57.0` and above.
|
|
10
11
|
|
|
11
12
|
```sh
|
|
12
13
|
npm install eslint-plugin-cypress --save-dev
|
|
@@ -18,7 +19,9 @@ yarn add eslint-plugin-cypress --dev
|
|
|
18
19
|
|
|
19
20
|
## Usage
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
If you are using ESLint `v7` or `v8`, then add an `.eslintrc.json` file to the root directory of your Cypress project with the contents shown below. You can continue to use this format with ESLint `v9` if you set the `ESLINT_USE_FLAT_CONFIG` environment variable to `false` (see [ESLint v9 > Configuration Files (Deprecated)](https://eslint.org/docs/latest/use/configure/configuration-files-deprecated).
|
|
23
|
+
|
|
24
|
+
ESLint `v9` uses a [Flat config file](https://eslint.org/docs/latest/use/configure/configuration-files) format with filename `eslint.config.*js` by default. Please refer to [additional Flat config installation and configuration details](FLAT-CONFIG.md). (You may also use this with ESLint `8.57.0`.)
|
|
22
25
|
|
|
23
26
|
```json
|
|
24
27
|
{
|
package/circle.yml
CHANGED
|
@@ -7,11 +7,13 @@ workflows:
|
|
|
7
7
|
- lint
|
|
8
8
|
- test-v7
|
|
9
9
|
- test-v8
|
|
10
|
+
- test-v9
|
|
10
11
|
- release:
|
|
11
12
|
requires:
|
|
12
13
|
- lint
|
|
13
14
|
- test-v7
|
|
14
15
|
- test-v8
|
|
16
|
+
- test-v9
|
|
15
17
|
filters:
|
|
16
18
|
branches:
|
|
17
19
|
only:
|
|
@@ -52,7 +54,7 @@ jobs:
|
|
|
52
54
|
command: npx eslint --version
|
|
53
55
|
- run:
|
|
54
56
|
name: Test ESLint 7
|
|
55
|
-
command: npm test
|
|
57
|
+
command: npm run test:legacy
|
|
56
58
|
|
|
57
59
|
test-v8:
|
|
58
60
|
docker:
|
|
@@ -70,6 +72,24 @@ jobs:
|
|
|
70
72
|
command: npx eslint --version
|
|
71
73
|
- run:
|
|
72
74
|
name: Test ESLint 8
|
|
75
|
+
command: npm run test:legacy
|
|
76
|
+
|
|
77
|
+
test-v9:
|
|
78
|
+
docker:
|
|
79
|
+
- image: cimg/node:20.12.2
|
|
80
|
+
steps:
|
|
81
|
+
- checkout
|
|
82
|
+
- run:
|
|
83
|
+
name: Install dependencies
|
|
84
|
+
command: npm ci
|
|
85
|
+
- run:
|
|
86
|
+
name: Install ESLint 9
|
|
87
|
+
command: npm install eslint@9
|
|
88
|
+
- run:
|
|
89
|
+
name: Show ESLint version
|
|
90
|
+
command: npx eslint --version
|
|
91
|
+
- run:
|
|
92
|
+
name: Test ESLint 9
|
|
73
93
|
command: npm test
|
|
74
94
|
|
|
75
95
|
release:
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import globals from 'globals'
|
|
2
|
+
import pluginJs from '@eslint/js'
|
|
3
|
+
import eslintPlugin from 'eslint-plugin-eslint-plugin'
|
|
4
|
+
import nodePlugin from 'eslint-plugin-n'
|
|
5
|
+
import mochaPlugin from 'eslint-plugin-mocha'
|
|
6
|
+
|
|
7
|
+
export default [
|
|
8
|
+
pluginJs.configs.recommended,
|
|
9
|
+
eslintPlugin.configs['flat/recommended'],
|
|
10
|
+
nodePlugin.configs['flat/recommended-script'],
|
|
11
|
+
mochaPlugin.configs.flat.recommended,
|
|
12
|
+
{
|
|
13
|
+
languageOptions: {
|
|
14
|
+
globals: globals.node
|
|
15
|
+
},
|
|
16
|
+
rules: {
|
|
17
|
+
'no-redeclare': 'off',
|
|
18
|
+
'eslint-plugin/require-meta-docs-url':
|
|
19
|
+
['error', { 'pattern': 'https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/{{name}}.md' }],
|
|
20
|
+
'eslint-plugin/require-meta-docs-description': 'error',
|
|
21
|
+
'eslint-plugin/meta-property-ordering': 'error',
|
|
22
|
+
'eslint-plugin/test-case-property-ordering': 'error',
|
|
23
|
+
'n/no-extraneous-require':
|
|
24
|
+
['error', { 'allowModules': ['jest-config'] }],
|
|
25
|
+
'mocha/no-mocha-arrows': 'off',
|
|
26
|
+
'mocha/no-setup-in-describe': 'off'
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
]
|
package/lib/flat.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const globals = require('globals')
|
|
2
|
+
const { name, version } = require('../package.json')
|
|
3
|
+
|
|
4
|
+
const plugin = {
|
|
5
|
+
meta: { name, version },
|
|
6
|
+
configs: {},
|
|
7
|
+
rules: {
|
|
8
|
+
'no-assigning-return-values': require('./rules/no-assigning-return-values'),
|
|
9
|
+
'unsafe-to-chain-command': require('./rules/unsafe-to-chain-command'),
|
|
10
|
+
'no-unnecessary-waiting': require('./rules/no-unnecessary-waiting'),
|
|
11
|
+
'no-async-before': require('./rules/no-async-before'),
|
|
12
|
+
'no-async-tests': require('./rules/no-async-tests'),
|
|
13
|
+
'assertion-before-screenshot': require('./rules/assertion-before-screenshot'),
|
|
14
|
+
'require-data-selectors': require('./rules/require-data-selectors'),
|
|
15
|
+
'no-force': require('./rules/no-force'),
|
|
16
|
+
'no-pause': require('./rules/no-pause'),
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const commonGlobals =
|
|
21
|
+
Object.assign({
|
|
22
|
+
cy: false,
|
|
23
|
+
Cypress: false,
|
|
24
|
+
expect: false,
|
|
25
|
+
assert: false,
|
|
26
|
+
chai: false,
|
|
27
|
+
}, globals.browser, globals.mocha)
|
|
28
|
+
|
|
29
|
+
const commonLanguageOptions = {
|
|
30
|
+
ecmaVersion: 2019,
|
|
31
|
+
sourceType: 'module'
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Object.assign(plugin.configs, {
|
|
35
|
+
globals: {
|
|
36
|
+
plugins: {
|
|
37
|
+
cypress: plugin
|
|
38
|
+
},
|
|
39
|
+
languageOptions: {
|
|
40
|
+
globals:
|
|
41
|
+
commonGlobals,
|
|
42
|
+
...commonLanguageOptions
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
Object.assign(plugin.configs, {
|
|
48
|
+
recommended: {
|
|
49
|
+
plugins: {
|
|
50
|
+
cypress: plugin
|
|
51
|
+
},
|
|
52
|
+
rules: {
|
|
53
|
+
'cypress/no-assigning-return-values': 'error',
|
|
54
|
+
'cypress/no-unnecessary-waiting': 'error',
|
|
55
|
+
'cypress/no-async-tests': 'error',
|
|
56
|
+
'cypress/unsafe-to-chain-command': 'error',
|
|
57
|
+
},
|
|
58
|
+
languageOptions: {
|
|
59
|
+
globals:
|
|
60
|
+
commonGlobals,
|
|
61
|
+
...commonLanguageOptions
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
module.exports = plugin
|
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-cypress",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "An ESLint plugin for projects using Cypress",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "legacy.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./legacy.js",
|
|
8
|
+
"./flat": "./lib/flat.js"
|
|
9
|
+
},
|
|
6
10
|
"author": "Cypress-io",
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"keywords": [
|
|
@@ -19,16 +23,18 @@
|
|
|
19
23
|
},
|
|
20
24
|
"homepage": "https://github.com/cypress-io/eslint-plugin-cypress#readme",
|
|
21
25
|
"peerDependencies": {
|
|
22
|
-
"eslint": ">=7
|
|
26
|
+
"eslint": ">=7"
|
|
23
27
|
},
|
|
24
28
|
"dependencies": {
|
|
25
29
|
"globals": "^13.20.0"
|
|
26
30
|
},
|
|
27
31
|
"devDependencies": {
|
|
28
|
-
"eslint": "^
|
|
29
|
-
"eslint
|
|
32
|
+
"@eslint/eslintrc": "^3.1.0",
|
|
33
|
+
"@eslint/js": "^9.3.0",
|
|
34
|
+
"eslint": "^9.3.0",
|
|
35
|
+
"eslint-plugin-eslint-plugin": "^6.1.0",
|
|
30
36
|
"eslint-plugin-mocha": "^10.4.3",
|
|
31
|
-
"eslint-plugin-n": "^17.
|
|
37
|
+
"eslint-plugin-n": "^17.7.0",
|
|
32
38
|
"husky": "^9.0.11",
|
|
33
39
|
"jest": "^29.7.0",
|
|
34
40
|
"semantic-release": "23.0.8"
|
|
@@ -39,6 +45,7 @@
|
|
|
39
45
|
"semantic-release": "semantic-release",
|
|
40
46
|
"start": "npm run test-watch",
|
|
41
47
|
"test": "jest",
|
|
48
|
+
"test:legacy": "jest --config jest.config-legacy.js",
|
|
42
49
|
"test-watch": "jest --watchAll",
|
|
43
50
|
"prepare": "husky"
|
|
44
51
|
}
|
package/tests/config.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
4
|
const globals = require('globals')
|
|
5
|
-
const config = require('../
|
|
5
|
+
const config = require('../lib/flat.js')
|
|
6
6
|
|
|
7
|
-
describe('
|
|
8
|
-
const
|
|
7
|
+
describe('globals languageOptions', () => {
|
|
8
|
+
const languageOptions = config.configs.globals.languageOptions
|
|
9
9
|
|
|
10
10
|
it('should not mutate globals', () => {
|
|
11
11
|
expect(globals.browser).not.toHaveProperty('cy')
|
|
@@ -13,12 +13,12 @@ describe('environments globals', () => {
|
|
|
13
13
|
})
|
|
14
14
|
|
|
15
15
|
it('should include other globals', () => {
|
|
16
|
-
expect(
|
|
17
|
-
expect(
|
|
16
|
+
expect(languageOptions.globals).toEqual(expect.objectContaining(globals.browser))
|
|
17
|
+
expect(languageOptions.globals).toEqual(expect.objectContaining(globals.mocha))
|
|
18
18
|
})
|
|
19
19
|
|
|
20
20
|
it('should include cypress globals', () => {
|
|
21
|
-
expect(
|
|
21
|
+
expect(languageOptions.globals).toEqual(expect.objectContaining({
|
|
22
22
|
cy: false,
|
|
23
23
|
Cypress: false,
|
|
24
24
|
}))
|
|
@@ -6,30 +6,29 @@ const RuleTester = require('eslint').RuleTester
|
|
|
6
6
|
const ruleTester = new RuleTester()
|
|
7
7
|
|
|
8
8
|
const errors = [{ messageId: 'unexpected' }]
|
|
9
|
-
const parserOptions = { ecmaVersion: 6 }
|
|
10
9
|
|
|
11
10
|
ruleTester.run('assertion-before-screenshot', rule, {
|
|
12
11
|
valid: [
|
|
13
|
-
{ code: 'cy.get(".some-element"); cy.screenshot();'
|
|
14
|
-
{ code: 'cy.get(".some-element").should("exist").screenshot();'
|
|
15
|
-
{ code: 'cy.get(".some-element").should("exist").screenshot().click()'
|
|
16
|
-
{ code: 'cy.get(".some-element").should("exist"); if(true) cy.screenshot();'
|
|
17
|
-
{ code: 'if(true) { cy.get(".some-element").should("exist"); cy.screenshot(); }'
|
|
18
|
-
{ code: 'cy.get(".some-element").should("exist"); if(true) { cy.screenshot(); }'
|
|
19
|
-
{ code: 'const a = () => { cy.get(".some-element").should("exist"); cy.screenshot(); }'
|
|
20
|
-
{ code: 'cy.get(".some-element").should("exist").and("be.visible"); cy.screenshot();'
|
|
21
|
-
{ code: 'cy.get(".some-element").contains("Text"); cy.screenshot();'
|
|
12
|
+
{ code: 'cy.get(".some-element"); cy.screenshot();' },
|
|
13
|
+
{ code: 'cy.get(".some-element").should("exist").screenshot();' },
|
|
14
|
+
{ code: 'cy.get(".some-element").should("exist").screenshot().click()' },
|
|
15
|
+
{ code: 'cy.get(".some-element").should("exist"); if(true) cy.screenshot();' },
|
|
16
|
+
{ code: 'if(true) { cy.get(".some-element").should("exist"); cy.screenshot(); }' },
|
|
17
|
+
{ code: 'cy.get(".some-element").should("exist"); if(true) { cy.screenshot(); }' },
|
|
18
|
+
{ code: 'const a = () => { cy.get(".some-element").should("exist"); cy.screenshot(); }' },
|
|
19
|
+
{ code: 'cy.get(".some-element").should("exist").and("be.visible"); cy.screenshot();' },
|
|
20
|
+
{ code: 'cy.get(".some-element").contains("Text"); cy.screenshot();' },
|
|
22
21
|
],
|
|
23
22
|
|
|
24
23
|
invalid: [
|
|
25
|
-
{ code: 'cy.screenshot()',
|
|
26
|
-
{ code: 'cy.visit("somepage"); cy.screenshot();',
|
|
27
|
-
{ code: 'cy.custom(); cy.screenshot()',
|
|
28
|
-
{ code: 'cy.get(".some-element").click(); cy.screenshot()',
|
|
29
|
-
{ code: 'cy.get(".some-element").click().screenshot()',
|
|
30
|
-
{ code: 'if(true) { cy.get(".some-element").click(); cy.screenshot(); }',
|
|
31
|
-
{ code: 'cy.get(".some-element").click(); if(true) { cy.screenshot(); }',
|
|
32
|
-
{ code: 'cy.get(".some-element"); function a() { cy.screenshot(); }',
|
|
33
|
-
{ code: 'cy.get(".some-element"); const a = () => { cy.screenshot(); }',
|
|
24
|
+
{ code: 'cy.screenshot()', errors },
|
|
25
|
+
{ code: 'cy.visit("somepage"); cy.screenshot();', errors },
|
|
26
|
+
{ code: 'cy.custom(); cy.screenshot()', errors },
|
|
27
|
+
{ code: 'cy.get(".some-element").click(); cy.screenshot()', errors },
|
|
28
|
+
{ code: 'cy.get(".some-element").click().screenshot()', errors },
|
|
29
|
+
{ code: 'if(true) { cy.get(".some-element").click(); cy.screenshot(); }', errors },
|
|
30
|
+
{ code: 'cy.get(".some-element").click(); if(true) { cy.screenshot(); }', errors },
|
|
31
|
+
{ code: 'cy.get(".some-element"); function a() { cy.screenshot(); }', errors },
|
|
32
|
+
{ code: 'cy.get(".some-element"); const a = () => { cy.screenshot(); }', errors },
|
|
34
33
|
],
|
|
35
34
|
})
|
|
@@ -6,33 +6,32 @@ const RuleTester = require('eslint').RuleTester
|
|
|
6
6
|
const ruleTester = new RuleTester()
|
|
7
7
|
|
|
8
8
|
const errors = [{ messageId: 'unexpected' }]
|
|
9
|
-
const parserOptions = { ecmaVersion: 6 }
|
|
10
9
|
|
|
11
10
|
ruleTester.run('no-assigning-return-values', rule, {
|
|
12
11
|
valid: [
|
|
13
|
-
{ code: 'var foo = true;'
|
|
14
|
-
{ code: 'let foo = true;'
|
|
15
|
-
{ code: 'const foo = true;'
|
|
16
|
-
{ code: 'const foo = bar();'
|
|
17
|
-
{ code: 'const foo = bar().baz();'
|
|
18
|
-
{ code: 'const spy = cy.spy();'
|
|
19
|
-
{ code: 'const spy = cy.spy().as();'
|
|
20
|
-
{ code: 'const stub = cy.stub();'
|
|
21
|
-
{ code: 'const result = cy.now();'
|
|
22
|
-
{ code: 'const state = cy.state();'
|
|
23
|
-
{ code: 'cy.get("foo");'
|
|
24
|
-
{ code: 'cy.contains("foo").click();'
|
|
12
|
+
{ code: 'var foo = true;' },
|
|
13
|
+
{ code: 'let foo = true;' },
|
|
14
|
+
{ code: 'const foo = true;' },
|
|
15
|
+
{ code: 'const foo = bar();' },
|
|
16
|
+
{ code: 'const foo = bar().baz();' },
|
|
17
|
+
{ code: 'const spy = cy.spy();' },
|
|
18
|
+
{ code: 'const spy = cy.spy().as();' },
|
|
19
|
+
{ code: 'const stub = cy.stub();' },
|
|
20
|
+
{ code: 'const result = cy.now();' },
|
|
21
|
+
{ code: 'const state = cy.state();' },
|
|
22
|
+
{ code: 'cy.get("foo");' },
|
|
23
|
+
{ code: 'cy.contains("foo").click();' },
|
|
25
24
|
],
|
|
26
25
|
|
|
27
26
|
invalid: [
|
|
28
|
-
{ code: 'let a = cy.get("foo")',
|
|
29
|
-
{ code: 'const a = cy.get("foo")',
|
|
30
|
-
{ code: 'var a = cy.get("foo")',
|
|
27
|
+
{ code: 'let a = cy.get("foo")', errors },
|
|
28
|
+
{ code: 'const a = cy.get("foo")', errors },
|
|
29
|
+
{ code: 'var a = cy.get("foo")', errors },
|
|
31
30
|
|
|
32
|
-
{ code: 'let a = cy.contains("foo")',
|
|
33
|
-
{ code: 'let a = cy.window()',
|
|
34
|
-
{ code: 'let a = cy.wait("@something")',
|
|
31
|
+
{ code: 'let a = cy.contains("foo")', errors },
|
|
32
|
+
{ code: 'let a = cy.window()', errors },
|
|
33
|
+
{ code: 'let a = cy.wait("@something")', errors },
|
|
35
34
|
|
|
36
|
-
{ code: 'let a = cy.contains("foo").click()',
|
|
35
|
+
{ code: 'let a = cy.contains("foo").click()', errors },
|
|
37
36
|
],
|
|
38
37
|
})
|
|
@@ -6,20 +6,18 @@ const RuleTester = require('eslint').RuleTester
|
|
|
6
6
|
const ruleTester = new RuleTester()
|
|
7
7
|
|
|
8
8
|
const errors = [{ messageId: 'unexpected' }]
|
|
9
|
-
// async functions are an ES2017 feature
|
|
10
|
-
const parserOptions = { ecmaVersion: 8 }
|
|
11
9
|
|
|
12
10
|
ruleTester.run('no-async-before', rule, {
|
|
13
11
|
valid: [
|
|
14
|
-
{ code: 'before(\'a before case\', () => { cy.get(\'.someClass\'); })'
|
|
15
|
-
{ code: 'before(\'a before case\', async () => { await somethingAsync(); })'
|
|
16
|
-
{ code: 'async function nonTestFn () { return await somethingAsync(); }'
|
|
17
|
-
{ code: 'const nonTestArrowFn = async () => { await somethingAsync(); }'
|
|
12
|
+
{ code: 'before(\'a before case\', () => { cy.get(\'.someClass\'); })' },
|
|
13
|
+
{ code: 'before(\'a before case\', async () => { await somethingAsync(); })' },
|
|
14
|
+
{ code: 'async function nonTestFn () { return await somethingAsync(); }' },
|
|
15
|
+
{ code: 'const nonTestArrowFn = async () => { await somethingAsync(); }' },
|
|
18
16
|
],
|
|
19
17
|
invalid: [
|
|
20
|
-
{ code: 'before(\'a test case\', async () => { cy.get(\'.someClass\'); })',
|
|
21
|
-
{ code: 'beforeEach(\'a test case\', async () => { cy.get(\'.someClass\'); })',
|
|
22
|
-
{ code: 'before(\'a test case\', async function () { cy.get(\'.someClass\'); })',
|
|
23
|
-
{ code: 'beforeEach(\'a test case\', async function () { cy.get(\'.someClass\'); })',
|
|
18
|
+
{ code: 'before(\'a test case\', async () => { cy.get(\'.someClass\'); })', errors },
|
|
19
|
+
{ code: 'beforeEach(\'a test case\', async () => { cy.get(\'.someClass\'); })', errors },
|
|
20
|
+
{ code: 'before(\'a test case\', async function () { cy.get(\'.someClass\'); })', errors },
|
|
21
|
+
{ code: 'beforeEach(\'a test case\', async function () { cy.get(\'.someClass\'); })', errors },
|
|
24
22
|
],
|
|
25
23
|
})
|
|
@@ -6,20 +6,18 @@ const RuleTester = require('eslint').RuleTester
|
|
|
6
6
|
const ruleTester = new RuleTester()
|
|
7
7
|
|
|
8
8
|
const errors = [{ messageId: 'unexpected' }]
|
|
9
|
-
// async functions are an ES2017 feature
|
|
10
|
-
const parserOptions = { ecmaVersion: 8 }
|
|
11
9
|
|
|
12
10
|
ruleTester.run('no-async-tests', rule, {
|
|
13
11
|
valid: [
|
|
14
|
-
{ code: 'it(\'a test case\', () => { cy.get(\'.someClass\'); })'
|
|
15
|
-
{ code: 'it(\'a test case\', async () => { await somethingAsync(); })'
|
|
16
|
-
{ code: 'async function nonTestFn () { return await somethingAsync(); }'
|
|
17
|
-
{ code: 'const nonTestArrowFn = async () => { await somethingAsync(); }'
|
|
12
|
+
{ code: 'it(\'a test case\', () => { cy.get(\'.someClass\'); })' },
|
|
13
|
+
{ code: 'it(\'a test case\', async () => { await somethingAsync(); })' },
|
|
14
|
+
{ code: 'async function nonTestFn () { return await somethingAsync(); }' },
|
|
15
|
+
{ code: 'const nonTestArrowFn = async () => { await somethingAsync(); }' },
|
|
18
16
|
],
|
|
19
17
|
invalid: [
|
|
20
|
-
{ code: 'it(\'a test case\', async () => { cy.get(\'.someClass\'); })',
|
|
21
|
-
{ code: 'test(\'a test case\', async () => { cy.get(\'.someClass\'); })',
|
|
22
|
-
{ code: 'it(\'a test case\', async function () { cy.get(\'.someClass\'); })',
|
|
23
|
-
{ code: 'test(\'a test case\', async function () { cy.get(\'.someClass\'); })',
|
|
18
|
+
{ code: 'it(\'a test case\', async () => { cy.get(\'.someClass\'); })', errors },
|
|
19
|
+
{ code: 'test(\'a test case\', async () => { cy.get(\'.someClass\'); })', errors },
|
|
20
|
+
{ code: 'it(\'a test case\', async function () { cy.get(\'.someClass\'); })', errors },
|
|
21
|
+
{ code: 'test(\'a test case\', async function () { cy.get(\'.someClass\'); })', errors },
|
|
24
22
|
],
|
|
25
23
|
})
|