diff --git a/lib/rules/no-assert-equal.js b/lib/rules/no-assert-equal.js index 5b0b5101..0aad59eb 100644 --- a/lib/rules/no-assert-equal.js +++ b/lib/rules/no-assert-equal.js @@ -159,6 +159,41 @@ module.exports = { }); } + /** + * @param {import('eslint').Rule.Node} propertyNode + * @returns {boolean} + */ + function isModuleHookCallback(propertyNode) { + return ( + propertyNode.parent && + propertyNode.parent.type === "Property" && + utils.isModuleHookPropertyKey(propertyNode.parent.key) && + utils.isInModule(propertyNode.parent) + ); + } + + /** + * @param {import('eslint').Rule.Node} propertyNode + * @returns {void} + */ + function pushModuleHookAssert(propertyNode) { + if (isModuleHookCallback(propertyNode)) { + testStack.push({ + assertVar: utils.getAssertContextName(propertyNode), + }); + } + } + + /** + * @param {import('eslint').Rule.Node} propertyNode + * @returns {void} + */ + function popModuleHookAssert(propertyNode) { + if (isModuleHookCallback(propertyNode)) { + testStack.pop(); + } + } + return { CallExpression: function (node) { /* istanbul ignore else: correctly does nothing */ @@ -188,6 +223,15 @@ module.exports = { testStack.pop(); } }, + + FunctionDeclaration: pushModuleHookAssert, + FunctionExpression: pushModuleHookAssert, + ArrowFunctionExpression: pushModuleHookAssert, + + "FunctionDeclaration:exit": popModuleHookAssert, + "FunctionExpression:exit": popModuleHookAssert, + "ArrowFunctionExpression:exit": popModuleHookAssert, + Program: function (node) { // Gather all calls to global `equal()`. /* istanbul ignore next: deprecated code paths only followed by old eslint versions */ diff --git a/lib/rules/no-qunit-start-in-tests.js b/lib/rules/no-qunit-start-in-tests.js index 009815e0..900b403c 100644 --- a/lib/rules/no-qunit-start-in-tests.js +++ b/lib/rules/no-qunit-start-in-tests.js @@ -51,20 +51,6 @@ module.exports = { ); } - /** - * @param {import('eslint').Rule.Node} propertyNode - * @returns {boolean} - */ - function isInModule(propertyNode) { - return ( - propertyNode && - propertyNode.parent && // ObjectExpression - propertyNode.parent.parent && // CallExpression? - propertyNode.parent.parent.type === "CallExpression" && - utils.isModule(propertyNode.parent.parent.callee) - ); - } - //---------------------------------------------------------------------- // Public //---------------------------------------------------------------------- @@ -93,7 +79,7 @@ module.exports = { Property: function (node) { if ( utils.isModuleHookPropertyKey(node.key) && - isInModule(node) && + utils.isInModule(node) && node.key.type === "Identifier" ) { contextStack.push(`${node.key.name} hook`); @@ -109,7 +95,7 @@ module.exports = { "Property:exit": function (node) { if ( utils.isModuleHookPropertyKey(node.key) && - isInModule(node) + utils.isInModule(node) ) { contextStack.pop(); } diff --git a/lib/rules/no-setup-teardown.js b/lib/rules/no-setup-teardown.js index 0d0d7c98..81e71bf8 100644 --- a/lib/rules/no-setup-teardown.js +++ b/lib/rules/no-setup-teardown.js @@ -68,25 +68,11 @@ module.exports = { } } - /** - * @param {import('eslint').Rule.Node} propertyNode - * @returns {boolean} - */ - function isInModule(propertyNode) { - return ( - propertyNode && - propertyNode.parent && // ObjectExpression - propertyNode.parent.parent && // CallExpression? - propertyNode.parent.parent.type === "CallExpression" && - utils.isModule(propertyNode.parent.parent.callee) - ); - } - return { Property: function (node) { if ( utils.isModuleHookPropertyKey(node.key) && - isInModule(node) + utils.isInModule(node) ) { checkModuleHook(node); } diff --git a/lib/rules/resolve-async.js b/lib/rules/resolve-async.js index 9880cc3b..61d0e256 100644 --- a/lib/rules/resolve-async.js +++ b/lib/rules/resolve-async.js @@ -159,20 +159,6 @@ module.exports = { } } - /** - * @param {import('eslint').Rule.Node} propertyNode - * @returns {boolean} - */ - function isInModule(propertyNode) { - return ( - propertyNode && - propertyNode.parent && // ObjectExpression - propertyNode.parent.parent && // CallExpression? - propertyNode.parent.parent.type === "CallExpression" && - utils.isModule(propertyNode.parent.parent.callee) - ); - } - return { CallExpression: function (node) { const callbackVar = getAsyncCallbackVarOrNull(node.callee); @@ -213,7 +199,7 @@ module.exports = { Property: function (node) { if ( utils.isModuleHookPropertyKey(node.key) && - isInModule(node) + utils.isInModule(node) ) { asyncStateStack.push({ stopSemaphoreCount: 0, @@ -228,7 +214,7 @@ module.exports = { "Property:exit": function (node) { if ( utils.isModuleHookPropertyKey(node.key) && - isInModule(node) + utils.isInModule(node) ) { const asyncState = asyncStateStack.pop(); if (!asyncState) { diff --git a/lib/utils.js b/lib/utils.js index 232a61d4..bdadc3af 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -216,6 +216,20 @@ exports.isModule = function (calleeNode) { return result; }; +/** + * @param {import('eslint').Rule.Node} propertyNode + * @returns {boolean} + */ +exports.isInModule = function (propertyNode) { + return ( + propertyNode && + propertyNode.parent && // ObjectExpression + propertyNode.parent.parent && // CallExpression? + propertyNode.parent.parent.type === "CallExpression" && + exports.isModule(propertyNode.parent.parent.callee) + ); +}; + /** * @param {import('estree').Node} identifierNode * @returns {boolean} diff --git a/tests/lib/rules/no-assert-equal.js b/tests/lib/rules/no-assert-equal.js index 6156c388..5f225a2a 100644 --- a/tests/lib/rules/no-assert-equal.js +++ b/tests/lib/rules/no-assert-equal.js @@ -184,5 +184,29 @@ ruleTester.run("no-assert-equal", rule, { }, ], }, + { + // assert.equal in module hooks + code: "QUnit.module('My module', { beforeEach: function (assert) { assert.equal(1, 1); } });", + errors: [ + { + messageId: "unexpectedAssertEqual", + data: { assertVar: "assert" }, + suggestions: [ + { + messageId: "switchToDeepEqual", + output: "QUnit.module('My module', { beforeEach: function (assert) { assert.deepEqual(1, 1); } });", + }, + { + messageId: "switchToPropEqual", + output: "QUnit.module('My module', { beforeEach: function (assert) { assert.propEqual(1, 1); } });", + }, + { + messageId: "switchToStrictEqual", + output: "QUnit.module('My module', { beforeEach: function (assert) { assert.strictEqual(1, 1); } });", + }, + ], + }, + ], + }, ], });