79 lines · 2.5 KB · JavaScript
RawDownload
import { getCallName } from "../utils.js";import { isTestLike } from "../utils.js";import { unwrapExpression } from "../utils.js"; const testRegistrars = new Set(["it", "test"]); const isFunction = (node) =>  node?.type === "ArrowFunctionExpression" ||  node?.type === "FunctionExpression" ||  node?.type === "FunctionDeclaration"; const isTestRegistrationCall = (node) => {  const callee = unwrapExpression(node.callee);  if (callee?.type === "Identifier") return testRegistrars.has(callee.name);  if (callee?.type !== "MemberExpression") return false;   const object = unwrapExpression(callee.object);  return object?.type === "Identifier" && testRegistrars.has(object.name);}; export default {  meta: {    type: "problem",    docs: {      description: "Disallow conditional expect calls inside tests.",    },  },  create(context) {    if (!isTestLike(context.filename)) return {};     const testCallbacks = new WeakSet();    let testDepth = 0;    let conditionalDepth = 0;     const enterFunction = (node) => {      if (testCallbacks.has(node)) testDepth++;    };    const exitFunction = (node) => {      if (testCallbacks.has(node)) testDepth--;    };    const enterConditional = () => {      if (testDepth > 0) conditionalDepth++;    };    const exitConditional = () => {      if (testDepth > 0) conditionalDepth--;    };     return {      CallExpression(node) {        if (isTestRegistrationCall(node)) {          const callback = node.arguments.find(isFunction);          if (callback) testCallbacks.add(callback);        }         if (testDepth === 0 || conditionalDepth === 0) return;        const name = getCallName(node.callee);        if (name !== "expect") return;        context.report({          node,          message: "Avoid conditional expect calls; split the test or assert both branches explicitly.",        });      },      FunctionDeclaration: enterFunction,      "FunctionDeclaration:exit": exitFunction,      FunctionExpression: enterFunction,      "FunctionExpression:exit": exitFunction,      ArrowFunctionExpression: enterFunction,      "ArrowFunctionExpression:exit": exitFunction,      IfStatement: enterConditional,      "IfStatement:exit": exitConditional,      ConditionalExpression: enterConditional,      "ConditionalExpression:exit": exitConditional,      LogicalExpression: enterConditional,      "LogicalExpression:exit": exitConditional,      SwitchCase: enterConditional,      "SwitchCase:exit": exitConditional,    };  },};