eslint-plugin-sonarjs
Version:
SonarJS rules for ESLint
85 lines (84 loc) • 3.12 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.rule = void 0;
const index_js_1 = require("../helpers/index.js");
const supertest_js_1 = require("../helpers/supertest.js");
const meta_js_1 = require("./meta.js");
/**
* We assume that the user is using a single assertion library per file,
* this is why we are not saving if an assertion has been performed for
* libX and the imported library was libY.
*/
exports.rule = {
meta: (0, index_js_1.generateMeta)(meta_js_1.meta),
create(context) {
const visitedNodes = new Set();
const potentialIssues = [];
return {
'CallExpression:exit': (node) => {
const testCase = index_js_1.Mocha.extractTestCase(node);
if (testCase !== null) {
checkAssertions(testCase, context, potentialIssues, visitedNodes);
}
},
'Program:exit': () => {
if (index_js_1.Chai.isImported(context) ||
index_js_1.Sinon.isImported(context) ||
index_js_1.Vitest.isImported(context) ||
supertest_js_1.Supertest.isImported(context)) {
potentialIssues.forEach(issue => {
context.report(issue);
});
}
},
};
},
};
function checkAssertions(testCase, context, potentialIssues, visitedNodes) {
const { node, callback } = testCase;
const visitor = new TestCaseAssertionVisitor(context);
visitor.visit(context, callback.body, visitedNodes);
if (visitor.missingAssertions()) {
potentialIssues.push({ node, message: 'Add at least one assertion to this test case.' });
}
}
class TestCaseAssertionVisitor {
constructor(context) {
this.context = context;
this.visitorKeys = context.sourceCode.visitorKeys;
this.hasAssertions = false;
}
visit(context, node, visitedNodes) {
if (visitedNodes.has(node)) {
return;
}
visitedNodes.add(node);
if (this.hasAssertions) {
return;
}
if (index_js_1.Chai.isAssertion(context, node) ||
index_js_1.Sinon.isAssertion(context, node) ||
index_js_1.Vitest.isAssertion(context, node) ||
supertest_js_1.Supertest.isAssertion(context, node)) {
this.hasAssertions = true;
return;
}
if ((0, index_js_1.isFunctionCall)(node)) {
const { callee } = node;
if (callee.name === 'expect') {
this.hasAssertions = true;
return;
}
const functionDef = (0, index_js_1.resolveFunction)(this.context, callee);
if (functionDef) {
this.visit(context, functionDef.body, visitedNodes);
}
}
for (const child of (0, index_js_1.childrenOf)(node, this.visitorKeys)) {
this.visit(context, child, visitedNodes);
}
}
missingAssertions() {
return !this.hasAssertions;
}
}
;