Skip to content

Commit

Permalink
Merge pull request #260 from lo1tuma/refactor-names
Browse files Browse the repository at this point in the history
New option `ignoreSkipped` for `handle-done-callback` rule
  • Loading branch information
lo1tuma committed Jul 31, 2020
2 parents 8fadc3e + 7ee4a5a commit ddb7ef2
Show file tree
Hide file tree
Showing 7 changed files with 389 additions and 18 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.json
Expand Up @@ -20,7 +20,8 @@
"files": [ "test/**/*.js", "benchmarks/**/*.js" ],
"env": { "mocha": true },
"rules": {
"max-nested-callbacks": [ "error", 8 ]
"max-nested-callbacks": [ "error", 8 ],
"max-statements": [ "error", 30 ]
}
}
]
Expand Down
13 changes: 13 additions & 0 deletions docs/rules/handle-done-callback.md
Expand Up @@ -59,6 +59,19 @@ before(function (done) {
});
});
```
## Options

This rule supports the following options:

* `ignoreSkipped`: When set to `true` skipped test cases won’t be checked. Defaults to `false`.

```json
{
"rules": {
"mocha/handle-done-callback": ["error", {"ignoreSkipped": true}]
}
}
```

## When Not To Use It

Expand Down
20 changes: 18 additions & 2 deletions lib/rules/handle-done-callback.js
Expand Up @@ -8,9 +8,25 @@ module.exports = {
type: 'problem',
docs: {
description: 'Enforces handling of callbacks for async tests'
}
},
schema: [
{
type: 'object',
properties: {
ignoreSkipped: {
type: 'boolean',
default: false
}
},
additionalProperties: false
}
]
},
create(context) {
const [ config = {} ] = context.options;
const { ignoreSkipped = false } = config;
const modifiersToCheck = ignoreSkipped ? [ 'only' ] : [ 'only', 'skip' ];

function isAsyncFunction(functionExpression) {
return functionExpression.params.length === 1;
}
Expand Down Expand Up @@ -43,7 +59,7 @@ module.exports = {
}

function check(node) {
if (astUtils.hasParentMochaFunctionCall(node) && isAsyncFunction(node)) {
if (astUtils.hasParentMochaFunctionCall(node, { modifiers: modifiersToCheck }) && isAsyncFunction(node)) {
checkAsyncMochaFunction(node);
}
}
Expand Down
25 changes: 10 additions & 15 deletions lib/util/ast.js
Expand Up @@ -6,25 +6,16 @@ const isNil = require('ramda/src/isNil');
const propEq = require('ramda/src/propEq');
const pathEq = require('ramda/src/pathEq');
const find = require('ramda/src/find');
const { getTestCaseNames, getSuiteNames } = require('./names');

const isDefined = complement(isNil);
const isCallExpression = both(isDefined, propEq('type', 'CallExpression'));

const describeAliases = [
'describe', 'xdescribe', 'describe.only', 'describe.skip',
'context', 'xcontext', 'context.only', 'context.skip',
'suite', 'xsuite', 'suite.only', 'suite.skip'
];
const hooks = [
'before', 'after', 'beforeEach', 'afterEach', 'beforeAll', 'afterAll',
'setup', 'teardown', 'suiteSetup', 'suiteTeardown'
];
const suiteConfig = [ 'timeout', 'slow', 'retries' ];
const testCaseNames = [
'it', 'it.only', 'it.skip', 'xit',
'test', 'test.only', 'test.skip',
'specify', 'specify.only', 'specify.skip', 'xspecify'
];

function getPropertyName(property) {
return property.name || property.value;
Expand All @@ -38,8 +29,9 @@ function getNodeName(node) {
}

function isDescribe(node, additionalSuiteNames = []) {
return isCallExpression(node) &&
describeAliases.concat(additionalSuiteNames).indexOf(getNodeName(node.callee)) > -1;
const describeAliases = getSuiteNames({ modifiers: [ 'skip', 'only' ], additionalSuiteNames });

return isCallExpression(node) && describeAliases.indexOf(getNodeName(node.callee)) > -1;
}

function isHookIdentifier(node) {
Expand All @@ -52,7 +44,10 @@ function isHookCall(node) {
return isCallExpression(node) && isHookIdentifier(node.callee);
}

function isTestCase(node) {
function isTestCase(node, options = {}) {
const { modifiers = [ 'skip', 'only' ] } = options;

const testCaseNames = getTestCaseNames({ modifiers });
return isCallExpression(node) && testCaseNames.indexOf(getNodeName(node.callee)) > -1;
}

Expand Down Expand Up @@ -100,8 +95,8 @@ function isMochaFunctionCall(node, scope) {
return isTestCase(node) || isDescribe(node) || isHookCall(node);
}

function hasParentMochaFunctionCall(functionExpression) {
return isTestCase(functionExpression.parent) || isHookCall(functionExpression.parent);
function hasParentMochaFunctionCall(functionExpression, options) {
return isTestCase(functionExpression.parent, options) || isHookCall(functionExpression.parent);
}

function isExplicitUndefined(node) {
Expand Down
77 changes: 77 additions & 0 deletions lib/util/names.js
@@ -0,0 +1,77 @@
'use strict';

const chain = require('ramda/src/chain');

const suiteNames = [
'describe',
'context',
'suite'
];

const suiteModifiers = {
skip: [
'describe.skip',
'context.skip',
'suite.skip',
'xdescribe',
'xcontext',
'xsuite'
],
only: [
'describe.only',
'context.only',
'suite.only'
]
};

const testCaseNames = [
'it',
'test',
'specify'
];

const testCaseModifiers = {
skip: [
'it.skip',
'test.skip',
'specify.skip',
'xit',
'xspecify'
],
only: [
'it.only',
'test.only',
'specify.only'
]
};

function getTestCaseNames(options = {}) {
const { modifiers = [], baseNames = true } = options;
const names = baseNames ? testCaseNames : [];

return names.concat(chain((modifierName) => {
if (testCaseModifiers[modifierName]) {
return testCaseModifiers[modifierName];
}

return [];
}, modifiers));
}

function getSuiteNames(options = {}) {
const { modifiers = [], baseNames = true, additionalSuiteNames = [] } = options;
const names = baseNames ? suiteNames.concat(additionalSuiteNames) : [];

return names.concat(chain((modifierName) => {
if (suiteModifiers[modifierName]) {
return suiteModifiers[modifierName];
}

return [];
}, modifiers));
}

module.exports = {
getTestCaseNames,
getSuiteNames
};
12 changes: 12 additions & 0 deletions test/rules/handle-done-callback.js
Expand Up @@ -31,6 +31,10 @@ ruleTester.run('handle-done-callback', rules['handle-done-callback'], {
{
code: 'it("", (done) => { done(); });',
parserOptions: { ecmaVersion: 6 }
},
{
code: 'it.skip("", function (done) { });',
options: [ { ignoreSkipped: true } ]
}
],

Expand All @@ -39,6 +43,14 @@ ruleTester.run('handle-done-callback', rules['handle-done-callback'], {
code: 'it("", function (done) { });',
errors: [ { message: 'Expected "done" callback to be handled.', column: 18, line: 1 } ]
},
{
code: 'it.skip("", function (done) { });',
errors: [ { message: 'Expected "done" callback to be handled.', column: 23, line: 1 } ]
},
{
code: 'xit("", function (done) { });',
errors: [ { message: 'Expected "done" callback to be handled.', column: 19, line: 1 } ]
},
{
code: 'it("", function (done) { callback(); });',
errors: [ { message: 'Expected "done" callback to be handled.', column: 18, line: 1 } ]
Expand Down

0 comments on commit ddb7ef2

Please sign in to comment.