Repository: cypress-io/eslint-plugin-cypress
Pull request #7 (2018-10-29 21:16:14)

Add `no-unnecessary-waiting` rule
Based on the [best practice](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting) and what I think was originally suggested in #4. Will error if calling `cy.get` with a number literal. Also adds this rule to the default recommended set of this plugin.

Based on #6, will refactor/rebase if any changes are needed there. I can also move the base stuff (set up a recommended config, test tools, etc.) to its own PR if it would be easier.

---

#### Example:

```js
// cypress/.eslintrc.js
module.exports = {
  plugins: ['cypress'],
  extends: 'plugin:cypress/recommended',
  env: {
    'cypress/globals': true
  }
}
```
```js
// cypress/test.js
describe('something', () => {
  it('might do a thing', () => {
    cy.visit('/');
    cy.wait(1000);
  });
});
```

```shell
$ yarn run eslint cypress/test.js

./cypress/test.js
  4:5  error  Do not wait for arbitrary time periods  cypress/no-unnecessary-waiting

✖ 1 problem (1 error, 0 warnings)
```


Patch:
diff --git a/README.md b/README.md
index 315532c..75c705a 100644
--- a/README.md
+++ b/README.md
@@ -46,6 +46,7 @@ rules which have a wrench (🔧) below.
 |    | Rule ID | Description |
 |:---|:--------|:------------|
 | ✅ | [no-assigning-return-values](./docs/rules/no-assigning-return-values.md) | Prevent assigning return values of cy calls |
+| ✅ | [no-unnecessary-waiting](./docs/rules/no-unnecessary-waiting.md) | Prevent waiting for arbitrary time periods |
 
 ## Chai and `no-unused-expressions`
 
diff --git a/docs/rules/no-unnecessary-waiting.md b/docs/rules/no-unnecessary-waiting.md
new file mode 100644
index 0000000..d462633
--- /dev/null
+++ b/docs/rules/no-unnecessary-waiting.md
@@ -0,0 +1,3 @@
+## No Assigning Return Values
+
+See [the Cypress Best Practices guide](https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting).
diff --git a/index.js b/index.js
index 8cdcca9..84788c5 100644
--- a/index.js
+++ b/index.js
@@ -3,6 +3,7 @@ const globals = require('globals')
 module.exports = {
   rules: {
     'no-assigning-return-values': require('./lib/rules/no-assigning-return-values'),
+    'no-unnecessary-waiting': require('./lib/rules/no-unnecessary-waiting'),
   },
   configs: {
     recommended: require('./lib/config/recommended'),
diff --git a/lib/config/recommended.js b/lib/config/recommended.js
index 9281ca6..a5f8030 100644
--- a/lib/config/recommended.js
+++ b/lib/config/recommended.js
@@ -3,6 +3,7 @@
 module.exports = {
   plugins: ['cypress'],
   rules: {
-    'cypress/no-assigning-return-values': 'error'
+    'cypress/no-assigning-return-values': 'error',
+    'cypress/no-unnecessary-waiting': 'error'
   }
 };
diff --git a/lib/rules/no-unnecessary-waiting.js b/lib/rules/no-unnecessary-waiting.js
new file mode 100644
index 0000000..45b8e7e
--- /dev/null
+++ b/lib/rules/no-unnecessary-waiting.js
@@ -0,0 +1,44 @@
+/**
+ * @fileoverview Prevent waiting for arbitrary time periods
+ * @author Elad Shahar
+ */
+
+'use strict';
+
+module.exports = {
+  meta: {
+    docs: {
+      description: 'Prevent waiting for arbitrary time periods',
+      category: 'Possible Errors',
+      recommended: true,
+      url: 'https://docs.cypress.io/guides/references/best-practices.html#Unnecessary-Waiting'
+    },
+    schema: [],
+    messages: {
+      unexpected: 'Do not wait for arbitrary time periods'
+    }
+  },
+  create(context) {
+    return {
+      CallExpression(node) {
+        if (isCallingCyWait(node) && isNumberArgument(node)) {
+          context.report({ node, messageId: 'unexpected' });
+        }
+      }
+    };
+  }
+};
+
+function isCallingCyWait(node) {
+  return node.callee.type === 'MemberExpression' &&
+         node.callee.object.type === 'Identifier' &&
+         node.callee.object.name === 'cy' &&
+         node.callee.property.type === 'Identifier' &&
+         node.callee.property.name === 'wait';
+}
+
+function isNumberArgument(node) {
+  return node.arguments.length > 0 &&
+         node.arguments[0].type === 'Literal' &&
+         typeof(node.arguments[0].value) === 'number';
+}


Test patch:
diff --git a/tests/lib/rules/no-unnecessary-waiting.js b/tests/lib/rules/no-unnecessary-waiting.js
new file mode 100644
index 0000000..a7ad8bf
--- /dev/null
+++ b/tests/lib/rules/no-unnecessary-waiting.js
@@ -0,0 +1,28 @@
+"use strict";
+
+const rule = require('../../../lib/rules/no-unnecessary-waiting');
+const RuleTester = require('eslint').RuleTester;
+
+const ruleTester = new RuleTester();
+
+const errors = [{ messageId: 'unexpected' }];
+const parserOptions = { ecmaVersion: 6 };
+
+ruleTester.run('no-unnecessary-waiting', rule, {
+  valid: [
+    { code: 'cy.wait("@someRequest")', parserOptions },
+    { code: 'cy.wait("@someRequest", { log: false })', parserOptions },
+    { code: 'cy.wait("@someRequest").then((xhr) => xhr)', parserOptions },
+    { code: 'cy.wait(["@someRequest", "@anotherRequest"])', parserOptions },
+
+    { code: 'cy.clock(5000)', parserOptions},
+    { code: 'cy.scrollTo(0, 10)', parserOptions },
+    { code: 'cy.tick(500)', parserOptions }
+  ],
+
+  invalid: [
+    { code: 'cy.wait(0)', parserOptions, errors },
+    { code: 'cy.wait(100)', parserOptions, errors },
+    { code: 'cy.wait(5000)', parserOptions, errors }
+  ]
+});