Skip to content

Commit 0e835e9

Browse files
Merge pull request #212 from MikeMcC399/add/flat-config
feat: add flat configurations
2 parents 55fa0dd + 0e434c7 commit 0e835e9

File tree

8 files changed

+149
-67
lines changed

8 files changed

+149
-67
lines changed

CONTRIBUTING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ To add a new rule:
3434
* Run `npm run lint`
3535
* 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)
3636
* Make sure all tests are passing
37-
* Add the rule to [index.js](https://github.com/cypress-io/eslint-plugin-cypress/blob/master/index.js)
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)
3838
* 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))
3939
* Create a PR from your branch
4040

FLAT-CONFIG.md

+69-57
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Usage with ESLint `8.57.0` and ESLint `9.x` is described.
1010

1111
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`.
1212

13-
The Cypress ESLint Plugin (`eslint-plugin-cypress`) is currently based on ESLint `8.x` and has not yet been migrated to support Flat Config natively. [ESLint's new config system, Part 2: Introduction to flat config](https://eslint.org/blog/2022/08/new-config-system-part-2/) from August 2022 introduced the [Backwards compatibility utility](https://eslint.org/blog/2022/08/new-config-system-part-2/#backwards-compatibility-utility). This gives the capability to use `eslint-plugin-cypress` in an ESLint flat config environment.
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.
1414

1515
The following information details installation and usage examples for `eslint-plugin-cypress` together with related plugins in an ESLint flat config environment.
1616

@@ -19,60 +19,82 @@ The following information details installation and usage examples for `eslint-pl
1919
It is recommended to use a minimum ESLint `8.x` version [[email protected]](https://github.com/eslint/eslint/releases/tag/v8.57.0) or ESLint `9.x`.
2020

2121
```shell
22-
npm install eslint @eslint/eslintrc eslint-plugin-cypress@^3.1.1 --save-dev
22+
npm install eslint eslint-plugin-cypress --save-dev
2323
```
2424

2525
or
2626

2727
```shell
28-
yarn add eslint @eslint/eslintrc eslint-plugin-cypress@^3.1.1 --dev
28+
yarn add eslint eslint-plugin-cypress --dev
2929
```
3030

3131
## Usage examples
3232

33-
Add a flat configuration file `eslint.config.mjs` file to the root directory of your Cypress project. 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.
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.
3447

3548
### Cypress
3649

37-
All rules from `eslint-plugin-cypress` are available through the `FlatCompat` class of [@eslint/eslintrc](https://www.npmjs.com/package/@eslint/eslintrc).
50+
All rules from `eslint-plugin-cypress` are available through `eslint-plugin-cypress/flat`.
3851
- [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`
3952

4053
```js
41-
import { FlatCompat } from '@eslint/eslintrc'
42-
const compat = new FlatCompat()
54+
import pluginCypress from 'eslint-plugin-cypress/flat'
4355
export default [
44-
...compat.config(
45-
{
46-
plugins: ['cypress'],
47-
rules: {
48-
'cypress/unsafe-to-chain-command': 'error'
49-
}
50-
})
56+
{
57+
plugins: {
58+
cypress: pluginCypress
59+
},
60+
rules: {
61+
'cypress/unsafe-to-chain-command': 'error'
62+
}
63+
}
5164
]
5265
```
5366

5467
### Cypress recommended
5568

56-
The `eslint-plugin-cypress` [recommended rules](README.md#rules) `plugin:cypress/recommended` are activated, except for
69+
The `eslint-plugin-cypress` [recommended rules](README.md#rules) `configs.recommended` are activated, except for
5770
- [cypress/no-unnecessary-waiting](https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/no-unnecessary-waiting.md) set to `off`
5871

5972
```js
60-
import { FlatCompat } from '@eslint/eslintrc'
61-
const compat = new FlatCompat()
73+
import pluginCypress from 'eslint-plugin-cypress/flat'
6274
export default [
63-
...compat.config(
64-
{
65-
extends: ['plugin:cypress/recommended'],
66-
rules: {
67-
'cypress/no-unnecessary-waiting': 'off'
68-
}
69-
})
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
7092
]
7193
```
7294

7395
### Cypress and Mocha recommended
7496

75-
[eslint-plugin-mocha](https://www.npmjs.com/package/eslint-plugin-mocha) is added to the previous example. This plugin offers a flat file recommended option `configs.flat.recommended`.
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`.
7698

7799
The settings for individual `mocha` rules from the `configs.flat.recommended` option are changed.
78100
- [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`
@@ -83,52 +105,42 @@ npm install eslint-plugin-mocha@^10.4.3 --save-dev
83105
```
84106

85107
```js
86-
import { FlatCompat } from '@eslint/eslintrc'
87-
import mochaPlugin from 'eslint-plugin-mocha'
88-
const compat = new FlatCompat()
108+
import pluginMocha from 'eslint-plugin-mocha'
109+
import pluginCypress from 'eslint-plugin-cypress/flat'
89110
export default [
90-
mochaPlugin.configs.flat.recommended, {
111+
pluginMocha.configs.flat.recommended,
112+
pluginCypress.configs.recommended,
113+
{
91114
rules: {
92-
'mocha/no-exclusive-tests': 'error',
93-
'mocha/no-skipped-tests': 'error',
94-
'mocha/no-mocha-arrows': 'off'
115+
'mocha/no-exclusive-tests': 'warn',
116+
'mocha/no-skipped-tests': 'warn',
117+
'mocha/no-mocha-arrows': 'off',
118+
'cypress/no-unnecessary-waiting': 'off'
95119
}
96-
},
97-
...compat.config(
98-
{
99-
extends: ['plugin:cypress/recommended'],
100-
rules: {
101-
'cypress/no-unnecessary-waiting': 'off'
102-
}
103-
})
120+
}
104121
]
105122
```
106123

107124
### Cypress and Chai recommended
108125

109-
[eslint-plugin-chai-friendly](https://www.npmjs.com/package/eslint-plugin-chai-friendly) is combined with the Cypress plugin `eslint-plugin-cypress`.
126+
[eslint-plugin-chai-friendly](https://www.npmjs.com/package/eslint-plugin-chai-friendly) (minimum version [[email protected]](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`.
110127

111-
The [eslint-plugin-chai-friendly](https://www.npmjs.com/package/eslint-plugin-chai-friendly) plugin does not currently offer flat config options and so the `FlatCompat` class of [@eslint/eslintrc](https://www.npmjs.com/package/@eslint/eslintrc) enables this plugin to be used too. The recommended rules for both plugins are used: `plugin:cypress/recommended` and `plugin:chai-friendly/recommended`.
128+
The recommended rules for both plugins are used: `pluginCypress.configs.recommended` and `pluginChaiFriendly.configs.recommended`:
112129

113130
```shell
114-
npm install eslint-plugin-chai-friendly --save-dev
131+
npm install eslint-plugin-chai-friendly@^0.8.0 --save-dev
115132
```
116133

117134
```js
118-
import { FlatCompat } from '@eslint/eslintrc'
119-
const compat = new FlatCompat()
135+
import pluginCypress from 'eslint-plugin-cypress/flat'
136+
import pluginChaiFriendly from 'eslint-plugin-chai-friendly'
120137
export default [
121-
...compat.config(
122-
{
123-
extends: [
124-
'plugin:cypress/recommended',
125-
'plugin:chai-friendly/recommended'
126-
],
127-
rules: {
128-
'cypress/no-unnecessary-waiting': 'off',
129-
}
130-
})
138+
pluginCypress.configs.recommended,
139+
pluginChaiFriendly.configs.recommended,
140+
{
141+
rules: {
142+
'cypress/no-unnecessary-waiting': 'off',
143+
},
144+
}
131145
]
132146
```
133-
134-
**Pending the resolution of issue https://github.com/ihordiachenko/eslint-plugin-chai-friendly/issues/32 [eslint-plugin-chai-friendly](https://www.npmjs.com/package/eslint-plugin-chai-friendly) cannot be used with ESLint `v9`.**

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Note: If you installed ESLint globally then you must also install `eslint-plugin
77
## Installation
88

99
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 through [@eslint/eslintrc](https://www.npmjs.com/package/@eslint/eslintrc).
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.
1111

1212
```sh
1313
npm install eslint-plugin-cypress --save-dev

index.js legacy.js

File renamed without changes.

lib/flat.js

+66
Original file line numberDiff line numberDiff line change
@@ -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.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
"name": "eslint-plugin-cypress",
33
"version": "0.0.0-development",
44
"description": "An ESLint plugin for projects using Cypress",
5-
"main": "index.js",
5+
"main": "legacy.js",
6+
"exports": {
7+
".": "./legacy.js",
8+
"./flat": "./lib/flat.js"
9+
},
610
"author": "Cypress-io",
711
"license": "MIT",
812
"keywords": [

tests-legacy/config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
'use strict'
33

44
const globals = require('globals')
5-
const config = require('../index.js')
5+
const config = require('../legacy.js')
66

77
describe('environments globals', () => {
88
const env = config.environments.globals

tests/config.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22
'use strict'
33

44
const globals = require('globals')
5-
const config = require('../index.js')
5+
const config = require('../lib/flat.js')
66

7-
describe('environments globals', () => {
8-
const env = config.environments.globals
7+
describe('globals languageOptions', () => {
8+
const languageOptions = config.configs.globals.languageOptions
99

1010
it('should not mutate globals', () => {
1111
expect(globals.browser).not.toHaveProperty('cy')
1212
expect(globals.mocha).not.toHaveProperty('cy')
1313
})
1414

1515
it('should include other globals', () => {
16-
expect(env.globals).toEqual(expect.objectContaining(globals.browser))
17-
expect(env.globals).toEqual(expect.objectContaining(globals.mocha))
16+
expect(languageOptions.globals).toEqual(expect.objectContaining(globals.browser))
17+
expect(languageOptions.globals).toEqual(expect.objectContaining(globals.mocha))
1818
})
1919

2020
it('should include cypress globals', () => {
21-
expect(env.globals).toEqual(expect.objectContaining({
21+
expect(languageOptions.globals).toEqual(expect.objectContaining({
2222
cy: false,
2323
Cypress: false,
2424
}))

0 commit comments

Comments
 (0)