eslint-plugin-cypress 5.0.0 → 5.0.1

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 CHANGED
@@ -32,7 +32,7 @@ To add a new rule:
32
32
  * Run `eslint-doc-generator` to generate automated documentation sections (see [Document generation](#document-generation) below)
33
33
  * Review documentation changes
34
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)
35
+ * Run `npm test` to run [Vitest](https://vitest.dev/)
36
36
  * Make sure all tests are passing
37
37
  * Add the rule to [flat.js](https://github.com/cypress-io/eslint-plugin-cypress/blob/master/lib/flat.js)
38
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))
package/eslint.config.mjs CHANGED
@@ -2,25 +2,32 @@ import globals from 'globals'
2
2
  import pluginJs from '@eslint/js'
3
3
  import eslintPlugin from 'eslint-plugin-eslint-plugin'
4
4
  import mochaPlugin from 'eslint-plugin-mocha'
5
+ import stylistic from '@stylistic/eslint-plugin'
5
6
 
6
7
  export default [
7
8
  pluginJs.configs.recommended,
8
9
  eslintPlugin.configs['flat/recommended'],
9
10
  mochaPlugin.configs.recommended,
10
- {ignores: ['test-project/']},
11
+ stylistic.configs.recommended,
12
+ { ignores: ['test-project/'] },
11
13
  {
12
14
  languageOptions: {
13
- globals: globals.node
15
+ globals: globals.node,
14
16
  },
15
17
  rules: {
16
18
  'no-redeclare': 'off',
19
+ '@stylistic/arrow-parens': ['error', 'always'],
20
+ '@stylistic/indent': ['error', 2],
21
+ '@stylistic/comma-dangle': ['error', 'always-multiline'],
22
+ '@stylistic/quotes': ['error', 'single'],
23
+ '@stylistic/semi': ['error', 'never'],
17
24
  'eslint-plugin/require-meta-docs-url':
18
- ['error', { 'pattern': 'https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/{{name}}.md' }],
25
+ ['error', { pattern: 'https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/{{name}}.md' }],
19
26
  'eslint-plugin/require-meta-docs-description': 'error',
20
27
  'eslint-plugin/meta-property-ordering': 'error',
21
28
  'eslint-plugin/test-case-property-ordering': 'error',
22
29
  'mocha/no-mocha-arrows': 'off',
23
- 'mocha/no-setup-in-describe': 'off'
24
- }
30
+ 'mocha/no-setup-in-describe': 'off',
31
+ },
25
32
  },
26
33
  ]
package/lib/flat.js CHANGED
@@ -20,8 +20,8 @@ const plugin = {
20
20
  },
21
21
  }
22
22
 
