UNPKG

eslint-plugin-mocha

Version:

Eslint rules for mocha.

86 lines 3.52 kB
import { createMochaVisitors } from '../ast/mocha-visitors.js'; import { isBlockStatement, isFunction } from '../ast/node-types.js'; import { isRecord } from '../record.js'; const asyncMethods = ['async', 'callback', 'promise']; function hasAsyncCallback(functionExpression) { return isFunction(functionExpression) && functionExpression.params.length === 1; } function isAsyncFunction(functionExpression) { return isFunction(functionExpression) && functionExpression.async === true; } function findPromiseReturnStatement(nodes) { return nodes.find((node) => { return (node.type === 'ReturnStatement' && node.argument !== null && node.argument?.type !== 'Literal'); }); } function doesReturnPromise(functionExpression) { if (!isFunction(functionExpression)) { return false; } const bodyStatement = functionExpression.body; let returnStatement = null; if (isBlockStatement(bodyStatement)) { returnStatement = findPromiseReturnStatement(bodyStatement.body); } else if (bodyStatement.type !== 'Literal') { // allow arrow statements calling a promise with implicit return. returnStatement = bodyStatement; } return returnStatement !== null && returnStatement !== undefined; } export const noSynchronousTestsRule = { meta: { type: 'suggestion', docs: { description: 'Disallow synchronous tests', url: 'https://github.com/lo1tuma/eslint-plugin-mocha/blob/main/docs/rules/no-synchronous-tests.md' }, schema: [ { type: 'object', properties: { allowed: { type: 'array', items: { type: 'string', enum: asyncMethods }, minItems: 1, uniqueItems: true } } } ] }, create(context) { const [firstOption] = context.options; const options = isRecord(firstOption) ? firstOption : {}; const allowedAsyncMethods = options.allowed === undefined ? asyncMethods // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- we have json schema validation in place so we know this is a string : options.allowed; return createMochaVisitors(context, { anyTestEntityCallback(visitorContext) { // For each allowed async test method, check if it is used in the test const testAsyncMethods = allowedAsyncMethods.map((method) => { switch (method) { case 'async': return isAsyncFunction(visitorContext.node); case 'callback': return hasAsyncCallback(visitorContext.node); default: return doesReturnPromise(visitorContext.node); } }); // Check that at least one allowed async test method is used in the test const isAsyncTest = testAsyncMethods.includes(true); if (!isAsyncTest) { context.report({ node: visitorContext.node, message: 'Unexpected synchronous test.' }); } } }); } }; //# sourceMappingURL=no-synchronous-tests.js.map