diff --git a/package.json b/package.json index efbbb21a02..08d7c392f9 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ }, "devDependencies": { "@ava/babel": "^1.0.1", + "@babel/code-frame": "7.10.3", "@lubien/fixture-beta-package": "^1.0.0-beta.1", "@typescript-eslint/parser": "^3.4.0", "ava": "^3.9.0", diff --git a/test/consistent-function-scoping.js b/test/consistent-function-scoping.js index 27a60b93ce..e2b4fe1a2d 100644 --- a/test/consistent-function-scoping.js +++ b/test/consistent-function-scoping.js @@ -2,6 +2,7 @@ import test from 'ava'; import avaRuleTester from 'eslint-ava-rule-tester'; import {outdent} from 'outdent'; import rule from '../rules/consistent-function-scoping'; +import visualizeRuleTester from './utils/visualize-rule-tester'; const ruleTester = avaRuleTester(test, { parserOptions: { @@ -647,3 +648,47 @@ typescriptRuleTester.run('consistent-function-scoping', rule, { ], invalid: [] }); + +const visualizeTester = visualizeRuleTester(test, { + parserOptions: { + sourceType: 'module', + ecmaVersion: 2020, + ecmaFeatures: { + jsx: true + } + } +}); + +visualizeTester.run('consistent-function-scoping', rule, [ + outdent` + function foo() { + function bar() {} + } + `, + outdent` + function foo() { + async function bar() {} + } + `, + outdent` + function foo() { + function * bar() {} + } + `, + outdent` + function foo() { + async function * bar() {} + } + `, + outdent` + function foo() { + const bar = () => {} + } + `, + 'const doFoo = () => bar => bar;', + outdent` + function foo() { + const bar = async () => {} + } + ` +]); diff --git a/test/no-useless-undefined.js b/test/no-useless-undefined.js index fec9b03e56..dde5712b8b 100644 --- a/test/no-useless-undefined.js +++ b/test/no-useless-undefined.js @@ -2,6 +2,7 @@ import test from 'ava'; import {outdent} from 'outdent'; import avaRuleTester from 'eslint-ava-rule-tester'; import rule from '../rules/no-useless-undefined'; +import visualizeRuleTester from './utils/visualize-rule-tester'; const messageId = 'no-useless-undefined'; @@ -238,3 +239,25 @@ typescriptRuleTester.run('no-useless-undefined', rule, { ], invalid: [] }); + +const visualizeTester = visualizeRuleTester(test, { + parserOptions: { + ecmaVersion: 2020 + } +}); + +visualizeTester.run('no-useless-undefined', rule, [ + outdent` + foo( + undefined, + bar, + undefined, + undefined, + undefined, + undefined, + ) + `, + 'function foo([bar = undefined] = []) {}', + 'foo(bar, undefined, undefined);', + 'let a = undefined, b = 2;' +]); diff --git a/test/snapshots/consistent-function-scoping.js.md b/test/snapshots/consistent-function-scoping.js.md new file mode 100644 index 0000000000..922552a5c7 --- /dev/null +++ b/test/snapshots/consistent-function-scoping.js.md @@ -0,0 +1,80 @@ +# Snapshot report for `test/consistent-function-scoping.js` + +The actual snapshot is saved in `consistent-function-scoping.js.snap`. + +Generated by [AVA](https://avajs.dev). + +## consistent-function-scoping - #1 + +> Snapshot 1 + + `␊ + 1 | function foo() {␊ + > 2 | function bar() {}␊ + | ^^^^^^^^^^^^ Move function 'bar' to the outer scope.␊ + 3 | }␊ + ` + +## consistent-function-scoping - #2 + +> Snapshot 1 + + `␊ + 1 | function foo() {␊ + > 2 | async function bar() {}␊ + | ^^^^^^^^^^^^^^^^^^ Move async function 'bar' to the outer scope.␊ + 3 | }␊ + ` + +## consistent-function-scoping - #3 + +> Snapshot 1 + + `␊ + 1 | function foo() {␊ + > 2 | function * bar() {}␊ + | ^^^^^^^^^^^^^^ Move generator function 'bar' to the outer scope.␊ + 3 | }␊ + ` + +## consistent-function-scoping - #4 + +> Snapshot 1 + + `␊ + 1 | function foo() {␊ + > 2 | async function * bar() {}␊ + | ^^^^^^^^^^^^^^^^^^^^ Move async generator function 'bar' to the outer scope.␊ + 3 | }␊ + ` + +## consistent-function-scoping - #5 + +> Snapshot 1 + + `␊ + 1 | function foo() {␊ + > 2 | const bar = () => {}␊ + | ^^ Move arrow function 'bar' to the outer scope.␊ + 3 | }␊ + ` + +## consistent-function-scoping - #6 + +> Snapshot 1 + + `␊ + > 1 | const doFoo = () => bar => bar;␊ + | ^^ Move arrow function to the outer scope.␊ + ` + +## consistent-function-scoping - #7 + +> Snapshot 1 + + `␊ + 1 | function foo() {␊ + > 2 | const bar = async () => {}␊ + | ^^ Move async arrow function 'bar' to the outer scope.␊ + 3 | }␊ + ` diff --git a/test/snapshots/consistent-function-scoping.js.snap b/test/snapshots/consistent-function-scoping.js.snap new file mode 100644 index 0000000000..3e89fb3425 Binary files /dev/null and b/test/snapshots/consistent-function-scoping.js.snap differ diff --git a/test/snapshots/no-useless-undefined.js.md b/test/snapshots/no-useless-undefined.js.md new file mode 100644 index 0000000000..c059aac202 --- /dev/null +++ b/test/snapshots/no-useless-undefined.js.md @@ -0,0 +1,51 @@ +# Snapshot report for `test/no-useless-undefined.js` + +The actual snapshot is saved in `no-useless-undefined.js.snap`. + +Generated by [AVA](https://avajs.dev). + +## no-useless-undefined - #1 + +> Snapshot 1 + + `␊ + 1 | foo(␊ + 2 | undefined,␊ + 3 | bar,␊ + > 4 | undefined,␊ + | ^^^^^^^^^^␊ + > 5 | undefined,␊ + | ^^^^^^^^^^^␊ + > 6 | undefined,␊ + | ^^^^^^^^^^^␊ + > 7 | undefined,␊ + | ^^^^^^^^^^^ Do not use useless `undefined`.␊ + 8 | )␊ + ` + +## no-useless-undefined - #2 + +> Snapshot 1 + + `␊ + > 1 | function foo([bar = undefined] = []) {}␊ + | ^^^^^^^^^ Do not use useless `undefined`.␊ + ` + +## no-useless-undefined - #3 + +> Snapshot 1 + + `␊ + > 1 | foo(bar, undefined, undefined);␊ + | ^^^^^^^^^^^^^^^^^^^^ Do not use useless `undefined`.␊ + ` + +## no-useless-undefined - #4 + +> Snapshot 1 + + `␊ + > 1 | let a = undefined, b = 2;␊ + | ^^^^^^^^^ Do not use useless `undefined`.␊ + ` diff --git a/test/snapshots/no-useless-undefined.js.snap b/test/snapshots/no-useless-undefined.js.snap new file mode 100644 index 0000000000..be7bb041ca Binary files /dev/null and b/test/snapshots/no-useless-undefined.js.snap differ diff --git a/test/utils/visualize-rule-tester.js b/test/utils/visualize-rule-tester.js new file mode 100644 index 0000000000..88bc059ae0 --- /dev/null +++ b/test/utils/visualize-rule-tester.js @@ -0,0 +1,78 @@ +'use strict'; +const {Linter} = require('eslint'); +const {codeFrameColumns} = require('@babel/code-frame'); +const codeFrameColumnsOptions = {linesAbove: Infinity, linesBelow: Infinity}; + +function visualizeRange(text, location, message) { + return codeFrameColumns( + text, + location, + { + ...codeFrameColumnsOptions, + message + } + ); +} + +function visualizeEslintResult(text, result) { + const {line, column, endLine, endColumn, message} = result; + const location = { + start: { + line, + column + } + }; + + if (typeof endLine === 'number' && typeof endColumn === 'number') { + location.end = { + line: endLine, + column: endColumn + }; + } + + return `\n${visualizeRange(text, location, message)}\n`; +} + +class VisualizeRuleTester { + constructor(test, config) { + this.test = test; + this.config = config; + } + + run(ruleId, rule, tests) { + const {test, config} = this; + const linter = new Linter(); + const verifyConfig = { + ...config, + rules: { + [ruleId]: 'error' + } + }; + + linter.defineRule(ruleId, rule); + + for (const [index, code] of tests.entries()) { + test(`${ruleId} - #${index + 1}`, t => { + const results = linter.verify(code, verifyConfig); + + if (results.length !== 1) { + throw new Error('Visualize test should has exactly one error.'); + } + + const [error] = results; + + if (error.fatal) { + throw new Error(error.message); + } + + t.snapshot(visualizeEslintResult(code, error)); + }); + } + } +} + +function visualizeRuleTester(test, config) { + return new VisualizeRuleTester(test, config); +} + +module.exports = visualizeRuleTester;