diff --git a/lib/rule-tester/rule-tester.js b/lib/rule-tester/rule-tester.js index 3e391576716..905f3418121 100644 --- a/lib/rule-tester/rule-tester.js +++ b/lib/rule-tester/rule-tester.js @@ -861,6 +861,16 @@ class RuleTester { ); } + // Rules that produce fixes must have `meta.fixable` property. + if (result.output !== item.code) { + assert.ok( + hasOwnProperty(rule, "meta"), + "Fixable rules should export a `meta.fixable` property." + ); + + // Linter throws if a rule that produced a fix has `meta` but doesn't have `meta.fixable`. + } + assertASTDidntChange(result.beforeAST, result.afterAST); } diff --git a/tests/fixtures/testers/rule-tester/no-var.js b/tests/fixtures/testers/rule-tester/no-var.js index 382885613d2..5841f15bfa1 100644 --- a/tests/fixtures/testers/rule-tester/no-var.js +++ b/tests/fixtures/testers/rule-tester/no-var.js @@ -7,27 +7,31 @@ // Rule Definition //------------------------------------------------------------------------------ -module.exports = function(context) { - - "use strict"; - - - var sourceCode = context.getSourceCode(); - - return { - - "VariableDeclaration": function(node) { - if (node.kind === "var") { - context.report({ - node: node, - loc: sourceCode.getFirstToken(node).loc, - message: "Bad var.", - fix: function(fixer) { - return fixer.remove(sourceCode.getFirstToken(node)); - } - }) +"use strict"; + +module.exports = { + + meta: { + fixable: "code" + }, + + create(context) { + + var sourceCode = context.getSourceCode(); + + return { + "VariableDeclaration": function(node) { + if (node.kind === "var") { + context.report({ + node: node, + loc: sourceCode.getFirstToken(node).loc, + message: "Bad var.", + fix: function(fixer) { + return fixer.remove(sourceCode.getFirstToken(node)); + } + }) + } } - } - }; - + }; + } }; diff --git a/tests/lib/rule-tester/rule-tester.js b/tests/lib/rule-tester/rule-tester.js index 7e26e1a826c..3f2393621b6 100644 --- a/tests/lib/rule-tester/rule-tester.js +++ b/tests/lib/rule-tester/rule-tester.js @@ -304,6 +304,10 @@ describe("RuleTester", () => { it("should use strict equality to compare output", () => { const replaceProgramWith5Rule = { + meta: { + fixable: "code" + }, + create: context => ({ Program(node) { context.report({ node, message: "bad", fix: fixer => fixer.replaceText(node, "5") }); @@ -1237,6 +1241,73 @@ describe("RuleTester", () => { }, "Error must specify 'messageId' if 'data' is used."); }); + // fixable rules with or without `meta` property + it("should not throw an error if a rule that has `meta.fixable` produces fixes", () => { + const replaceProgramWith5Rule = { + meta: { + fixable: "code" + }, + create(context) { + return { + Program(node) { + context.report({ node, message: "bad", fix: fixer => fixer.replaceText(node, "5") }); + } + }; + } + }; + + ruleTester.run("replaceProgramWith5", replaceProgramWith5Rule, { + valid: [], + invalid: [ + { code: "var foo = bar;", output: "5", errors: 1 } + ] + }); + }); + it("should throw an error if a new-format rule that doesn't have `meta` produces fixes", () => { + const replaceProgramWith5Rule = { + create(context) { + return { + Program(node) { + context.report({ node, message: "bad", fix: fixer => fixer.replaceText(node, "5") }); + } + }; + } + }; + + assert.throws(() => { + ruleTester.run("replaceProgramWith5", replaceProgramWith5Rule, { + valid: [], + invalid: [ + { code: "var foo = bar;", output: "5", errors: 1 } + ] + }); + }, "Fixable rules should export a `meta.fixable` property."); + }); + it("should throw an error if a legacy-format rule produces fixes", () => { + + /** + * Legacy-format rule (a function instead of an object with `create` method). + * @param {RuleContext} context The ESLint rule context object. + * @returns {Object} Listeners. + */ + function replaceProgramWith5Rule(context) { + return { + Program(node) { + context.report({ node, message: "bad", fix: fixer => fixer.replaceText(node, "5") }); + } + }; + } + + assert.throws(() => { + ruleTester.run("replaceProgramWith5", replaceProgramWith5Rule, { + valid: [], + invalid: [ + { code: "var foo = bar;", output: "5", errors: 1 } + ] + }); + }, "Fixable rules should export a `meta.fixable` property."); + }); + describe("suggestions", () => { it("should pass with valid suggestions (tested using desc)", () => { ruleTester.run("suggestions-basic", require("../../fixtures/testers/rule-tester/suggestions").basic, {