From e1e3cdf1298ae3c71fa63cb45d9d6e96af95bb42 Mon Sep 17 00:00:00 2001 From: Jeroen Engels Date: Sat, 25 Nov 2017 18:23:14 +0100 Subject: [PATCH] Improve target reporting (#182) * no-only-test: Target `only` modifier, not the whole test * no-unknown-modifiers: Target unknown modifier, not the whole test * no-skip-test: Target `skip` modifier, not the whole test * no-duplicate-modifiers: Target duplicate modifier, not the whole test * no-async-fn-without-await: Target async modifier, not the whole test * no-cb-test: Target `cb` modifier, not the whole test * no-identical-title: Target title, not the whole test --- create-ava-rule.js | 28 +++---- rules/no-async-fn-without-await.js | 20 +++-- rules/no-cb-test.js | 5 +- rules/no-duplicate-modifiers.js | 21 +++++- rules/no-identical-title.js | 2 +- rules/no-only-test.js | 9 ++- rules/no-skip-test.js | 6 +- rules/no-unknown-modifiers.js | 6 +- test/no-async-fn-without-await.js | 96 +++++++++++++++++------- test/no-cb-test.js | 27 ++++++- test/no-duplicate-modifiers.js | 34 ++++++--- test/no-identical-title.js | 68 ++++++++++++++--- test/no-only-test.js | 75 ++++++++++++++++--- test/no-skip-test.js | 27 ++++++- test/no-unknown-modifiers.js | 114 ++++++++++++++++++++--------- util.js | 19 ++--- 16 files changed, 404 insertions(+), 153 deletions(-) diff --git a/create-ava-rule.js b/create-ava-rule.js index 63cf47b2..300e85cb 100644 --- a/create-ava-rule.js +++ b/create-ava-rule.js @@ -2,6 +2,7 @@ const espurify = require('espurify'); const enhance = require('enhance-visitors'); const deepStrictEqual = require('deep-strict-equal'); +const util = require('./util'); const avaImportDeclarationAst = { type: 'ImportDeclaration', @@ -51,18 +52,8 @@ function isTestFunctionCall(node) { return false; } -function hasTestModifier(node, mod) { - if (node.type === 'CallExpression') { - return hasTestModifier(node.callee, mod); - } else if (node.type === 'MemberExpression') { - if (node.property.type === 'Identifier' && node.property.name === mod) { - return true; - } - - return hasTestModifier(node.object, mod); - } - - return false; +function getTestModifierNames(node) { + return util.getTestModifiers(node).map(property => property.name); } module.exports = () => { @@ -99,11 +90,14 @@ module.exports = () => { }; return { - hasTestModifier: mod => hasTestModifier(currentTestNode, mod), - hasNoHookModifier: () => !hasTestModifier(currentTestNode, 'before') && - !hasTestModifier(currentTestNode, 'beforeEach') && - !hasTestModifier(currentTestNode, 'after') && - !hasTestModifier(currentTestNode, 'afterEach'), + hasTestModifier: mod => getTestModifierNames(currentTestNode).indexOf(mod) >= 0, + hasNoHookModifier: () => { + const modifiers = getTestModifierNames(currentTestNode); + return modifiers.indexOf('before') === -1 && + modifiers.indexOf('beforeEach') === -1 && + modifiers.indexOf('after') === -1 && + modifiers.indexOf('afterEach') === -1; + }, isInTestFile: () => isTestFile, isInTestNode: () => currentTestNode, isTestNode: node => currentTestNode === node, diff --git a/rules/no-async-fn-without-await.js b/rules/no-async-fn-without-await.js index 9a445c82..cb7bf2af 100644 --- a/rules/no-async-fn-without-await.js +++ b/rules/no-async-fn-without-await.js @@ -4,11 +4,11 @@ const createAvaRule = require('../create-ava-rule'); const create = context => { const ava = createAvaRule(); - let testIsAsync = false; + let asyncTest = null; let testUsed = false; const registerUseOfAwait = () => { - if (testIsAsync) { + if (asyncTest) { testUsed = true; } }; @@ -20,21 +20,27 @@ const create = context => { ava.isInTestFile, ava.isTestNode ])(node => { - testIsAsync = isAsync(node.arguments[0]) || isAsync(node.arguments[1]); + asyncTest = (isAsync(node.arguments[0]) && node.arguments[0]) || + (isAsync(node.arguments[1]) && node.arguments[1]) || + null; }), AwaitExpression: registerUseOfAwait, YieldExpression: registerUseOfAwait, 'CallExpression:exit': visitIf([ ava.isInTestFile, ava.isTestNode - ])(node => { - if (testIsAsync && !testUsed) { + ])(() => { + if (asyncTest && !testUsed) { context.report({ - node, + node: asyncTest, + loc: { + start: asyncTest.loc.start, + end: asyncTest.loc.start + 5 + }, message: 'Function was declared as `async` but doesn\'t use `await`' }); } - testIsAsync = false; + asyncTest = null; testUsed = false; }) }); diff --git a/rules/no-cb-test.js b/rules/no-cb-test.js index e159b936..311068dd 100644 --- a/rules/no-cb-test.js +++ b/rules/no-cb-test.js @@ -1,6 +1,7 @@ 'use strict'; const visitIf = require('enhance-visitors').visitIf; const createAvaRule = require('../create-ava-rule'); +const util = require('../util'); const create = context => { const ava = createAvaRule(); @@ -12,8 +13,8 @@ const create = context => { ])(node => { if (ava.hasTestModifier('cb')) { context.report({ - node, - message: '`test.cb()` should be not be used.' + node: util.getTestModifier(node, 'cb'), + message: '`test.cb()` should not be used.' }); } }) diff --git a/rules/no-duplicate-modifiers.js b/rules/no-duplicate-modifiers.js index 1b84e2a3..1a563a7e 100644 --- a/rules/no-duplicate-modifiers.js +++ b/rules/no-duplicate-modifiers.js @@ -3,6 +3,18 @@ const visitIf = require('enhance-visitors').visitIf; const util = require('../util'); const createAvaRule = require('../create-ava-rule'); +function sortByName(a, b) { + if (a.name < b.name) { + return -1; + } + + if (a.name > b.name) { + return 1; + } + + return 0; +} + const create = context => { const ava = createAvaRule(); @@ -11,16 +23,17 @@ const create = context => { ava.isInTestFile, ava.isTestNode ])(node => { - const testModifiers = util.getTestModifiers(node).sort(); + const testModifiers = util.getTestModifiers(node).sort(sortByName); + if (testModifiers.length === 0) { return; } testModifiers.reduce((prev, current) => { - if (prev === current) { + if (prev.name === current.name) { context.report({ - node, - message: `Duplicate test modifier \`${current}\`.` + node: current, + message: `Duplicate test modifier \`${current.name}\`.` }); } return current; diff --git a/rules/no-identical-title.js b/rules/no-identical-title.js index 60f96c95..c3a88fcf 100644 --- a/rules/no-identical-title.js +++ b/rules/no-identical-title.js @@ -45,7 +45,7 @@ const create = context => { if (isTitleUsed(usedTitleNodes, titleNode)) { context.report({ - node, + node: titleNode, message: 'Test title is used multiple times in the same file.' }); return; diff --git a/rules/no-only-test.js b/rules/no-only-test.js index 7169de49..d2b115f3 100644 --- a/rules/no-only-test.js +++ b/rules/no-only-test.js @@ -1,7 +1,7 @@ 'use strict'; const visitIf = require('enhance-visitors').visitIf; const createAvaRule = require('../create-ava-rule'); -const getTestModifier = require('../util').getTestModifier; +const util = require('../util'); const create = context => { const ava = createAvaRule(); @@ -11,12 +11,13 @@ const create = context => { ava.isInTestFile, ava.isTestNode ])(node => { - if (ava.hasTestModifier('only')) { + const propertyNode = util.getTestModifier(node, 'only'); + if (propertyNode) { context.report({ - node, + node: propertyNode, message: '`test.only()` should not be used.', fix: fixer => { - const range = getTestModifier(node, 'only').range.slice(); + const range = propertyNode.range.slice(); const source = context.getSourceCode().getText(); let dotPosition = range[0] - 1; while (source.charAt(dotPosition) !== '.') { diff --git a/rules/no-skip-test.js b/rules/no-skip-test.js index 12bace4c..9573e043 100644 --- a/rules/no-skip-test.js +++ b/rules/no-skip-test.js @@ -1,6 +1,7 @@ 'use strict'; const visitIf = require('enhance-visitors').visitIf; const createAvaRule = require('../create-ava-rule'); +const util = require('../util'); const create = context => { const ava = createAvaRule(); @@ -10,9 +11,10 @@ const create = context => { ava.isInTestFile, ava.isTestNode ])(node => { - if (ava.hasTestModifier('skip')) { + const propertyNode = util.getTestModifier(node, 'skip'); + if (propertyNode) { context.report({ - node, + node: propertyNode, message: 'No tests should be skipped.' }); } diff --git a/rules/no-unknown-modifiers.js b/rules/no-unknown-modifiers.js index 8296db3d..cfcc505f 100644 --- a/rules/no-unknown-modifiers.js +++ b/rules/no-unknown-modifiers.js @@ -18,7 +18,7 @@ const modifiers = [ ]; const unknownModifiers = node => util.getTestModifiers(node) - .filter(modifier => modifiers.indexOf(modifier) === -1); + .filter(modifier => modifiers.indexOf(modifier.name) === -1); const create = context => { const ava = createAvaRule(); @@ -32,8 +32,8 @@ const create = context => { if (unknown.length !== 0) { context.report({ - node, - message: `Unknown test modifier \`${unknown[0]}\`.` + node: unknown[0], + message: `Unknown test modifier \`${unknown[0].name}\`.` }); } }) diff --git a/test/no-async-fn-without-await.js b/test/no-async-fn-without-await.js index ed7e65e7..c9b2908e 100644 --- a/test/no-async-fn-without-await.js +++ b/test/no-async-fn-without-await.js @@ -2,10 +2,8 @@ import test from 'ava'; import avaRuleTester from 'eslint-ava-rule-tester'; import rule from '../rules/no-async-fn-without-await'; -const error = { - ruleId: 'no-async-fn-without-await', - message: 'Function was declared as `async` but doesn\'t use `await`' -}; +const ruleId = 'no-async-fn-without-await'; +const message = 'Function was declared as `async` but doesn\'t use `await`'; const header = `const test = require('ava');\n`; const ruleTesterOptions = [ @@ -27,45 +25,87 @@ ruleTesterOptions.forEach(options => { ruleTester.run(`no-async-fn-without-await`, rule, { valid: [ - `${header} test(fn);`, - `${header} test(t => {});`, - `${header} test(function(t) {});`, - `${header} test(async t => { await foo(); });`, - `${header} test(async t => { t.is(await foo(), 1); });`, - `${header} test(async function(t) { await foo(); });`, - `${header} test(async t => { if (bar) { await foo(); } });`, - `${header} test(async t => { if (bar) {} else { await foo(); } });`, - `${header} test.after(async () => { await foo(); });`, - `${header} test('title', fn);`, - `${header} test('title', function(t) {});`, - `${header} test('title', async t => { await foo(); });`, + `${header}test(fn);`, + `${header}test(t => {});`, + `${header}test(function(t) {});`, + `${header}test(async t => { await foo(); });`, + `${header}test(async t => { t.is(await foo(), 1); });`, + `${header}test(async function(t) { await foo(); });`, + `${header}test(async t => { if (bar) { await foo(); } });`, + `${header}test(async t => { if (bar) {} else { await foo(); } });`, + `${header}test.after(async () => { await foo(); });`, + `${header}test('title', fn);`, + `${header}test('title', function(t) {});`, + `${header}test('title', async t => { await foo(); });`, // Shouldn't be triggered since it's not a test file 'test(async t => {});' ], invalid: [ { - code: `${header} test(async t => {});`, - errors: [error] + code: `${header}test(async t => {});`, + errors: [{ + ruleId, + message, + type: 'ArrowFunctionExpression', + line: 2, + column: 6 + }] }, { - code: `${header} test(async function(t) {});`, - errors: [error] + code: `${header}test(async function(t) {});`, + errors: [{ + ruleId, + message, + type: 'FunctionExpression', + line: 2, + column: 6 + }] }, { - code: `${header} test(async t => {}); test(async t => {});`, - errors: [error, error] + code: `${header}test(async t => {}); test(async t => {});`, + errors: [{ + ruleId, + message, + type: 'ArrowFunctionExpression', + line: 2, + column: 6 + }, { + ruleId, + message, + type: 'ArrowFunctionExpression', + line: 2, + column: 27 + }] }, { - code: `${header} test(async t => {}); test(async t => { await foo(); });`, - errors: [error] + code: `${header}test(async t => {}); test(async t => { await foo(); });`, + errors: [{ + ruleId, + message, + type: 'ArrowFunctionExpression', + line: 2, + column: 6 + }] }, { - code: `${header} test(async t => { await foo(); }); test(async t => {});`, - errors: [error] + code: `${header}test(async t => { await foo(); }); test(async t => {});`, + errors: [{ + ruleId, + message, + type: 'ArrowFunctionExpression', + line: 2, + column: 41 + }] }, { - code: `${header} test('title', async t => {});`, - errors: [error] + code: `${header}test('title', async t => {});`, + errors: [{ + ruleId, + message, + type: 'ArrowFunctionExpression', + line: 2, + column: 15 + }] } ] }); diff --git a/test/no-cb-test.js b/test/no-cb-test.js index f1ae9bdd..0c554bfd 100644 --- a/test/no-cb-test.js +++ b/test/no-cb-test.js @@ -8,7 +8,8 @@ const ruleTester = avaRuleTester(test, { } }); -const errors = [{ruleId: 'no-cb-test'}]; +const ruleId = 'no-cb-test'; +const message = '`test.cb()` should not be used.'; const header = `const test = require('ava');\n`; ruleTester.run('no-cb-test', rule, { @@ -22,15 +23,33 @@ ruleTester.run('no-cb-test', rule, { invalid: [ { code: header + 'test.cb(t => { t.pass(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 2, + column: 6 + }] }, { code: header + 'test.cb.skip(t => { t.pass(); t.end(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 2, + column: 6 + }] }, { code: header + 'test.skip.cb(t => { t.pass(); t.end(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 2, + column: 11 + }] } ] }); diff --git a/test/no-duplicate-modifiers.js b/test/no-duplicate-modifiers.js index 1c25cf8e..4d2534b3 100644 --- a/test/no-duplicate-modifiers.js +++ b/test/no-duplicate-modifiers.js @@ -8,7 +8,7 @@ const ruleTester = avaRuleTester(test, { } }); -const ruleError = {ruleId: 'no-duplicate-modifiers'}; +const ruleId = 'no-duplicate-modifiers'; const header = `const test = require('ava');\n`; const modifiers = [ @@ -25,29 +25,41 @@ const modifiers = [ 'todo' ]; -const valid = modifiers.map(modifier => `${header} test.${modifier}(t => {});`); +const valid = modifiers.map(modifier => `${header}test.${modifier}(t => {});`); const invalid = modifiers.map(modifier => ({ - code: `${header} test.${modifier}.${modifier}(t => {});`, + code: `${header}test.${modifier}.${modifier}(t => {});`, errors: [ - Object.assign({}, ruleError, {message: `Duplicate test modifier \`${modifier}\`.`}) + { + ruleId, + message: `Duplicate test modifier \`${modifier}\`.`, + type: 'Identifier', + line: 2, + column: 7 + modifier.length + } ] })); ruleTester.run('no-duplicate-modifiers', rule, { valid: valid.concat([ - `${header} test(t => {});`, - `${header} test.cb.only(t => {});`, - `${header} test.after.always(t => {});`, - `${header} test.afterEach.always(t => {});`, - `${header} test.failing.cb(t => {});`, + `${header}test(t => {});`, + `${header}test.cb.only(t => {});`, + `${header}test.after.always(t => {});`, + `${header}test.afterEach.always(t => {});`, + `${header}test.failing.cb(t => {});`, // Shouldn't be triggered since it's not a test file `test.serial.serial(t => {});` ]), invalid: invalid.concat([ { - code: `${header} test.serial.cb.only.serial(t => {});`, + code: `${header}test.serial.cb.only.serial(t => {});`, errors: [ - Object.assign({}, ruleError, {message: 'Duplicate test modifier `serial`.'}) + { + ruleId, + message: 'Duplicate test modifier `serial`.', + type: 'Identifier', + line: 2, + column: 21 + } ] } ]) diff --git a/test/no-identical-title.js b/test/no-identical-title.js index 7ab4c1f6..710825e7 100644 --- a/test/no-identical-title.js +++ b/test/no-identical-title.js @@ -8,7 +8,9 @@ const ruleTester = avaRuleTester(test, { } }); -const errors = [{ruleId: 'no-identical-title'}]; +const ruleId = 'no-identical-title'; +const message = 'Test title is used multiple times in the same file.'; + const header = `const test = require('ava');\n`; ruleTester.run('no-identical-title', rule, { @@ -58,36 +60,84 @@ ruleTester.run('no-identical-title', rule, { invalid: [ { code: header + 'test("a", t => {}); test("a", t => {});', - errors + errors: [{ + ruleId, + message, + type: 'Literal', + line: 2, + column: 26 + }] }, { code: header + 'test(`a`, t => {}); test(`a`, t => {});', - errors + errors: [{ + ruleId, + message, + type: 'TemplateLiteral', + line: 2, + column: 26 + }] }, { code: header + 'test("a", t => {}); test.cb("a", t => {});', - errors + errors: [{ + ruleId, + message, + type: 'Literal', + line: 2, + column: 29 + }] }, { code: header + 'test(`a`, t => {}); test.cb(`a`, t => {});', - errors + errors: [{ + ruleId, + message, + type: 'TemplateLiteral', + line: 2, + column: 29 + }] }, { code: header + 'test("a", t => {}); test.cb.skip("a", t => {});', - errors + errors: [{ + ruleId, + message, + type: 'Literal', + line: 2, + column: 34 + }] }, { code: header + 'test("foo" + 1, t => {}); test("foo" + 1, t => {});', - errors + errors: [{ + ruleId, + message, + type: 'BinaryExpression', + line: 2, + column: 32 + }] }, { // eslint-disable-next-line no-template-curly-in-string code: header + 'test(`${"foo" + 1}`, t => {}); test(`${"foo" + 1}`, t => {});', - errors + errors: [{ + ruleId, + message, + type: 'TemplateLiteral', + line: 2, + column: 37 + }] }, { code: header + 'test.todo("a"); test.todo("a");', - errors + errors: [{ + ruleId, + message, + type: 'Literal', + line: 2, + column: 27 + }] } ] }); diff --git a/test/no-only-test.js b/test/no-only-test.js index ed80c64d..c0a5120e 100644 --- a/test/no-only-test.js +++ b/test/no-only-test.js @@ -11,7 +11,8 @@ const ruleTester = avaRuleTester(test, { } }); -const errors = [{ruleId: 'no-only-test'}]; +const ruleId = 'no-only-test'; +const message = '`test.only()` should not be used.'; const header = `const test = require('ava');\n`; ruleTester.run('no-only-test', rule, { @@ -27,47 +28,101 @@ ruleTester.run('no-only-test', rule, { { code: header + 'test\n\t.only(t => { t.pass(); });', output: header + 'test\n\t(t => { t.pass(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 3, + column: 3 + }] }, { code: header + 'test\n .only(t => { t.pass(); });', output: header + 'test\n (t => { t.pass(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 3, + column: 4 + }] }, { code: header + 'test\t.only(t => { t.pass(); });', output: header + 'test\t(t => { t.pass(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 2, + column: 7 + }] }, { code: header + 'test .only(t => { t.pass(); });', output: header + 'test (t => { t.pass(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 2, + column: 8 + }] }, { code: header + 'test.\n\tonly(t => { t.pass(); });', output: header + 'test\n\t(t => { t.pass(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 3, + column: 2 + }] }, { code: header + 'test.\n only(t => { t.pass(); });', output: header + 'test\n (t => { t.pass(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 3, + column: 3 + }] }, { code: header + 'test.only(t => { t.pass(); });', output: header + 'test(t => { t.pass(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 2, + column: 6 + }] }, { code: header + 'test.cb.only(t => { t.pass(); t.end(); });', output: header + 'test.cb(t => { t.pass(); t.end(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 2, + column: 9 + }] }, { code: header + 'test.only.cb(t => { t.pass(); t.end(); });', output: header + 'test.cb(t => { t.pass(); t.end(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 2, + column: 6 + }] } ] }); diff --git a/test/no-skip-test.js b/test/no-skip-test.js index 3a448d59..ee1d18e5 100644 --- a/test/no-skip-test.js +++ b/test/no-skip-test.js @@ -8,7 +8,8 @@ const ruleTester = avaRuleTester(test, { } }); -const errors = [{ruleId: 'no-skip-test'}]; +const ruleId = 'no-skip-test'; +const message = 'No tests should be skipped.'; const header = `const test = require('ava');\n`; ruleTester.run('no-skip-test', rule, { @@ -24,15 +25,33 @@ ruleTester.run('no-skip-test', rule, { invalid: [ { code: header + 'test.skip(t => { t.pass(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 2, + column: 6 + }] }, { code: header + 'test.cb.skip(t => { t.pass(); t.end(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 2, + column: 9 + }] }, { code: header + 'test.skip.cb(t => { t.pass(); t.end(); });', - errors + errors: [{ + ruleId, + message, + type: 'Identifier', + line: 2, + column: 6 + }] } ] }); diff --git a/test/no-unknown-modifiers.js b/test/no-unknown-modifiers.js index 84c3be34..70d8b5e0 100644 --- a/test/no-unknown-modifiers.js +++ b/test/no-unknown-modifiers.js @@ -8,64 +8,108 @@ const ruleTester = avaRuleTester(test, { } }); -const ruleError = {ruleId: 'no-unknown-modifiers'}; +const ruleId = 'no-unknown-modifiers'; const header = `const test = require('ava');\n`; -function error(message) { - return Object.assign({}, ruleError, {message}); -} - ruleTester.run('no-unknown-modifiers', rule, { valid: [ - `${header} test(t => {});`, - `${header} test.after(t => {});`, - `${header} test.afterEach(t => {});`, - `${header} test.before(t => {});`, - `${header} test.beforeEach(t => {});`, - `${header} test.cb(t => {});`, - `${header} test.cb.only(t => {});`, - `${header} test.only(t => {});`, - `${header} test.serial(t => {});`, - `${header} test.skip(t => {});`, - `${header} test.todo(t => {});`, - `${header} test.after.always(t => {});`, - `${header} test.afterEach.always(t => {});`, - `${header} test.failing(t => {});`, + `${header}test(t => {});`, + `${header}test.after(t => {});`, + `${header}test.afterEach(t => {});`, + `${header}test.before(t => {});`, + `${header}test.beforeEach(t => {});`, + `${header}test.cb(t => {});`, + `${header}test.cb.only(t => {});`, + `${header}test.only(t => {});`, + `${header}test.serial(t => {});`, + `${header}test.skip(t => {});`, + `${header}test.todo(t => {});`, + `${header}test.after.always(t => {});`, + `${header}test.afterEach.always(t => {});`, + `${header}test.failing(t => {});`, // Shouldn't be triggered since it's not a test file `test.foo(t => {});` ], invalid: [ { - code: `${header} test.foo(t => {});`, - errors: [error('Unknown test modifier `foo`.')] + code: `${header}test.foo(t => {});`, + errors: [{ + ruleId, + message: 'Unknown test modifier `foo`.', + type: 'Identifier', + line: 2, + column: 6 + }] }, { - code: `${header} test.onlu(t => {});`, - errors: [error('Unknown test modifier `onlu`.')] + code: `${header}test.onlu(t => {});`, + errors: [{ + ruleId, + message: 'Unknown test modifier `onlu`.', + type: 'Identifier', + line: 2, + column: 6 + }] }, { - code: `${header} test.beforeeach(t => {});`, - errors: [error('Unknown test modifier `beforeeach`.')] + code: `${header}test.beforeeach(t => {});`, + errors: [{ + ruleId, + message: 'Unknown test modifier `beforeeach`.', + type: 'Identifier', + line: 2, + column: 6 + }] }, { - code: `${header} test.c.only(t => {});`, - errors: [error('Unknown test modifier `c`.')] + code: `${header}test.c.only(t => {});`, + errors: [{ + ruleId, + message: 'Unknown test modifier `c`.', + type: 'Identifier', + line: 2, + column: 6 + }] }, { - code: `${header} test.cb.onlu(t => {});`, - errors: [error('Unknown test modifier `onlu`.')] + code: `${header}test.cb.onlu(t => {});`, + errors: [{ + ruleId, + message: 'Unknown test modifier `onlu`.', + type: 'Identifier', + line: 2, + column: 9 + }] }, { - code: `${header} test.foo.bar.baz(t => {});`, - errors: [error('Unknown test modifier `foo`.')] + code: `${header}test.foo.bar.baz(t => {});`, + errors: [{ + ruleId, + message: 'Unknown test modifier `foo`.', + type: 'Identifier', + line: 2, + column: 6 + }] }, { - code: `${header} test.default(t => {});`, - errors: [error('Unknown test modifier `default`.')] + code: `${header}test.default(t => {});`, + errors: [{ + ruleId, + message: 'Unknown test modifier `default`.', + type: 'Identifier', + line: 2, + column: 6 + }] }, { - code: `${header} test.test(t => {});`, - errors: [error('Unknown test modifier `test`.')] + code: `${header}test.test(t => {});`, + errors: [{ + ruleId, + message: 'Unknown test modifier `test`.', + type: 'Identifier', + line: 2, + column: 6 + }] } ] }); diff --git a/util.js b/util.js index 1323f87c..f9d4772b 100644 --- a/util.js +++ b/util.js @@ -41,28 +41,23 @@ exports.isFunctionExpression = node => { return node && functionExpressions.indexOf(node.type) !== -1; }; -exports.getTestModifiers = function getTestModifiers(node) { +function getTestModifiers(node) { if (node.type === 'CallExpression') { return getTestModifiers(node.callee); } if (node.type === 'MemberExpression') { - return getTestModifiers(node.object).concat(node.property.name); + return getTestModifiers(node.object).concat(node.property); } return []; -}; +} -exports.getTestModifier = function getTestModifier(node, mod) { - if (node.type === 'CallExpression') { - return getTestModifier(node.callee, mod); - } else if (node.type === 'MemberExpression') { - if (node.property.type === 'Identifier' && node.property.name === mod) { - return node.property; - } +exports.getTestModifiers = getTestModifiers; - return getTestModifier(node.object, mod); - } +exports.getTestModifier = (node, mod) => { + const testModifiers = getTestModifiers(node); + return testModifiers.find(property => property.name === mod); }; const getMembers = node => {