Repository: lo1tuma/eslint-plugin-mocha
Pull request #112 (2016-10-26 09:38:37)

Make no-mocha-arrows rule fixable
## Summary

I make `no-mocha-arrows` rule fixable with `--fix` option of `eslint` command.
## Example
- Before

``` js
it("does something", () => { assert.ok(true); });
it("does something", () => assert.ok(true));
```
- After

``` js
it("does something", function () { assert.ok(true); });
it("does something", function () { return assert.ok(true); });
```

EDIT: Translation result of single expression body



Patch:
diff --git a/lib/rules/no-mocha-arrows.js b/lib/rules/no-mocha-arrows.js
index 674a884..00ca039 100644
--- a/lib/rules/no-mocha-arrows.js
+++ b/lib/rules/no-mocha-arrows.js
@@ -41,6 +41,38 @@ module.exports = function (context) {
         return !R.find(R.propEq('name', name), scope.variables);
     }
 
+    function fixArrowFunction(fixer, fn) {
+        var sourceCode = context.getSourceCode(),
+            paramsLeftParen = sourceCode.getFirstToken(fn),
+            paramsRightParen = sourceCode.getTokenBefore(sourceCode.getTokenBefore(fn.body)),
+            paramsFullText =
+                sourceCode.text.slice(paramsLeftParen.range[0], paramsRightParen.range[1]),
+            functionKeyword = 'function ',
+            bodyText;
+
+        if (fn.async) {
+            // When 'async' specified, take care about the keyword.
+            functionKeyword = 'async function';
+            // Strip 'async (...)' to ' (...)'
+            paramsFullText = paramsFullText.slice(5);
+        }
+
+        if (fn.body.type === 'BlockStatement') {
+            // When it((...) => { ... }),
+            // simply replace '(...) => ' with 'function () '
+            return fixer.replaceTextRange(
+                [ fn.start, fn.body.start ],
+                functionKeyword + paramsFullText + ' '
+            );
+        }
+
+        bodyText = sourceCode.text.slice(fn.body.range[0], fn.body.range[1]);
+        return fixer.replaceTextRange(
+            [ fn.start, fn.end ],
+            functionKeyword + paramsFullText + ' { return ' + bodyText + '; }'
+        );
+    }
+
     return {
         CallExpression: function (node) {
             var name = getCalleeName(node.callee),
@@ -50,7 +82,13 @@ module.exports = function (context) {
                 fnArg = node.arguments.slice(-1)[0];
                 if (fnArg && fnArg.type === 'ArrowFunctionExpression') {
                     if (isLikelyMochaGlobal(context.getScope(), name)) {
-                        context.report(node, 'Do not pass arrow functions to ' + name + '()');
+                        context.report({
+                            node: node,
+                            message: 'Do not pass arrow functions to ' + name + '()',
+                            fix: function (fixer) {
+                                return fixArrowFunction(fixer, fnArg);
+                            }
+                        });
                     }
                 }
             }


Test patch:
diff --git a/test/rules/no-mocha-arrows.js b/test/rules/no-mocha-arrows.js
index c9c5919..f7a899d 100644
--- a/test/rules/no-mocha-arrows.js
+++ b/test/rules/no-mocha-arrows.js
@@ -2,8 +2,11 @@
 
 var RuleTester = require('eslint').RuleTester,
     rules = require('../../').rules,
-    ruleTester = new RuleTester(),
-    expectedErrorMessage = 'Do not pass arrow functions to it()';
+    ruleTester = new RuleTester({
+        parserOptions: { ecmaVersion: 2017 }
+    }),
+    expectedErrorMessage = 'Do not pass arrow functions to it()',
+    errors = [ { message: expectedErrorMessage, column: 1, line: 1 } ];
 
 ruleTester.run('no-mocha-arrows', rules['no-mocha-arrows'], {
 
@@ -11,40 +14,65 @@ ruleTester.run('no-mocha-arrows', rules['no-mocha-arrows'], {
         'it()',
         'it(function() { assert(something, false); })',
         'it("should be false", function() { assert(something, false); })',
-        {
-            // In this example, `it` is not a global.
-            code: 'function it () {}; it(() => { console.log("okay") })',
-            parserOptions: { ecmaVersion: 6 }
-        },
-        'it.only()'
+         // In this example, `it` is not a global.
+        'function it () {}; it(() => { console.log("okay") })',
+        'it.only()',
+        'it(function(done) { assert(something, false); done(); })',
+        'it(function*() { assert(something, false) })',
+        'it(async function () { assert(something, false) })'
     ],
 
     invalid: [
         {
             code: 'it(() => { assert(something, false); })',
-            parserOptions: { ecmaVersion: 6 },
-            errors: [ { message: expectedErrorMessage, column: 1, line: 1 } ]
+            errors: errors,
+            output: 'it(function () { assert(something, false); })'
         },
         {
             code: 'it(() => { assert(something, false); })',
             globals: [ 'it' ],
-            parserOptions: { ecmaVersion: 6 },
-            errors: [ { message: expectedErrorMessage, column: 1, line: 1 } ]
+            errors: errors,
+            output: 'it(function () { assert(something, false); })'
         },
         {
             code: 'it(() => assert(something, false))',
-            parserOptions: { ecmaVersion: 6 },
-            errors: [ { message: expectedErrorMessage, column: 1, line: 1 } ]
+            errors: errors,
+            output: 'it(function () { return assert(something, false); })'
         },
         {
             code: 'it("should be false", () => { assert(something, false); })',
-            parserOptions: { ecmaVersion: 6 },
-            errors: [ { message: expectedErrorMessage, column: 1, line: 1 } ]
+            errors: errors,
+            output: 'it("should be false", function () { assert(something, false); })'
         },
         {
             code: 'it.only(() => { assert(something, false); })',
-            parserOptions: { ecmaVersion: 6 },
-            errors: [ { message: 'Do not pass arrow functions to it.only()', column: 1, line: 1 } ]
+            errors: [ { message: 'Do not pass arrow functions to it.only()', column: 1, line: 1 } ],
+            output: 'it.only(function () { assert(something, false); })'
+        },
+        {
+            code: 'it((done) => { assert(something, false); })',
+            errors: errors,
+            output: 'it(function (done) { assert(something, false); })'
+        },
+        {
+            code: 'it("should be false", () => {\n assert(something, false);\n})',
+            errors: errors,
+            output: 'it("should be false", function () {\n assert(something, false);\n})'
+        },
+        {
+            code: 'it(async () => { assert(something, false) })',
+            errors: errors,
+            output: 'it(async function () { assert(something, false) })'
+        },
+        {
+            code: 'it(async () => assert(something, false))',
+            errors: errors,
+            output: 'it(async function () { return assert(something, false); })'
+        },
+        {
+            code: 'it(async() => assert(something, false))',
+            errors: errors,
+            output: 'it(async function() { return assert(something, false); })'
         }
     ]