lib/rules/no-sinon-assert-called-if-called-with.js (75 lines of code) (raw):

'use strict'; module.exports = { meta: { docs: { category: 'Stylistic Issues', description: 'Ensure `sinon.assert.called()` is absent when `sinon.assert.calledWith()` is used', githubIssue: 'https://github.com/mozilla/addons-frontend/issues/2437', recommended: true, }, messages: { error: 'No need to use `sinon.assert.called()` when you use `sinon.assert.calledWith()` on the same spy.', }, fixable: null, schema: [], }, create: (context) => { const isSinonAssertCall = (node) => { if (!node.expression.callee) { return false; } const { object } = node.expression.callee; if (!object || !object.object || !object.property) { return false; } return ( object.object.name === 'sinon' && object.property.name === 'assert' ); }; const getSinonAssertMethod = (node) => { return node.expression.callee.property.name; }; const getSinonAssertSpy = (node) => { if (!node.expression.arguments.length) { return null; } const spy = node.expression.arguments[0]; if (spy.type === 'MemberExpression') { return `${spy.object.name}.${spy.property.name}`; } return spy.name; }; return { BlockStatement: (node) => { const { body } = node; for (let i = 0; i < body.length; i++) { const current = body[i]; const next = i + 1 < body.length ? body[i + 1] : null; if ( !current || !next || current.type !== 'ExpressionStatement' || next.type !== 'ExpressionStatement' || !isSinonAssertCall(current) || !isSinonAssertCall(next) ) { continue; } if ( getSinonAssertMethod(current) === 'called' && getSinonAssertMethod(next) === 'calledWith' && getSinonAssertSpy(current) === getSinonAssertSpy(next) ) { context.report({ node: current, messageId: 'error', }); break; } } }, }; }, };