23
- const commonGlobals =
24
- Object.assign({
23
+ const commonGlobals
24
+ = Object.assign({
25
25
  cy: false,
26
26
  Cypress: false,
27
27
  expect: false,
@@ -33,20 +33,20 @@ Object.assign(plugin.configs, {
33
33
  globals: {
34
34
  name: 'cypress/globals',
35
35
  plugins: {
36
- cypress: plugin
36
+ cypress: plugin,
37
37
  },
38
38
  languageOptions: {
39
39
  globals:
40
40
  commonGlobals,
41
- }
42
- }
41
+ },
42
+ },
43
43
  })
44
44
 
45
45
  Object.assign(plugin.configs, {
46
46
  recommended: {
47
47
  name: 'cypress/recommended',
48
48
  plugins: {
49
- cypress: plugin
49
+ cypress: plugin,
50
50
  },
51
51
  rules: {
52
52
  'cypress/no-assigning-return-values': 'error',
@@ -57,8 +57,8 @@ Object.assign(plugin.configs, {
57
57
  languageOptions: {
58
58
  globals:
59
59
  commonGlobals,
60
- }
61
- }
60
+ },
61
+ },
62
62
  })
63
63
 
64
64
  module.exports = plugin
@@ -28,9 +28,9 @@ module.exports = {
28
28
  unexpected: 'Make an assertion on the page state before taking a screenshot',
29
29
  },
30
30
  },
31
- create (context) {
31
+ create(context) {
32
32
  return {
33
- CallExpression (node) {
33
+ CallExpression(node) {
34
34
  if (isCallingCyScreenshot(node) && !isPreviousAnAssertion(node)) {
35
35
  context.report({ node, messageId: 'unexpected' })
36
36
  }
@@ -39,12 +39,12 @@ module.exports = {
39
39
  },
40
40
  }
41
41
 
42
- function isRootCypress (node) {
42
+ function isRootCypress(node) {
43
43
  while (node.type === 'CallExpression') {
44
44
  if (node.callee.type !== 'MemberExpression') return false
45
45
 
46
- if (node.callee.object.type === 'Identifier' &&
47
- node.callee.object.name === 'cy') {
46
+ if (node.callee.object.type === 'Identifier'
47
+ && node.callee.object.name === 'cy') {
48
48
  return true
49
49
  }
50
50
 
@@ -54,26 +54,26 @@ function isRootCypress (node) {
54
54
  return false
55
55
  }
56
56
 
57
- function getPreviousInChain (node) {
58
- return node.type === 'CallExpression' &&
59
- node.callee.type === 'MemberExpression' &&
60
- node.callee.object.type === 'CallExpression' &&
61
- node.callee.object.callee.type === 'MemberExpression' &&
62
- node.callee.object.callee.property.type === 'Identifier' &&
63
- node.callee.object.callee.property.name
57
+ function getPreviousInChain(node) {
58
+ return node.type === 'CallExpression'
59
+ && node.callee.type === 'MemberExpression'
60
+ && node.callee.object.type === 'CallExpression'
61
+ && node.callee.object.callee.type === 'MemberExpression'
62
+ && node.callee.object.callee.property.type === 'Identifier'
63
+ && node.callee.object.callee.property.name
64
64
  }
65
65
 
66
- function getCallExpressionCypressCommand (node) {
67
- return isRootCypress(node) &&
68
- node.callee.property.type === 'Identifier' &&
69
- node.callee.property.name
66
+ function getCallExpressionCypressCommand(node) {
67
+ return isRootCypress(node)
68
+ && node.callee.property.type === 'Identifier'
69
+ && node.callee.property.name
70
70
  }
71
71
 
72
- function isCallingCyScreenshot (node) {
72
+ function isCallingCyScreenshot(node) {
73
73
  return getCallExpressionCypressCommand(node) === 'screenshot'
74
74
  }
75
75
 
76
- function getPreviousCypressCommand (node) {
76
+ function getPreviousCypressCommand(node) {
77
77
  const previousInChain = getPreviousInChain(node)
78
78
 
79
79
  if (previousInChain) {
@@ -97,15 +97,15 @@ function getPreviousCypressCommand (node) {
97
97
 
98
98
  const previousStatement = body[index - 1]
99
99
 
100
- if (previousStatement.type !== 'ExpressionStatement' ||
101
- previousStatement.expression.type !== 'CallExpression') {
100
+ if (previousStatement.type !== 'ExpressionStatement'
101
+ || previousStatement.expression.type !== 'CallExpression') {
102
102
  return null
103
103
  }
104
104
 
105
105
  return getCallExpressionCypressCommand(previousStatement.expression)
106
106
  }
107
107
 
108
- function isPreviousAnAssertion (node) {
108
+ function isPreviousAnAssertion(node) {
109
109
  const previousCypressCommand = getPreviousCypressCommand(node)
110
110
 
111
111
  return assertionCommands.indexOf(previousCypressCommand) >= 0
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  // safely get nested object property
4
- function get (obj, propertyString = '') {
4
+ function get(obj, propertyString = '') {
5
5
  const properties = propertyString.split('.')
6
6
 
7
7
  for (let i = 0; i < properties.length; i++) {
@@ -29,9 +29,9 @@ module.exports = {
29
29
  unexpected: 'Do not assign the return value of a Cypress command',
30
30
  },
31
31
  },
32
- create (context) {
32
+ create(context) {
33
33
  return {
34
- VariableDeclaration (node) {
34
+ VariableDeclaration(node) {
35
35
  if (node.declarations.some(isCypressCommandDeclaration)) {
36
36
  context.report({ node, messageId: 'unexpected' })
37
37
  }
@@ -47,7 +47,7 @@ const allowedCommands = {
47
47
  stub: true,
48
48
  }
49
49
 
50
- function isCypressCommandDeclaration (declarator) {
50
+ function isCypressCommandDeclaration(declarator) {
51
51
  let object = get(declarator, 'init.callee.object')
52
52
 
53
53
  if (!object) return
@@ -15,31 +15,31 @@ module.exports = {
15
15
  },
16
16
  },
17
17
 
18
- create (context) {
19
- function isBeforeBlock (callExpressionNode) {
18
+ create(context) {
19
+ function isBeforeBlock(callExpressionNode) {
20
20
  const { type, name } = callExpressionNode.callee
21
21
 
22
22
  return type === 'Identifier'
23
- && name === 'before' || name === 'beforeEach'
23
+ && (name === 'before' || name === 'beforeEach')
24
24
  }
25
25
 
26
- function isBeforeAsync (node) {
26
+ function isBeforeAsync(node) {
27
27
  return node.arguments
28
- && node.arguments.length >= 2
29
- && node.arguments[1].async === true
28
+ && node.arguments.length >= 2
29
+ && node.arguments[1].async === true
30
30
  }
31
31
  const sourceCode = context.sourceCode ?? context.getSourceCode()
32
32
 
33
33
  return {
34
- Identifier (node) {
34
+ Identifier(node) {
35
35
  if (node.name === 'cy' || node.name === 'Cypress') {
36
36
  const ancestors = sourceCode.getAncestors
37
37
  ? sourceCode.getAncestors(node)
38
38
  : context.getAncestors()
39
39
  const asyncTestBlocks = ancestors
40
- .filter((n) => n.type === 'CallExpression')
41
- .filter(isBeforeBlock)
42
- .filter(isBeforeAsync)
40
+ .filter((n) => n.type === 'CallExpression')
41
+ .filter(isBeforeBlock)
42
+ .filter(isBeforeAsync)
43
43
 
44
44
  if (asyncTestBlocks.length >= 1) {
45
45
  asyncTestBlocks.forEach((node) => {
@@ -15,31 +15,31 @@ module.exports = {
15
15
  },
16
16
  },
17
17
 
18
- create (context) {
19
- function isTestBlock (callExpressionNode) {
18
+ create(context) {
19
+ function isTestBlock(callExpressionNode) {
20
20
  const { type, name } = callExpressionNode.callee
21
21
 
22
22
  return type === 'Identifier'
23
- && name === 'it' || name === 'test'
23
+ && (name === 'it' || name === 'test')
24
24
  }
25
25
 
26
- function isTestAsync (node) {
26
+ function isTestAsync(node) {
27
27
  return node.arguments
28
- && node.arguments.length >= 2
29
- && node.arguments[1].async === true
28
+ && node.arguments.length >= 2
29
+ && node.arguments[1].async === true
30
30
  }
31
31
  const sourceCode = context.sourceCode ?? context.getSourceCode()
32
32
 
33
33
  return {
34
- Identifier (node) {
34
+ Identifier(node) {
35
35
  if (node.name === 'cy' || node.name === 'Cypress') {
36
36
  const ancestors = sourceCode.getAncestors
37
37
  ? sourceCode.getAncestors(node)
38
38
  : context.getAncestors()
39
39
  const asyncTestBlocks = ancestors
40
- .filter((n) => n.type === 'CallExpression')
41
- .filter(isTestBlock)
42
- .filter(isTestAsync)
40
+ .filter((n) => n.type === 'CallExpression')
41
+ .filter(isTestBlock)
42
+ .filter(isTestAsync)
43
43
 
44
44
  if (asyncTestBlocks.length >= 1) {
45
45
  asyncTestBlocks.forEach((node) => {
@@ -1,8 +1,8 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
- //------------------------------------------------------------------------------
3
+ // ------------------------------------------------------------------------------
4
4
  // Rule Definition
5
- //------------------------------------------------------------------------------
5
+ // ------------------------------------------------------------------------------
6
6
 
7
7
  /** @type {import('eslint').Rule.RuleModule} */
8
8
  module.exports = {
@@ -23,55 +23,55 @@ module.exports = {
23
23
  create(context) {
24
24
  const isRootCypress = (node) => {
25
25
  if (
26
- node.type !== 'CallExpression' ||
27
- node.callee.type !== 'MemberExpression'
26
+ node.type !== 'CallExpression'
27
+ || node.callee.type !== 'MemberExpression'
28
28
  ) {
29
- return false;
29
+ return false
30
30
  }
31
31
 
32
32
  if (
33
- node.callee.object.type === 'Identifier' &&
34
- node.callee.object.name === 'cy'
33
+ node.callee.object.type === 'Identifier'
34
+ && node.callee.object.name === 'cy'
35
35
  ) {
36
- return true;
36
+ return true
37
37
  }
38
38
 
39
- return isRootCypress(node.callee.object);
40
- };
39
+ return isRootCypress(node.callee.object)
40
+ }
41
41
 
42
42
  const hasChainedGet = (node) => {
43
43
  // Check if this node is a get() call
44
- const isGetCall =
45
- node.callee &&
46
- node.callee.type === 'MemberExpression' &&
47
- node.callee.property &&
48
- node.callee.property.type === 'Identifier' &&
49
- node.callee.property.name === 'get';
44
+ const isGetCall
45
+ = node.callee
46
+ && node.callee.type === 'MemberExpression'
47
+ && node.callee.property
48
+ && node.callee.property.type === 'Identifier'
49
+ && node.callee.property.name === 'get'
50
50
 
51
51
  if (!isGetCall) {
52
- return false;
52
+ return false
53
53
  }
54
54
 
55
- const obj = node.callee.object;
55
+ const obj = node.callee.object
56
56
 
57
57
  if (obj.type === 'CallExpression') {
58
- const objCallee = obj.callee;
58
+ const objCallee = obj.callee
59
59
 
60
60
  if (
61
- objCallee &&
62
- objCallee.type === 'MemberExpression' &&
63
- objCallee.property &&
64
- objCallee.property.type === 'Identifier' &&
65
- objCallee.property.name === 'get'
61
+ objCallee
62
+ && objCallee.type === 'MemberExpression'
63
+ && objCallee.property
64
+ && objCallee.property.type === 'Identifier'
65
+ && objCallee.property.name === 'get'
66
66
  ) {
67
- return true;
67
+ return true
68
68
  }
69
69
 
70
- return hasChainedGet(obj);
70
+ return hasChainedGet(obj)
71
71
  }
72
72
 
73
- return false;
74
- };
73
+ return false
74
+ }
75
75
 
76
76
  return {
77
77
  CallExpression(node) {
@@ -79,9 +79,9 @@ module.exports = {
79
79
  context.report({
80
80
  node,
81
81
  messageId: 'unexpected',
82
- });
82
+ })
83
83
  }
84
84
  },
85
- };
85
+ }
86
86
  },
87
- };
87
+ }
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
2
 
3
- //------------------------------------------------------------------------------
3
+ // ------------------------------------------------------------------------------
4
4
  // Rule Definition
5
- //------------------------------------------------------------------------------
5
+ // ------------------------------------------------------------------------------
6
6
 
7
7
  module.exports = {
8
8
  meta: {
@@ -20,37 +20,36 @@ module.exports = {
20
20
  },
21
21
  },
22
22
 
23
- create (context) {
24
-
23
+ create(context) {
25
24
  // variables should be defined here
26
25
 
27
- //----------------------------------------------------------------------
26
+ // ----------------------------------------------------------------------
28
27
  // Helpers
29
- //----------------------------------------------------------------------
30
- function isCallingDebug (node) {
31
- return node.callee &&
32
- node.callee.property &&
33
- node.callee.property.type === 'Identifier' &&
34
- node.callee.property.name === 'debug'
28
+ // ----------------------------------------------------------------------
29
+ function isCallingDebug(node) {
30
+ return node.callee
31
+ && node.callee.property
32
+ && node.callee.property.type === 'Identifier'
33
+ && node.callee.property.name === 'debug'
35
34
  }
36
35
 
37
- function isCypressCall (node) {
36
+ function isCypressCall(node) {
38
37
  if (!node.callee || node.callee.type !== 'MemberExpression') {
39
- return false;
38
+ return false
40
39
  }
41
40
  if (node.callee.object.type === 'Identifier' && node.callee.object.name === 'cy') {
42
- return true;
41
+ return true
43
42
  }
44
- return isCypressCall(node.callee.object);
43
+ return isCypressCall(node.callee.object)
45
44
  }
46
-
47
- //----------------------------------------------------------------------
45
+
46
+ // ----------------------------------------------------------------------
48
47
  // Public
49
- //----------------------------------------------------------------------
48
+ // ----------------------------------------------------------------------
50
49
 
51
50
  return {
52
51
 
53
- CallExpression (node) {
52
+ CallExpression(node) {
54
53
  if (isCypressCall(node) && isCallingDebug(node)) {
55
54
  context.report({ node, messageId: 'unexpected' })
56
55
  }
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
2
 
3
- //------------------------------------------------------------------------------
3
+ // ------------------------------------------------------------------------------
4
4
  // Rule Definition
5
- //------------------------------------------------------------------------------
5
+ // ------------------------------------------------------------------------------
6
6
 
7
7
  module.exports = {
8
8
  meta: {
@@ -20,39 +20,36 @@ module.exports = {
20
20
  },
21
21
  },
22
22
 
23
- create (context) {
24
-
23
+ create(context) {
25
24
  // variables should be defined here
26
25
 
27
- //----------------------------------------------------------------------
26
+ // ----------------------------------------------------------------------
28
27
  // Helpers
29
- //----------------------------------------------------------------------
30
- function isCallingClickOrType (node) {
28
+ // ----------------------------------------------------------------------
29
+ function isCallingClickOrType(node) {
31
30
  const allowedMethods = ['click', 'dblclick', 'type', 'trigger', 'check', 'rightclick', 'focus', 'select']
32
31
 
33
- return node.property && node.property.type === 'Identifier' &&
34
- allowedMethods.includes(node.property.name)
32
+ return node.property && node.property.type === 'Identifier'
33
+ && allowedMethods.includes(node.property.name)
35
34
  }
36
35
 
37
- function isCypressCall (node) {
38
- return node.callee.type === 'MemberExpression' &&
39
- node.callee.object.type === 'Identifier' &&
40
- node.callee.object.name === 'cy'
36
+ function isCypressCall(node) {
37
+ return node.callee.type === 'MemberExpression'
38
+ && node.callee.object.type === 'Identifier'
39
+ && node.callee.object.name === 'cy'
41
40
  }
42
41
 
43
- function hasOptionForce (node) {
44
-
45
- return node.arguments && node.arguments.length &&
46
- node.arguments.some((arg) => {
47
- return arg.type === 'ObjectExpression' && arg.properties.some((propNode) => propNode.key && propNode.key.name === 'force')
48
- })
42
+ function hasOptionForce(node) {
43
+ return node.arguments && node.arguments.length
44
+ && node.arguments.some((arg) => {
45
+ return arg.type === 'ObjectExpression' && arg.properties.some((propNode) => propNode.key && propNode.key.name === 'force')
46
+ })
49
47
  }
50
48
 
51
- function deepCheck (node, checkFunc) {
49
+ function deepCheck(node, checkFunc) {
52
50
  let currentNode = node
53
51
 
54
52
  while (currentNode.parent) {
55
-
56
53
  if (checkFunc(currentNode.parent)) {
57
54
  return true
58
55
  }
@@ -63,13 +60,13 @@ module.exports = {
63
60
  return false
64
61
  }
65
62
 
66
- //----------------------------------------------------------------------
63
+ // ----------------------------------------------------------------------
67
64
  // Public
68
- //----------------------------------------------------------------------
65
+ // ----------------------------------------------------------------------
69
66
 
70
67
  return {
71
68
 
72
- CallExpression (node) {
69
+ CallExpression(node) {
73
70
  if (isCypressCall(node) && deepCheck(node, isCallingClickOrType) && deepCheck(node, hasOptionForce)) {
74
71
  context.report({ node, messageId: 'unexpected' })
75
72
  }
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
2
 
3
- //------------------------------------------------------------------------------
3
+ // ------------------------------------------------------------------------------
4
4
  // Rule Definition
5
- //------------------------------------------------------------------------------
5
+ // ------------------------------------------------------------------------------
6
6
 
7
7
  module.exports = {
8
8
  meta: {
@@ -20,37 +20,36 @@ module.exports = {
20
20
  },
21
21
  },
22
22
 
23
- create (context) {
24
-
23
+ create(context) {
25
24
  // variables should be defined here
26
25
 
27
- //----------------------------------------------------------------------
26
+ // ----------------------------------------------------------------------
28
27
  // Helpers
29
- //----------------------------------------------------------------------
30
- function isCallingPause (node) {
31
- return node.callee &&
32
- node.callee.property &&
33
- node.callee.property.type === 'Identifier' &&
34
- node.callee.property.name === 'pause'
28
+ // ----------------------------------------------------------------------
29
+ function isCallingPause(node) {
30
+ return node.callee
31
+ && node.callee.property
32
+ && node.callee.property.type === 'Identifier'
33
+ && node.callee.property.name === 'pause'
35
34
  }
36
35
 
37
- function isCypressCall (node) {
36
+ function isCypressCall(node) {
38
37
  if (!node.callee || node.callee.type !== 'MemberExpression') {
39
- return false;
38
+ return false
40
39
  }
41
40
  if (node.callee.object.type === 'Identifier' && node.callee.object.name === 'cy') {
42
- return true;
41
+ return true
43
42
  }
44
- return isCypressCall(node.callee.object);
43
+ return isCypressCall(node.callee.object)
45
44
  }
46
-
47
- //----------------------------------------------------------------------
45
+
46
+ // ----------------------------------------------------------------------
48
47
  // Public
49
- //----------------------------------------------------------------------
48
+ // ----------------------------------------------------------------------
50
49
 
51
50
  return {
52
51
 
53
- CallExpression (node) {
52
+ CallExpression(node) {
54
53
  if (isCypressCall(node) && isCallingPause(node)) {
55
54
  context.report({ node, messageId: 'unexpected' })
56
55
  }
@@ -14,11 +14,11 @@ module.exports = {
14
14
  unexpected: 'Do not wait for arbitrary time periods',
15
15
  },
16
16
  },
17
- create (context) {
17
+ create(context) {
18
18
  const sourceCode = context.sourceCode ?? context.getSourceCode()
19
19
 
20
20
  return {
21
- CallExpression (node) {
21
+ CallExpression(node) {
22
22
  if (isCallingCyWait(node)) {
23
23
  const scope = sourceCode.getScope
24
24
  ? sourceCode.getScope(node)
@@ -33,7 +33,7 @@ module.exports = {
33
33
  },
34
34
  }
35
35
 
36
- function nodeIsCalledByCy (node) {
36
+ function nodeIsCalledByCy(node) {
37
37
  if (node.type === 'Identifier' && node.name === 'cy') return true
38
38
 
39
39
  if (typeof node.callee === 'undefined' || typeof node.callee.object === 'undefined') {
@@ -43,20 +43,20 @@ function nodeIsCalledByCy (node) {
43
43
  return nodeIsCalledByCy(node.callee.object)
44
44
  }
45
45
 
46
- function isCallingCyWait (node) {
47
- return node.callee.type === 'MemberExpression' &&
48
- nodeIsCalledByCy(node) &&
49
- node.callee.property.type === 'Identifier' &&
50
- node.callee.property.name === 'wait'
46
+ function isCallingCyWait(node) {
47
+ return node.callee.type === 'MemberExpression'
48
+ && nodeIsCalledByCy(node)
49
+ && node.callee.property.type === 'Identifier'
50
+ && node.callee.property.name === 'wait'
51
51
  }
52
52
 
53
- function isNumberArgument (node) {
54
- return node.arguments.length > 0 &&
55
- node.arguments[0].type === 'Literal' &&
56
- typeof (node.arguments[0].value) === 'number'
53
+ function isNumberArgument(node) {
54
+ return node.arguments.length > 0
55
+ && node.arguments[0].type === 'Literal'
56
+ && typeof (node.arguments[0].value) === 'number'
57
57
  }
58
58
 
59
- function isIdentifierNumberConstArgument (node, scope) {
59
+ function isIdentifierNumberConstArgument(node, scope) {
60
60
  if (node.arguments.length === 0) return false
61
61
 
62
62
  if (node.arguments[0].type !== 'Identifier') return false
@@ -6,7 +6,7 @@ module.exports = {
6
6
  docs: {
7
7
  description: 'disallow using `cy.xpath()` calls',
8
8
  recommended: false,
9
- url: 'https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/no-xpath.md'
9
+ url: 'https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/no-xpath.md',
10
10
  },
11
11
  fixable: null, // Or `code` or `whitespace`
12
12
  schema: [], // Add a schema if the rule has options
@@ -15,21 +15,21 @@ module.exports = {
15
15
  },
16
16
  },
17
17
 
18
- create (context) {
18
+ create(context) {
19
19
  return {
20
- CallExpression (node) {
20
+ CallExpression(node) {
21
21
  if (isCallingCyXpath(node)) {
22
22
  context.report({ node, messageId: 'unexpected' })
23
23
  }
24
24
  },
25
25
  }
26
26
  },
27
- };
27
+ }
28
28
 
29
- function isCallingCyXpath (node) {
30
- return node.callee.type === 'MemberExpression' &&
31
- node.callee.object.type === 'Identifier' &&
32
- node.callee.object.name === 'cy' &&
33
- node.callee.property.type === 'Identifier' &&
34
- node.callee.property.name === 'xpath'
29
+ function isCallingCyXpath(node) {
30
+ return node.callee.type === 'MemberExpression'
31
+ && node.callee.object.type === 'Identifier'
32
+ && node.callee.object.name === 'cy'
33
+ && node.callee.property.type === 'Identifier'
34
+ && node.callee.property.name === 'xpath'
35
35
  }
@@ -15,9 +15,9 @@ module.exports = {
15
15
  },
16
16
  },
17
17
 
18
- create (context) {
18
+ create(context) {
19
19
  return {
20
- CallExpression (node) {
20
+ CallExpression(node) {
21
21
  if (isCallingCyGet(node) && !isDataArgument(node)) {
22
22
  context.report({ node, messageId: 'unexpected' })
23
23
  }
@@ -26,23 +26,23 @@ module.exports = {
26
26
  },
27
27
  }
28
28
 
29
- function isCallingCyGet (node) {
30
- return node.callee.type === 'MemberExpression' &&
31
- node.callee.object.type === 'Identifier' &&
32
- node.callee.object.name === 'cy' &&
33
- node.callee.property.type === 'Identifier' &&
34
- node.callee.property.name === 'get'
29
+ function isCallingCyGet(node) {
30
+ return node.callee.type === 'MemberExpression'
31
+ && node.callee.object.type === 'Identifier'
32
+ && node.callee.object.name === 'cy'
33
+ && node.callee.property.type === 'Identifier'
34
+ && node.callee.property.name === 'get'
35
35
  }
36
36
 
37
- function isDataArgument (node) {
38
- return node.arguments.length > 0 &&
39
- (
40
- (node.arguments[0].type === 'Literal' && isAliasOrDataSelector(String(node.arguments[0].value))) ||
41
- (node.arguments[0].type === 'TemplateLiteral' && isAliasOrDataSelector(String(node.arguments[0].quasis[0].value.cooked)))
37
+ function isDataArgument(node) {
38
+ return node.arguments.length > 0
39
+ && (
40
+ (node.arguments[0].type === 'Literal' && isAliasOrDataSelector(String(node.arguments[0].value)))
41
+ || (node.arguments[0].type === 'TemplateLiteral' && isAliasOrDataSelector(String(node.arguments[0].quasis[0].value.cooked)))
42
42
  )
43
43
  }
44
44
 
45
- function isAliasOrDataSelector (selector) {
45
+ function isAliasOrDataSelector(selector) {
46
46
  return ['[data-', '@'].some(function (validValue) {
47
47
  return selector.startsWith(validValue)
48
48
  })
@@ -82,15 +82,15 @@ module.exports = {
82
82
  'It is unsafe to chain further commands that rely on the subject after this command. It is best to split the chain, chaining again from `cy.` in a next command line.',
83
83
  },
84
84
  },
85
- create (context) {
85
+ create(context) {
86
86
  const { methods } = getDefaultOptions(context)
87
87
 
88
88
  return {
89
- CallExpression (node) {
89
+ CallExpression(node) {
90
90
  if (
91
- isRootCypress(node) &&
92
- isActionUnsafeToChain(node, methods) &&
93
- node.parent.type === 'MemberExpression'
91
+ isRootCypress(node)
92
+ && isActionUnsafeToChain(node, methods)
93
+ && node.parent.type === 'MemberExpression'
94
94
  ) {
95
95
  context.report({
96
96
  node,
@@ -108,15 +108,15 @@ module.exports = {
108
108
  */
109
109
  const isRootCypress = (node) => {
110
110
  if (
111
- node.type !== 'CallExpression' ||
112
- node.callee.type !== 'MemberExpression'
111
+ node.type !== 'CallExpression'
112
+ || node.callee.type !== 'MemberExpression'
113
113
  ) {
114
114
  return false
115
115
  }
116
116
 
117
117
  if (
118
- node.callee.object.type === 'Identifier' &&
119
- node.callee.object.name === 'cy'
118
+ node.callee.object.type === 'Identifier'
119
+ && node.callee.object.name === 'cy'
120
120
  ) {
121
121
  return true
122
122
  }
@@ -135,9 +135,9 @@ const isActionUnsafeToChain = (node, additionalMethods = []) => {
135
135
  ].join('|'))
136
136
 
137
137
  return (
138
- node.callee &&
139
- node.callee.property &&
140
- node.callee.property.type === 'Identifier' &&
141
- unsafeActionsRegex.test(node.callee.property.name)
138
+ node.callee
139
+ && node.callee.property
140
+ && node.callee.property.type === 'Identifier'
141
+ && unsafeActionsRegex.test(node.callee.property.name)
142
142
  )
143
143
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-cypress",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": "An ESLint plugin for projects using Cypress",
5
5
  "main": "./lib/flat.js",
6
6
  "exports": {
@@ -29,20 +29,19 @@
29
29
  "globals": "^16.2.0"
30
30
  },
31
31
  "devDependencies": {
32
+ "@stylistic/eslint-plugin": "^4.4.0",
32
33
  "eslint": "^9.27.0",
33
34
  "eslint-plugin-eslint-plugin": "^6.4.0",
34
35
  "eslint-plugin-mocha": "^11.1.0",
35
36
  "husky": "^9.1.7",
36
- "jest": "^29.7.0",
37
- "semantic-release": "24.2.5"
37
+ "semantic-release": "24.2.5",
38
+ "vitest": "^3.1.4"
38
39
  },
39
40
  "scripts": {
40
41
  "lint": "eslint",
41
42
  "lint-fix": "eslint --fix",
42
43
  "semantic-release": "semantic-release",
43
- "start": "npm run test-watch",
44
- "test": "jest",
45
- "test-watch": "jest --watchAll",
44
+ "test": "vitest run",
46
45
  "prepare": "husky"
47
46
  }
48
47
  }
@@ -2,30 +2,30 @@
2
2
  * @fileoverview disallow chain of `cy.get()` calls
3
3
  * @author benoit
4
4
  */
5
- "use strict";
5
+ 'use strict'
6
6
 
7
- //------------------------------------------------------------------------------
7
+ // ------------------------------------------------------------------------------
8
8
  // Requirements
9
- //------------------------------------------------------------------------------
9
+ // ------------------------------------------------------------------------------
10
10
 
11
- const rule = require("../../../lib/rules/no-chained-get"),
12
- RuleTester = require("eslint").RuleTester;
11
+ const rule = require('../../../lib/rules/no-chained-get'),
12
+ RuleTester = require('eslint').RuleTester
13
13
 
14
- //------------------------------------------------------------------------------
14
+ // ------------------------------------------------------------------------------
15
15
  // Tests
16
- //------------------------------------------------------------------------------
16
+ // ------------------------------------------------------------------------------
17
17
 
18
- const ruleTester = new RuleTester();
19
- ruleTester.run("no-chained-get", rule, {
18
+ const ruleTester = new RuleTester()
19
+ ruleTester.run('no-chained-get', rule, {
20
20
  valid: [
21
- { code: "cy.get('div')" },
22
- { code: "cy.get('.div').find().get()" },
23
- { code: "cy.get('input').should('be.disabled')" },
21
+ { code: 'cy.get(\'div\')' },
22
+ { code: 'cy.get(\'.div\').find().get()' },
23
+ { code: 'cy.get(\'input\').should(\'be.disabled\')' },
24
24
  ],
25
25
  invalid: [
26
26
  {
27
- code: "cy.get('div').get('div')",
28
- errors: [{ messageId: "unexpected" }],
27
+ code: 'cy.get(\'div\').get(\'div\')',
28
+ errors: [{ messageId: 'unexpected' }],
29
29
  },
30
30
  ],
31
- });
31
+ })
@@ -10,14 +10,14 @@ const errors = [{ messageId: 'unexpected' }]
10
10
  ruleTester.run('no-debug', rule, {
11
11
 
12
12
  valid: [
13
- { code: `debug()` },
14
- { code: `cy.get('button').dblclick()` },
13
+ { code: 'debug()' },
14
+ { code: 'cy.get(\'button\').dblclick()' },
15
15
  ],
16
16
 
17
17
  invalid: [
18
- { code: `cy.debug()`, errors },
19
- { code: `cy.debug({ log: false })`, errors },
20
- { code: `cy.get('button').debug()`, errors },
21
- { code: `cy.get('a').should('have.attr', 'href').and('match', /dashboard/).debug()`, errors }
18
+ { code: 'cy.debug()', errors },
19
+ { code: 'cy.debug({ log: false })', errors },
20
+ { code: 'cy.get(\'button\').debug()', errors },
21
+ { code: 'cy.get(\'a\').should(\'have.attr\', \'href\').and(\'match\', /dashboard/).debug()', errors },
22
22
  ],
23
23
  })
@@ -10,30 +10,30 @@ const errors = [{ messageId: 'unexpected' }]
10
10
  ruleTester.run('no-force', rule, {
11
11
 
12
12
  valid: [
13
- { code: `cy.get('button').click()` },
14
- { code: `cy.get('button').click({multiple: true})` },
15
- { code: `cy.get('button').dblclick()` },
16
- { code: `cy.get('input').type('somth')` },
17
- { code: `cy.get('input').type('somth', {anyoption: true})` },
18
- { code: `cy.get('input').trigger('click', {anyoption: true})` },
19
- { code: `cy.get('input').rightclick({anyoption: true})` },
20
- { code: `cy.get('input').check()` },
21
- { code: `cy.get('input').select()` },
22
- { code: `cy.get('input').focus()` },
23
- { code: `cy.document().trigger("keydown", { ...event })` },
13
+ { code: 'cy.get(\'button\').click()' },
14
+ { code: 'cy.get(\'button\').click({multiple: true})' },
15
+ { code: 'cy.get(\'button\').dblclick()' },
16
+ { code: 'cy.get(\'input\').type(\'somth\')' },
17
+ { code: 'cy.get(\'input\').type(\'somth\', {anyoption: true})' },
18
+ { code: 'cy.get(\'input\').trigger(\'click\', {anyoption: true})' },
19
+ { code: 'cy.get(\'input\').rightclick({anyoption: true})' },
20
+ { code: 'cy.get(\'input\').check()' },
21
+ { code: 'cy.get(\'input\').select()' },
22
+ { code: 'cy.get(\'input\').focus()' },
23
+ { code: 'cy.document().trigger("keydown", { ...event })' },
24
24
  ],
25
25
 
26
26
  invalid: [
27
- { code: `cy.get('button').click({force: true})`, errors },
28
- { code: `cy.get('button').dblclick({force: true})`, errors },
29
- { code: `cy.get('input').type('somth', {force: true})`, errors },
30
- { code: `cy.get('div').find('.foo').type('somth', {force: true})`, errors },
31
- { code: `cy.get('div').find('.foo').find('.bar').click({force: true})`, errors },
32
- { code: `cy.get('div').find('.foo').find('.bar').trigger('change', {force: true})`, errors },
33
- { code: `cy.get('input').trigger('click', {force: true})`, errors },
34
- { code: `cy.get('input').rightclick({force: true})`, errors },
35
- { code: `cy.get('input').check({force: true})`, errors },
36
- { code: `cy.get('input').select({force: true})`, errors },
37
- { code: `cy.get('input').focus({force: true})`, errors },
27
+ { code: 'cy.get(\'button\').click({force: true})', errors },
28
+ { code: 'cy.get(\'button\').dblclick({force: true})', errors },
29
+ { code: 'cy.get(\'input\').type(\'somth\', {force: true})', errors },
30
+ { code: 'cy.get(\'div\').find(\'.foo\').type(\'somth\', {force: true})', errors },
31
+ { code: 'cy.get(\'div\').find(\'.foo\').find(\'.bar\').click({force: true})', errors },
32
+ { code: 'cy.get(\'div\').find(\'.foo\').find(\'.bar\').trigger(\'change\', {force: true})', errors },
33
+ { code: 'cy.get(\'input\').trigger(\'click\', {force: true})', errors },
34
+ { code: 'cy.get(\'input\').rightclick({force: true})', errors },
35
+ { code: 'cy.get(\'input\').check({force: true})', errors },
36
+ { code: 'cy.get(\'input\').select({force: true})', errors },
37
+ { code: 'cy.get(\'input\').focus({force: true})', errors },
38
38
  ],
39
39
  })
@@ -10,14 +10,14 @@ const errors = [{ messageId: 'unexpected' }]
10
10
  ruleTester.run('no-pause', rule, {
11
11
 
12
12
  valid: [
13
- { code: `pause()` },
14
- { code: `cy.get('button').dblclick()` },
13
+ { code: 'pause()' },
14
+ { code: 'cy.get(\'button\').dblclick()' },
15
15
  ],
16
16
 
17
17
  invalid: [
18
- { code: `cy.pause()`, errors },
19
- { code: `cy.pause({ log: false })`, errors },
20
- { code: `cy.get('button').pause()`, errors },
21
- { code: `cy.get('a').should('have.attr', 'href').and('match', /dashboard/).pause()`, errors }
18
+ { code: 'cy.pause()', errors },
19
+ { code: 'cy.pause({ log: false })', errors },
20
+ { code: 'cy.get(\'button\').pause()', errors },
21
+ { code: 'cy.get(\'a\').should(\'have.attr\', \'href\').and(\'match\', /dashboard/).pause()', errors },
22
22
  ],
23
23
  })
@@ -1,30 +1,30 @@
1
- "use strict";
1
+ 'use strict'
2
2
 
3
- //------------------------------------------------------------------------------
3
+ // ------------------------------------------------------------------------------
4
4
  // Requirements
5
- //------------------------------------------------------------------------------
5
+ // ------------------------------------------------------------------------------
6
6
 
7
- const rule = require("../../../lib/rules/no-xpath"),
8
- RuleTester = require("eslint").RuleTester;
7
+ const rule = require('../../../lib/rules/no-xpath'),
8
+ RuleTester = require('eslint').RuleTester
9
9
 
10
- //------------------------------------------------------------------------------
10
+ // ------------------------------------------------------------------------------
11
11
  // Tests
12
- //------------------------------------------------------------------------------
12
+ // ------------------------------------------------------------------------------
13
13
 
14
- const ruleTester = new RuleTester();
15
- ruleTester.run("no-xpath", rule, {
14
+ const ruleTester = new RuleTester()
15
+ ruleTester.run('no-xpath', rule, {
16
16
  valid: [
17
17
  { code: 'cy.get("button").click({force: true})' },
18
18
  ],
19
19
 
20
20
  invalid: [
21
21
  {
22
- code: "cy.xpath('//div[@class=\"container\"]/p[1]').click()",
23
- errors: [{ messageId: "unexpected" }],
22
+ code: 'cy.xpath(\'//div[@class="container"]/p[1]\').click()',
23
+ errors: [{ messageId: 'unexpected' }],
24
24
  },
25
25
  {
26
- code: "cy.xpath('//p[1]').should('exist')",
27
- errors: [{ messageId: "unexpected" }]
28
- }
26
+ code: 'cy.xpath(\'//p[1]\').should(\'exist\')',
27
+ errors: [{ messageId: 'unexpected' }],
28
+ },
29
29
  ],
30
- });
30
+ })
@@ -10,7 +10,7 @@ const errors = [{ messageId: 'unexpected' }]
10
10
  ruleTester.run('action-ends-chain', rule, {
11
11
  valid: [
12
12
  {
13
- code: 'cy.get("new-todo").type("todo A{enter}"); cy.get("new-todo").type("todo B{enter}"); cy.get("new-todo").should("have.class", "active");'
13
+ code: 'cy.get("new-todo").type("todo A{enter}"); cy.get("new-todo").type("todo B{enter}"); cy.get("new-todo").should("have.class", "active");',
14
14
  },
15
15
  { code: 'cy.focused().should("be.visible");' },
16
16
  { code: 'cy.submitBtn().click();' },
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ['**/tests/**/*.[jt]s?(x)'],
6
+ globals: true
7
+ },
8
+ })
package/jest.config.js DELETED
@@ -1,6 +0,0 @@
1
- const { defaults } = require('jest-config')
2
-
3
- module.exports = {
4
- testMatch: ['**/tests/**/*.[jt]s?(x)'],
5
- testPathIgnorePatterns: [...defaults.testPathIgnorePatterns, '.history'],
6
- }