eslint-plugin-cypress 4.2.1 → 4.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 CHANGED
@@ -48,3 +48,29 @@ This plugin uses the ESLint [eslint-doc-generator](https://www.npmjs.com/package
48
48
 
49
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
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).
51
+
52
+ ## Merging pull requests
53
+
54
+ This information is for Cypress.io Members or Collaborators who merge pull requests:
55
+
56
+ 1. When merging a pull request, use the [Squash and merge](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/about-merge-methods-on-github#squashing-your-merge-commits) option to squash all commits into one.
57
+ 1. Make sure the commit subject and body follow [semantic commit convention](https://semantic-release.gitbook.io/semantic-release/#commit-message-format), for instance:
58
+
59
+ ```text
60
+ feat: added new parameter
61
+ fix: fixed a bug
62
+ ```
63
+
64
+ If you need to bump the major version, mark it as breaking change in the body of the commit's message like:
65
+
66
+ ```text
67
+ fix: upgrade dependency X
68
+
69
+ BREAKING CHANGE: requires minimum Node.js 20 to run
70
+ ```
71
+
72
+ 1. New versions of this module will be released automatically by the CI pipeline when any PR with a triggering commit message is merged to the `master` branch: see the `release` job of [circle.yml](circle.yml).
73
+ This will create a new [GitHub release](https://github.com/cypress-io/eslint-plugin-cypress/releases) and publish it to [eslint-plugin-cypress](https://www.npmjs.com/package/eslint-plugin-cypress) on the [npm registry](https://docs.npmjs.com/about-the-public-npm-registry).
74
+ 1. The module's CI is configured to use the [default Angular release rules](https://github.com/semantic-release/commit-analyzer/blob/master/lib/default-release-rules.js).
75
+ This means that only `feat:`, `fix:` and `perf:` trigger a new release.
76
+ Other Angular commit types listed in the [Angular commit message guidelines](https://github.com/angular/angular/blob/main/contributing-docs/commit-message-guidelines.md) can be used for documentation purposes, however they are ignored by the currently configured release process.
package/README.md CHANGED
@@ -50,6 +50,7 @@ These rules enforce some of the [best practices recommended for using Cypress](h
50
50
  | [no-assigning-return-values](docs/rules/no-assigning-return-values.md) | disallow assigning return values of `cy` calls | ✅ |
51
51
  | [no-async-before](docs/rules/no-async-before.md) | disallow using `async`/`await` in Cypress `before` methods | |
52
52
  | [no-async-tests](docs/rules/no-async-tests.md) | disallow using `async`/`await` in Cypress test cases | ✅ |
53
+ | [no-chained-get](docs/rules/no-chained-get.md) | disallow chain of `cy.get()` calls | |
53
54
  | [no-debug](docs/rules/no-debug.md) | disallow using `cy.debug()` calls | |
54
55
  | [no-force](docs/rules/no-force.md) | disallow using `force: true` with action commands | |
55
56
  | [no-pause](docs/rules/no-pause.md) | disallow using `cy.pause()` calls | |
@@ -0,0 +1,19 @@
1
+ # Disallow chain of `cy.get()` calls (`cypress/no-chained-get`)
2
+
3
+ <!-- end auto-generated rule header -->
4
+ This rule disallows the usage of chained `.get()` calls as `cy.get()` always starts its search from the cy.root element.
5
+
6
+ ## Rule Details
7
+
8
+ Examples of **incorrect** code for this rule:
9
+
10
+ ```js
11
+ cy.get('parent').get('child')
12
+ ```
13
+
14
+ Examples of **correct** code for this rule:
15
+
16
+ ```js
17
+ cy.get('parent')
18
+ .find('child')
19
+ ```
package/legacy.js CHANGED
@@ -13,6 +13,7 @@ module.exports = {
13
13
  'no-pause': require('./lib/rules/no-pause'),
14
14
  'no-debug': require('./lib/rules/no-debug'),
15
15
  'no-xpath': require('./lib/rules/no-xpath'),
16
+ 'no-chained-get': require('./lib/rules/no-chained-get'),
16
17
  },
17
18
  configs: {
18
19
  recommended: require('./lib/config/recommended'),
package/lib/flat.js CHANGED
@@ -16,6 +16,7 @@ const plugin = {
16
16
  'no-pause': require('./rules/no-pause'),
17
17
  'no-debug': require('./rules/no-debug'),
18
18
  'no-xpath': require('./rules/no-xpath'),
19
+ 'no-chained-get': require('./rules/no-chained-get'),
19
20
  },
20
21
  }
21
22
 
@@ -0,0 +1,87 @@
1
+ 'use strict';
2
+
3
+ //------------------------------------------------------------------------------
4
+ // Rule Definition
5
+ //------------------------------------------------------------------------------
6
+
7
+ /** @type {import('eslint').Rule.RuleModule} */
8
+ module.exports = {
9
+ meta: {
10
+ type: 'problem',
11
+ docs: {
12
+ description: 'disallow chain of `cy.get()` calls',
13
+ recommended: false,
14
+ url: 'https://github.com/cypress-io/eslint-plugin-cypress/blob/master/docs/rules/no-chained-get.md',
15
+ },
16
+ fixable: null,
17
+ schema: [],
18
+ messages: {
19
+ unexpected: 'Avoid chaining multiple cy.get() calls',
20
+ },
21
+ },
22
+
23
+ create(context) {
24
+ const isRootCypress = (node) => {
25
+ if (
26
+ node.type !== 'CallExpression' ||
27
+ node.callee.type !== 'MemberExpression'
28
+ ) {
29
+ return false;
30
+ }
31
+
32
+ if (
33
+ node.callee.object.type === 'Identifier' &&
34
+ node.callee.object.name === 'cy'
35
+ ) {
36
+ return true;
37
+ }
38
+
39
+ return isRootCypress(node.callee.object);
40
+ };
41
+
42
+ const hasChainedGet = (node) => {
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';
50
+
51
+ if (!isGetCall) {
52
+ return false;
53
+ }
54
+
55
+ const obj = node.callee.object;
56
+
57
+ if (obj.type === 'CallExpression') {
58
+ const objCallee = obj.callee;
59
+
60
+ if (
61
+ objCallee &&
62
+ objCallee.type === 'MemberExpression' &&
63
+ objCallee.property &&
64
+ objCallee.property.type === 'Identifier' &&
65
+ objCallee.property.name === 'get'
66
+ ) {
67
+ return true;
68
+ }
69
+
70
+ return hasChainedGet(obj);
71
+ }
72
+
73
+ return false;
74
+ };
75
+
76
+ return {
77
+ CallExpression(node) {
78
+ if (isRootCypress(node) && hasChainedGet(node)) {
79
+ context.report({
80
+ node,
81
+ messageId: 'unexpected',
82
+ });
83
+ }
84
+ },
85
+ };
86
+ },
87
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-cypress",
3
- "version": "4.2.1",
3
+ "version": "4.3.0",
4
4
  "description": "An ESLint plugin for projects using Cypress",
5
5
  "main": "legacy.js",
6
6
  "exports": {
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @fileoverview disallow chain of `cy.get()` calls
3
+ * @author benoit
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const rule = require("../../../lib/rules/no-chained-get"),
12
+ RuleTester = require("eslint").RuleTester;
13
+
14
+ //------------------------------------------------------------------------------
15
+ // Tests
16
+ //------------------------------------------------------------------------------
17
+
18
+ const ruleTester = new RuleTester();
19
+ ruleTester.run("no-chained-get", rule, {
20
+ valid: [
21
+ { code: "cy.get('div')" },
22
+ { code: "cy.get('.div').find().get()" },
23
+ { code: "cy.get('input').should('be.disabled')" },
24
+ ],
25
+ invalid: [
26
+ {
27
+ code: "cy.get('div').get('div')",
28
+ errors: [{ messageId: "unexpected" }],
29
+ },
30
+ ],
31
+ });