diff --git a/README.md b/README.md index 424d4869..80da4977 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ Name | ✔️ | 🛠 | Description [no-identical-tests](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-identical-tests.md) | | 🛠 | Disallows identical tests [no-missing-placeholders](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-missing-placeholders.md) | ✔️ | | Disallows missing placeholders in rule report messages [no-useless-token-range](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-useless-token-range.md) | ✔️ | 🛠 | Disallows unnecessary calls to sourceCode.getFirstToken and sourceCode.getLastToken +[prefer-output-null](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-output-null.md) | | | Disallows invalid RuleTester test cases with the output the same as the code. [prefer-placeholders](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/prefer-placeholders.md) | | | Disallows template literals as report messages [report-message-format](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/report-message-format.md) | | | Enforces a consistent format for report messages [require-meta-fixable](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-fixable.md) | ✔️ | | Requires a `meta.fixable` property for fixable rules diff --git a/docs/rules/prefer-output-null.md b/docs/rules/prefer-output-null.md new file mode 100644 index 00000000..3a95b525 --- /dev/null +++ b/docs/rules/prefer-output-null.md @@ -0,0 +1,31 @@ +# Disallows invalid RuleTester test cases with the output the same as the code. (prefer-output-null) + +## Rule Details + +The rule reports an error if it encounters a test case where the output is the same as the code. + +Examples of **incorrect** code for this rule: + +```js +/* eslint eslint-plugin/prefer-output-null: error */ + +new RuleTester().run('foo', bar, { + valid: [], + invalid: [ + { code: 'foo', output: 'foo', errors: [{ message: 'bar' }] }, + ] +}); +``` + +Examples of **correct** code for this rule: + +```js +/* eslint eslint-plugin/prefer-output-null: error */ + +new RuleTester().run('foo', bar, { + valid: [], + invalid: [ + { code: 'foo', output: null, errors: [{ message: 'bar' }] }, + ] +}); +``` diff --git a/lib/rules/prefer-output-null.js b/lib/rules/prefer-output-null.js new file mode 100644 index 00000000..9f31645a --- /dev/null +++ b/lib/rules/prefer-output-null.js @@ -0,0 +1,61 @@ +/** + * @fileoverview disallows invalid RuleTester test cases with the output the same as the code. + * @author 薛定谔的猫 + */ + +'use strict'; + +const utils = require('../utils'); + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: 'disallows invalid RuleTester test cases with the output the same as the code.', + category: 'Tests', + recommended: false, + }, + fixable: null, + schema: [], + }, + + create (context) { + // ---------------------------------------------------------------------- + // Public + // ---------------------------------------------------------------------- + + const message = 'Use `output: null` to assert that a test case is not autofixed.'; + const sourceCode = context.getSourceCode(); + + return { + Program (ast) { + utils.getTestInfo(context, ast).forEach(testRun => { + (testRun.invalid || []).forEach(test => { + /** + * Get a test case's giving keyname node. + * @param {string} the keyname to find. + * @returns {Node} found node; if not found, return null; + */ + function getTestInfo (key) { + const res = test.properties.filter(item => item.key.name === key); + return res.length ? res[res.length - 1] : null; + } + + const code = getTestInfo('code'); + const output = getTestInfo('output'); + + if (output && sourceCode.getText(output.value) === sourceCode.getText(code.value)) { + context.report({ + node: test, + message, + }); + } + }); + }); + }, + }; + }, +}; diff --git a/tests/lib/rules/no-deprecated-report-api.js b/tests/lib/rules/no-deprecated-report-api.js index f0eeafe0..e5e3559b 100644 --- a/tests/lib/rules/no-deprecated-report-api.js +++ b/tests/lib/rules/no-deprecated-report-api.js @@ -124,13 +124,7 @@ ruleTester.run('no-deprecated-report-api', rule, { } }; `, - output: ` - module.exports = { - create(context) { - context.report(theNode, theMessage, theData, theFix); - } - }; - `, + output: null, errors: [ERROR], }, { @@ -175,13 +169,7 @@ ruleTester.run('no-deprecated-report-api', rule, { } }; `, - output: ` - module.exports = { - create(notContext) { - notContext.report(theNode, theMessage, theData, theFix); - } - }; - `, + output: null, errors: [ERROR], }, { @@ -218,13 +206,7 @@ ruleTester.run('no-deprecated-report-api', rule, { } }; `, - output: ` - module.exports = { - create(context) { - context.report(theNode, theLocation, theMessage, theData, theFix, somethingElse, somethingElse, somethingElse); - } - }; - `, + output: null, errors: [ERROR], }, ], diff --git a/tests/lib/rules/prefer-output-null.js b/tests/lib/rules/prefer-output-null.js new file mode 100644 index 00000000..24ee3eae --- /dev/null +++ b/tests/lib/rules/prefer-output-null.js @@ -0,0 +1,55 @@ +/** + * @fileoverview disallows invalid RuleTester test cases with the output the same as the code. + * @author 薛定谔的猫 + */ + +'use strict'; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const rule = require('../../../lib/rules/prefer-output-null'); +const RuleTester = require('eslint').RuleTester; + +const ERROR = { message: 'Use `output: null` to assert that a test case is not autofixed.' }; + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester(); +ruleTester.run('prefer-output-null', rule, { + valid: [ + ` + new RuleTester().run('foo', bar, { + valid: [], + invalid: [ + {code: 'foo', output: 'bar', errors: ['bar']}, + ] + }); + `, + ` + new RuleTester().run('foo', bar, { + valid: [], + invalid: [ + {code: 'foo', output: null, errors: ['bar']}, + ] + }); + `, + ], + + invalid: [ + { + code: ` + new RuleTester().run('foo', bar, { + valid: [], + invalid: [ + {code: 'foo', output: 'foo', errors: ['bar']}, + ] + }); + `, + errors: [ERROR], + }, + ], +});