From 4ea8bffe68e41fde0f46df6a299af2311c25093e Mon Sep 17 00:00:00 2001 From: Bryan Mishkin <698306+bmish@users.noreply.github.com> Date: Sat, 26 Jun 2021 11:06:58 -0400 Subject: [PATCH] breaking: rename `consistent-output` rule to `require-test-output` Changes the default rule behavior to always require a test `output` assertion. The old default behavior of `consistent` (only require `output` assertions if some tests have it) is still provided as an available option. * [As of ESLint 7](https://eslint.org/docs/user-guide/migrating-to-7.0.0#additional-validation-added-to-the-ruletester-class), the `output` property is required for test cases that provide an autofix * And even when test cases don't autofix, it's still best practice to assert that there's no autofix with `output: null` --- README.md | 2 +- ...stent-output.md => require-test-output.md} | 21 ++-- ...stent-output.js => require-test-output.js} | 22 +++- tests/lib/rules/consistent-output.js | 113 ----------------- tests/lib/rules/fixer-return.js | 12 ++ tests/lib/rules/no-missing-placeholders.js | 7 ++ tests/lib/rules/no-unused-placeholders.js | 4 + tests/lib/rules/prefer-placeholders.js | 4 + tests/lib/rules/prefer-replace-text.js | 5 + tests/lib/rules/require-meta-fixable.js | 8 ++ tests/lib/rules/require-meta-type.js | 8 ++ tests/lib/rules/require-test-output.js | 115 ++++++++++++++++++ 12 files changed, 188 insertions(+), 133 deletions(-) rename docs/rules/{consistent-output.md => require-test-output.md} (52%) rename lib/rules/{consistent-output.js => require-test-output.js} (70%) delete mode 100644 tests/lib/rules/consistent-output.js create mode 100644 tests/lib/rules/require-test-output.js diff --git a/README.md b/README.md index a78fc8c2..35504916 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,6 @@ Then configure the rules you want to use under the rules section. Name | ✔️ | 🛠 | 💡 | Description ----- | ----- | ----- | ----- | ----- -[consistent-output](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/consistent-output.md) | | | | enforce consistent use of `output` assertions in rule tests [fixer-return](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/fixer-return.md) | ✔️ | | | require fixer functions to return a fix [meta-property-ordering](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/meta-property-ordering.md) | | 🛠 | | enforce the order of meta properties [no-deprecated-context-methods](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/no-deprecated-context-methods.md) | | 🛠 | | disallow usage of deprecated methods on rule context objects @@ -68,6 +67,7 @@ Name | ✔️ | 🛠 | 💡 | Description [require-meta-has-suggestions](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-has-suggestions.md) | | 🛠 | | require suggestable rules to implement a `meta.hasSuggestions` property [require-meta-schema](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-schema.md) | | 🛠 | | require rules to implement a `meta.schema` property [require-meta-type](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-meta-type.md) | | | | require rules to implement a `meta.type` property +[require-test-output](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/require-test-output.md) | | | | enforce use of `output` assertions in rule tests [test-case-property-ordering](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/test-case-property-ordering.md) | | 🛠 | | require the properties of a test case to be placed in a consistent order [test-case-shorthand-strings](https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/test-case-shorthand-strings.md) | | 🛠 | | enforce consistent usage of shorthand strings for test cases with no options diff --git a/docs/rules/consistent-output.md b/docs/rules/require-test-output.md similarity index 52% rename from docs/rules/consistent-output.md rename to docs/rules/require-test-output.md index 72db0bcc..ad5f5af0 100644 --- a/docs/rules/consistent-output.md +++ b/docs/rules/require-test-output.md @@ -1,19 +1,19 @@ -# Enforce consistent use of `output` assertions in rule tests (consistent-output) +# Enforce use of `output` assertions in rule tests (require-test-output) -When writing tests for a fixable rule with `RuleTester`, you can assert the autofix output of your test cases. However, it can be easy to forget to assert the output of a particular test case. +When writing tests for a fixable rule with `RuleTester`, you can assert the autofix `output` of your test cases. [As of ESLint 7](https://eslint.org/docs/user-guide/migrating-to-7.0.0#additional-validation-added-to-the-ruletester-class), test cases that trigger an autofix are required to provide the `output` property. -Even test that do not trigger an autofix can benefit from asserting that they have no autofix using `output: null`. +However, it can be easy to forget to assert the output of a particular test case, leading to the autofix being untested. And even tests that do not trigger an autofix can benefit from asserting that they have no autofix using `output: null`. ## Rule Details -This rule aims to ensure that if any invalid test cases have output assertions, then all test cases have output assertions. +This rule ensures all invalid test cases have `output` assertions. Examples of **incorrect** code for this rule: ```js -/* eslint eslint-plugin/consistent-output: error */ +/* eslint eslint-plugin/require-test-output: error */ new RuleTester().run('example-rule', rule, { valid: [], @@ -34,7 +34,7 @@ new RuleTester().run('example-rule', rule, { Examples of **correct** code for this rule: ```js -/* eslint eslint-plugin/consistent-output: error */ +/* eslint eslint-plugin/require-test-output: error */ new RuleTester().run('example-rule', rule, { valid: [], @@ -60,14 +60,9 @@ new RuleTester().run('example-rule', rule, { ## Options -This rule takes an optional string enum option with one of the following values: +This rule takes an optional object containing: -* `"consistent"` - (default) if any invalid test cases have output assertions, then all invalid test cases must have output assertions -* `"always"` - always require invalid test cases to have output assertions - -## When Not To Use It - -If you're not writing fixable rules, or you want to write test cases without output assertions, do not enable this rule. +* `boolean` -- `consistent` -- only require `output` assertions when some test cases have them (default `false`) ## Further Reading diff --git a/lib/rules/consistent-output.js b/lib/rules/require-test-output.js similarity index 70% rename from lib/rules/consistent-output.js rename to lib/rules/require-test-output.js index aee28ad8..8cb505b4 100644 --- a/lib/rules/consistent-output.js +++ b/lib/rules/require-test-output.js @@ -1,5 +1,5 @@ /** - * @fileoverview Enforce consistent use of `output` assertions in rule tests + * @fileoverview Enforce use of `output` assertions in rule tests * @author Teddy Katz */ @@ -15,24 +15,34 @@ module.exports = { meta: { type: 'suggestion', docs: { - description: 'enforce consistent use of `output` assertions in rule tests', + description: 'enforce use of `output` assertions in rule tests', category: 'Tests', recommended: false, }, fixable: null, // or "code" or "whitespace" schema: [ { - type: 'string', - enum: ['always', 'consistent'], + type: 'object', + properties: { + consistent: { + type: 'boolean', + default: false, + }, + }, + additionalProperties: false, }, ], + messages: { + missingOutput: 'This test case should have an `output` assertion.', + }, }, create (context) { // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- - const always = context.options[0] && context.options[0] === 'always'; + const consistent = context.options[0] && context.options[0].consistent; + const always = !consistent; return { Program (ast) { @@ -48,7 +58,7 @@ module.exports = { casesWithoutOutput.forEach(testCase => { context.report({ node: testCase, - message: 'This test case should have an output assertion.', + messageId: 'missingOutput', }); }); } diff --git a/tests/lib/rules/consistent-output.js b/tests/lib/rules/consistent-output.js deleted file mode 100644 index 7cbd04cb..00000000 --- a/tests/lib/rules/consistent-output.js +++ /dev/null @@ -1,113 +0,0 @@ -/** - * @fileoverview Enforce consistent use of `output` assertions in rule tests - * @author Teddy Katz - */ - -'use strict'; - -// ------------------------------------------------------------------------------ -// Requirements -// ------------------------------------------------------------------------------ - -const rule = require('../../../lib/rules/consistent-output'); -const RuleTester = require('eslint').RuleTester; - -const ERROR = { message: 'This test case should have an output assertion.', type: 'ObjectExpression' }; - -// ------------------------------------------------------------------------------ -// Tests -// ------------------------------------------------------------------------------ - -const ruleTester = new RuleTester(); -ruleTester.run('consistent-output', rule, { - valid: [ - ` - new RuleTester().run('foo', bar, { - valid: [], - invalid: [ - { - code: 'foo', - errors: ['bar'] - }, - { - code: 'baz', - errors: ['qux'] - } - ] - }); - `, - ` - new RuleTester().run('foo', bar, { - valid: [], - invalid: [ - { - code: 'foo', - output: 'baz', - errors: ['bar'], - }, - { - code: 'foo', - output: 'qux', - errors: ['bar'] - } - ] - }); - `, - { - code: ` - new RuleTester().run('foo', bar, { - valid: [], - invalid: [ - { - code: 'foo', - output: 'baz', - errors: ['bar'] - }, - ] - }); - `, - options: ['always'], - }, - ], - - invalid: [ - { - code: ` - new RuleTester().run('foo', bar, { - valid: [], - invalid: [ - { - code: 'foo', - output: 'baz', - errors: ['bar'], - }, - { - code: 'foo', - errors: ['bar'] - }, - { - code: 'foo bar', - errors: ['bar'] - } - ] - }); - `, - errors: [ERROR, ERROR], - }, - { - code: ` - new RuleTester().run('foo', bar, { - valid: [], - invalid: [ - { - code: 'foo', - errors: ['bar'], - }, - ] - }); - `, - options: ['always'], - errors: [ERROR], - }, - ], -}); diff --git a/tests/lib/rules/fixer-return.js b/tests/lib/rules/fixer-return.js index 11cf7ab6..3bc2688f 100644 --- a/tests/lib/rules/fixer-return.js +++ b/tests/lib/rules/fixer-return.js @@ -237,6 +237,7 @@ ruleTester.run('fixer-return', rule, { } }; `, + output: null, errors: [{ messageId: 'missingFix', type: 'FunctionExpression', line: 5, column: 24 }], }, { @@ -252,6 +253,7 @@ ruleTester.run('fixer-return', rule, { } }; `, + output: null, errors: [{ messageId: 'missingFix', type: 'ArrowFunctionExpression', line: 5, endLine: 5, column: 34, endColumn: 36 }], }, { @@ -267,6 +269,7 @@ ruleTester.run('fixer-return', rule, { } }; `, + output: null, errors: [{ messageId: 'missingFix', type: 'ArrowFunctionExpression', line: 5, endLine: 5, column: 34, endColumn: 36 }], }, { @@ -280,6 +283,7 @@ ruleTester.run('fixer-return', rule, { } }; `, + output: null, errors: [{ messageId: 'missingFix', type: 'ArrowFunctionExpression', line: 5, endLine: 5, column: 32, endColumn: 34 }], }, { @@ -295,6 +299,7 @@ ruleTester.run('fixer-return', rule, { } }; `, + output: null, errors: [{ messageId: 'missingFix', type: 'FunctionExpression', line: 5, column: 25 }], }, { @@ -310,6 +315,7 @@ ruleTester.run('fixer-return', rule, { } }; `, + output: null, errors: [{ messageId: 'missingFix', type: 'FunctionExpression', line: 5, column: 25 }], }, { @@ -325,6 +331,7 @@ ruleTester.run('fixer-return', rule, { } }; `, + output: null, errors: [{ messageId: 'missingFix', type: 'FunctionExpression', line: 5, column: 26 }], }, { @@ -340,6 +347,7 @@ ruleTester.run('fixer-return', rule, { } }; `, + output: null, errors: [{ messageId: 'missingFix', type: 'FunctionExpression', line: 5, column: 26 }], }, { @@ -356,6 +364,7 @@ ruleTester.run('fixer-return', rule, { } }; `, + output: null, errors: [{ messageId: 'missingFix', type: 'FunctionExpression', line: 5, column: 26 }], }, { @@ -371,6 +380,7 @@ ruleTester.run('fixer-return', rule, { } }; `, + output: null, errors: [{ messageId: 'missingFix', type: 'FunctionExpression', line: 5, column: 26 }], }, { @@ -386,6 +396,7 @@ ruleTester.run('fixer-return', rule, { } }; `, + output: null, errors: [{ messageId: 'missingFix', type: 'FunctionExpression', line: 5, column: 26 }], }, { @@ -400,6 +411,7 @@ ruleTester.run('fixer-return', rule, { } }; `, + output: null, errors: [{ messageId: 'missingFix', type: 'FunctionExpression', line: 5, column: 26 }], }, ], diff --git a/tests/lib/rules/no-missing-placeholders.js b/tests/lib/rules/no-missing-placeholders.js index 09b8ce36..722caa73 100644 --- a/tests/lib/rules/no-missing-placeholders.js +++ b/tests/lib/rules/no-missing-placeholders.js @@ -142,6 +142,7 @@ ruleTester.run('no-missing-placeholders', rule, { } }; `, + output: null, errors: [error('bar')], }, { @@ -156,6 +157,7 @@ ruleTester.run('no-missing-placeholders', rule, { } }; `, + output: null, errors: [error('bar')], }, { @@ -170,6 +172,7 @@ ruleTester.run('no-missing-placeholders', rule, { } }; `, + output: null, errors: [error('hasOwnProperty')], }, { @@ -178,6 +181,7 @@ ruleTester.run('no-missing-placeholders', rule, { context.report(node, 'foo {{bar}}', { baz: 'qux' }); }; `, + output: null, errors: [error('bar')], }, { @@ -188,6 +192,7 @@ ruleTester.run('no-missing-placeholders', rule, { context.report(node, MESSAGE, { baz: 'qux' }); }; `, + output: null, errors: [error('bar', 'Identifier')], }, { @@ -196,6 +201,7 @@ ruleTester.run('no-missing-placeholders', rule, { context.report(node, { line: 1, column: 3 }, 'foo {{bar}}', { baz: 'baz' }); }; `, + output: null, errors: [error('bar')], }, { @@ -210,6 +216,7 @@ ruleTester.run('no-missing-placeholders', rule, { } }; `, + output: null, errors: [error('bar')], }, ], diff --git a/tests/lib/rules/no-unused-placeholders.js b/tests/lib/rules/no-unused-placeholders.js index 4646de9f..8b7a93f9 100644 --- a/tests/lib/rules/no-unused-placeholders.js +++ b/tests/lib/rules/no-unused-placeholders.js @@ -122,6 +122,7 @@ ruleTester.run('no-unused-placeholders', rule, { } }; `, + output: null, errors: [error('bar')], }, { @@ -138,6 +139,7 @@ ruleTester.run('no-unused-placeholders', rule, { } }; `, + output: null, errors: [error('bar', 'Identifier')], }, { @@ -152,6 +154,7 @@ ruleTester.run('no-unused-placeholders', rule, { } }; `, + output: null, errors: [error('bar')], }, { @@ -166,6 +169,7 @@ ruleTester.run('no-unused-placeholders', rule, { } }; `, + output: null, errors: [error('baz')], }, ], diff --git a/tests/lib/rules/prefer-placeholders.js b/tests/lib/rules/prefer-placeholders.js index e3093823..a5c1806a 100644 --- a/tests/lib/rules/prefer-placeholders.js +++ b/tests/lib/rules/prefer-placeholders.js @@ -92,6 +92,7 @@ ruleTester.run('prefer-placeholders', rule, { } }; `, + output: null, errors: [ERROR], }, { @@ -107,6 +108,7 @@ ruleTester.run('prefer-placeholders', rule, { } }; `, + output: null, errors: [ERROR], }, { @@ -120,6 +122,7 @@ ruleTester.run('prefer-placeholders', rule, { } }; `, + output: null, errors: [ERROR], }, { @@ -130,6 +133,7 @@ ruleTester.run('prefer-placeholders', rule, { } }; `, + output: null, errors: [ERROR], }, ], diff --git a/tests/lib/rules/prefer-replace-text.js b/tests/lib/rules/prefer-replace-text.js index 3402196c..314991ea 100644 --- a/tests/lib/rules/prefer-replace-text.js +++ b/tests/lib/rules/prefer-replace-text.js @@ -67,6 +67,7 @@ ruleTester.run('prefer-placeholders', rule, { } }; `, + output: null, errors: [ERROR], }, { @@ -81,6 +82,7 @@ ruleTester.run('prefer-placeholders', rule, { } }; `, + output: null, errors: [ERROR], }, { @@ -95,6 +97,7 @@ ruleTester.run('prefer-placeholders', rule, { } }; `, + output: null, errors: [ERROR], }, { @@ -107,6 +110,7 @@ ruleTester.run('prefer-placeholders', rule, { } }; `, + output: null, errors: [ERROR], }, { @@ -121,6 +125,7 @@ ruleTester.run('prefer-placeholders', rule, { } }; `, + output: null, errors: [ERROR], }, ], diff --git a/tests/lib/rules/require-meta-fixable.js b/tests/lib/rules/require-meta-fixable.js index f9aa6b3b..3758c043 100644 --- a/tests/lib/rules/require-meta-fixable.js +++ b/tests/lib/rules/require-meta-fixable.js @@ -142,6 +142,7 @@ ruleTester.run('require-meta-fixable', rule, { create(context) { context.report({node, message, fix: foo}); } }; `, + output: null, errors: [{ messageId: 'missing', type: 'ObjectExpression' }], }, { @@ -150,6 +151,7 @@ ruleTester.run('require-meta-fixable', rule, { create(context) { context.report({node, message, fix: foo}); } }; `, + output: null, errors: [{ messageId: 'missing', type: 'FunctionExpression' }], }, { @@ -159,6 +161,7 @@ ruleTester.run('require-meta-fixable', rule, { create(context) { context.report(node, loc, message, data, fix); } }; `, + output: null, errors: [{ messageId: 'missing', type: 'ObjectExpression' }], }, { @@ -168,6 +171,7 @@ ruleTester.run('require-meta-fixable', rule, { create(context) { context.report({node, message}); } }; `, + output: null, errors: [{ messageId: 'invalid', type: 'Literal' }], }, { @@ -177,6 +181,7 @@ ruleTester.run('require-meta-fixable', rule, { create(context) { context.report({node, message, fix: foo}); } }; `, + output: null, errors: [{ messageId: 'invalid', type: 'Literal' }], }, { @@ -187,6 +192,7 @@ ruleTester.run('require-meta-fixable', rule, { create(context) { context.report({node, message, fix: foo}); } }; `, + output: null, errors: [{ messageId: 'invalid', type: 'Identifier' }], }, { @@ -196,6 +202,7 @@ ruleTester.run('require-meta-fixable', rule, { create(context) { context.report({node, message, fix: foo}); } }; `, + output: null, errors: [{ messageId: 'missing', type: 'Literal' }], }, { @@ -205,6 +212,7 @@ ruleTester.run('require-meta-fixable', rule, { create(context) { context.report({node, message, fix: foo}); } }; `, + output: null, errors: [{ messageId: 'missing', type: 'Identifier' }], }, ], diff --git a/tests/lib/rules/require-meta-type.js b/tests/lib/rules/require-meta-type.js index 25ca0992..8dbf832a 100644 --- a/tests/lib/rules/require-meta-type.js +++ b/tests/lib/rules/require-meta-type.js @@ -79,6 +79,7 @@ ruleTester.run('require-meta-type', rule, { create(context) {} }; `, + output: null, errors: [{ messageId: 'missing', type: 'ObjectExpression' }], }, { @@ -89,6 +90,7 @@ ruleTester.run('require-meta-type', rule, { create, }; `, + output: null, errors: [{ messageId: 'missing', type: 'ObjectExpression' }], }, { @@ -99,6 +101,7 @@ ruleTester.run('require-meta-type', rule, { create, }; `, + output: null, errors: [{ messageId: 'missing', type: 'ObjectExpression' }], }, { @@ -109,6 +112,7 @@ ruleTester.run('require-meta-type', rule, { create, }; `, + output: null, errors: [{ messageId: 'missing', type: 'ObjectExpression' }], }, { @@ -118,6 +122,7 @@ ruleTester.run('require-meta-type', rule, { create(context) {} }; `, + output: null, errors: [{ messageId: 'unexpected', type: 'Literal' }], }, { @@ -128,6 +133,7 @@ ruleTester.run('require-meta-type', rule, { create(context) {} }; `, + output: null, errors: [{ messageId: 'unexpected', type: 'Identifier' }], }, { @@ -137,6 +143,7 @@ ruleTester.run('require-meta-type', rule, { create(context) {} }; `, + output: null, errors: [{ messageId: 'unexpected', type: 'Literal' }], }, { @@ -146,6 +153,7 @@ ruleTester.run('require-meta-type', rule, { create(context) {} }; `, + output: null, errors: [{ messageId: 'unexpected', type: 'Identifier' }], }, ], diff --git a/tests/lib/rules/require-test-output.js b/tests/lib/rules/require-test-output.js new file mode 100644 index 00000000..142f8b81 --- /dev/null +++ b/tests/lib/rules/require-test-output.js @@ -0,0 +1,115 @@ +'use strict'; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const rule = require('../../../lib/rules/require-test-output'); +const RuleTester = require('eslint').RuleTester; + +const ERROR = { messageId: 'missingOutput', type: 'ObjectExpression' }; + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester(); +ruleTester.run('require-test-output', rule, { + valid: [ + { + // Explicit option of `consistent` (no output in any tests). + code: ` + new RuleTester().run('foo', bar, { + valid: [], + invalid: [ + { code: 'foo', errors: ['bar'] }, + { code: 'baz', errors: ['qux'] } + ] + }); + `, + options: [{ consistent: true }], + }, + { + // Explicit option of `consistent` (output in all tests). + code: ` + new RuleTester().run('foo', bar, { + valid: [], + invalid: [ + { code: 'foo', output: 'baz', errors: ['bar'] }, + { code: 'foo', output: 'qux', errors: ['bar'] }, + ] + }); + `, + options: [{ consistent: true }], + }, + { + // Explicitly turning off the `consistent` option (results in "always" behavior). + code: ` + new RuleTester().run('foo', bar, { + valid: [], + invalid: [ + { code: 'foo', output: 'baz', errors: ['bar'] }, + { code: 'foo', output: 'qux', errors: ['bar'] }, + { code: 'foo', output: null, errors: ['bar'] }, + ] + }); + `, + options: [{ consistent: false }], + }, + // When defaulting to the "always" behavior. + ` + new RuleTester().run('foo', bar, { + valid: [], + invalid: [ + { code: 'foo', output: 'baz', errors: ['bar'] }, + ] + }); + `, + ], + + invalid: [ + { + // Explicit option of `consistent`. + code: ` + new RuleTester().run('foo', bar, { + valid: [], + invalid: [ + { code: 'foo', output: 'baz', errors: ['bar'] }, + { code: 'foo', errors: ['bar'] }, + { code: 'foo bar', errors: ['bar'] }, + ] + }); + `, + output: null, + options: [{ consistent: true }], + errors: [ERROR, ERROR], + }, + { + // Explicitly turning off the `consistent` option (results in "always" behavior). + code: ` + new RuleTester().run('foo', bar, { + valid: [], + invalid: [ + { code: 'foo', errors: ['bar'] }, + ] + }); + `, + output: null, + options: [{ consistent: false }], + errors: [ERROR], + }, + { + // When defaulting to the "always" behavior. + code: ` + new RuleTester().run('foo', bar, { + valid: [], + invalid: [ + { code: 'foo', errors: ['bar'] }, + ] + }); + `, + output: null, + errors: [ERROR], + }, + ], +});