diff --git a/src/language-js/print/call-expression.js b/src/language-js/print/call-expression.js index a896410ca..d8742f322 100644 --- a/src/language-js/print/call-expression.js +++ b/src/language-js/print/call-expression.js @@ -8,9 +8,9 @@ import { isNodeMatches, isStringLiteral, isTemplateOnItsOwnLine, - isTestCall, iterateCallArgumentsPath, } from "../utilities/index.js"; +import { isTestCall } from "../utilities/test-libraries.js"; import printCallArguments from "./call-arguments.js"; import printMemberChain from "./member-chain.js"; import { printOptionalToken } from "./miscellaneous.js"; diff --git a/src/language-js/print/function-parameters.js b/src/language-js/print/function-parameters.js index b328698d5..fb338a345 100644 --- a/src/language-js/print/function-parameters.js +++ b/src/language-js/print/function-parameters.js @@ -20,11 +20,11 @@ import { isObjectExpression, isObjectType, isSimpleType, - isTestCall, isTypeAnnotationAFunction, iterateFunctionParametersPath, shouldPrintComma, } from "../utilities/index.js"; +import { isTestCall } from "../utilities/test-libraries.js"; import { printDanglingCommentsInList } from "./miscellaneous.js"; /** @import AstPath from "../../common/ast-path.js" */ diff --git a/src/language-js/print/type-parameters.js b/src/language-js/print/type-parameters.js index 3d720f657..26f50bb53 100644 --- a/src/language-js/print/type-parameters.js +++ b/src/language-js/print/type-parameters.js @@ -17,9 +17,9 @@ import { getFunctionParameters, hasComment, isObjectType, - isTestCall, shouldPrintComma, } from "../utilities/index.js"; +import { isTestCall } from "../utilities/test-libraries.js"; import { isArrowFunctionVariableDeclarator } from "./assignment.js"; import { printTypeAnnotationProperty, diff --git a/src/language-js/utilities/index.js b/src/language-js/utilities/index.js index 169c429bf..288258736 100644 --- a/src/language-js/utilities/index.js +++ b/src/language-js/utilities/index.js @@ -18,7 +18,6 @@ import getRaw from "./get-raw.js"; import isBlockComment from "./is-block-comment.js"; import isFlowKeywordType from "./is-flow-keyword-type.js"; import isLineComment from "./is-line-comment.js"; -import isNodeMatches from "./is-node-matches.js"; import isTsKeywordType from "./is-ts-keyword-type.js"; import { isArrayExpression, @@ -213,36 +212,6 @@ const isSingleWordType = createTypeCheckFunction([ "PrivateIdentifier", ]); -/** - * @param {Node} node - * @returns {boolean} - */ -function isFunctionOrArrowExpressionWithBody(node) { - return ( - node.type === "FunctionExpression" || - (node.type === "ArrowFunctionExpression" && - node.body.type === "BlockStatement") - ); -} - -/** - * Note: `inject` is used in AngularJS 1.x, `async` and `fakeAsync` in - * Angular 2+, although `async` is deprecated and replaced by `waitForAsync` - * since Angular 12. - * - * example: https://docs.angularjs.org/guide/unit-testing#using-beforeall- - * - * @param {NodeMap["CallExpression"]} node - * @returns {boolean} - */ -function isAngularTestWrapper(node) { - return ( - isCallExpression(node) && - node.callee.type === "Identifier" && - ["async", "inject", "fakeAsync", "waitForAsync"].includes(node.callee.name) - ); -} - function isMethod(node) { return ( (node.method && node.kind === "init") || @@ -317,89 +286,6 @@ function isSimpleType(node) { ); } -/** - * @param {*} node - * @returns {boolean} - */ -function isUnitTestSetupIdentifier(node) { - return ( - node.type === "Identifier" && - (node.name === "beforeEach" || - node.name === "beforeAll" || - node.name === "afterEach" || - node.name === "afterAll") - ); -} - -const testCallCalleePatterns = [ - "it", - "it.only", - "it.skip", - "describe", - "describe.only", - "describe.skip", - "test", - "test.only", - "test.skip", - "test.fixme", - "test.step", - "test.describe", - "test.describe.only", - "test.describe.skip", - "test.describe.fixme", - "test.describe.parallel", - "test.describe.parallel.only", - "test.describe.serial", - "test.describe.serial.only", - "skip", - "xit", - "xdescribe", - "xtest", - "fit", - "fdescribe", - "ftest", -]; - -function isTestCallCallee(node) { - return isNodeMatches(node, testCallCalleePatterns); -} - -// eg; `describe("some string", (done) => {})` -function isTestCall(node, parent) { - if (node?.type !== "CallExpression" || node.optional) { - return false; - } - - const args = getCallArguments(node); - - if (args.length === 1) { - if (isAngularTestWrapper(node) && isTestCall(parent)) { - return isFunctionOrArrowExpression(args[0]); - } - - if (isUnitTestSetupIdentifier(node.callee)) { - return isAngularTestWrapper(args[0]); - } - } else if ( - (args.length === 2 || args.length === 3) && - (args[0].type === "TemplateLiteral" || isStringLiteral(args[0])) && - isTestCallCallee(node.callee) - ) { - // it("name", () => { ... }, 2500) - if (args[2] && !isNumericLiteral(args[2])) { - return false; - } - return ( - (args.length === 2 - ? isFunctionOrArrowExpression(args[1]) - : isFunctionOrArrowExpressionWithBody(args[1]) && - getFunctionParameters(args[1]).length <= 1) || - isAngularTestWrapper(args[1]) - ); - } - return false; -} - /** * Attempts to gauge the rough complexity of a node, for example * to detect deeply-nested booleans, call expressions with lots of arguments, etc. @@ -1189,7 +1075,6 @@ export { isSimpleType, isStringLiteral, isTemplateOnItsOwnLine, - isTestCall, isTsAsConstExpression, isTupleType, isTypeAlias, diff --git a/src/language-js/utilities/test-libraries.js b/src/language-js/utilities/test-libraries.js new file mode 100644 index 000000000..224590511 --- /dev/null +++ b/src/language-js/utilities/test-libraries.js @@ -0,0 +1,134 @@ +import { + getCallArguments, + getFunctionParameters, + isNumericLiteral, + isStringLiteral, +} from "./index.js"; +import isNodeMatches from "./is-node-matches.js"; +import { isCallExpression, isFunctionOrArrowExpression } from "./node-types.js"; + +/** +@import { + Node, + NodeMap, +} from "../types/estree.js"; +*/ + +const testCallCalleePatterns = [ + "it", + "it.only", + "it.skip", + "describe", + "describe.only", + "describe.skip", + "test", + "test.only", + "test.skip", + "test.fixme", + "test.step", + "test.describe", + "test.describe.only", + "test.describe.skip", + "test.describe.fixme", + "test.describe.parallel", + "test.describe.parallel.only", + "test.describe.serial", + "test.describe.serial.only", + "skip", + "xit", + "xdescribe", + "xtest", + "fit", + "fdescribe", + "ftest", +]; + +/** + * @param {Node} node + * @returns {boolean} + */ +function isTestCallCallee(node) { + return isNodeMatches(node, testCallCalleePatterns); +} + +/** + * @param {Node} node + * @returns {boolean} + */ +function isUnitTestSetupIdentifier(node) { + return ( + node.type === "Identifier" && + (node.name === "beforeEach" || + node.name === "beforeAll" || + node.name === "afterEach" || + node.name === "afterAll") + ); +} + +/** + * Note: `inject` is used in AngularJS 1.x, `async` and `fakeAsync` in + * Angular 2+, although `async` is deprecated and replaced by `waitForAsync` + * since Angular 12. + * + * example: https://docs.angularjs.org/guide/unit-testing#using-beforeall- + * + * @param {NodeMap["CallExpression"]} node + * @returns {boolean} + */ +function isAngularTestWrapper(node) { + return ( + isCallExpression(node) && + node.callee.type === "Identifier" && + ["async", "inject", "fakeAsync", "waitForAsync"].includes(node.callee.name) + ); +} + +/** + * @param {Node} node + * @returns {boolean} + */ +function isFunctionOrArrowExpressionWithBody(node) { + return ( + node.type === "FunctionExpression" || + (node.type === "ArrowFunctionExpression" && + node.body.type === "BlockStatement") + ); +} + +// eg; `describe("some string", (done) => {})` +function isTestCall(node, parent) { + if (node?.type !== "CallExpression" || node.optional) { + return false; + } + + const args = getCallArguments(node); + + if (args.length === 1) { + if (isAngularTestWrapper(node) && isTestCall(parent)) { + return isFunctionOrArrowExpression(args[0]); + } + + if (isUnitTestSetupIdentifier(node.callee)) { + return isAngularTestWrapper(args[0]); + } + } else if ( + (args.length === 2 || args.length === 3) && + (args[0].type === "TemplateLiteral" || isStringLiteral(args[0])) && + isTestCallCallee(node.callee) + ) { + // it("name", () => { ... }, 2500) + if (args[2] && !isNumericLiteral(args[2])) { + return false; + } + return ( + (args.length === 2 + ? isFunctionOrArrowExpression(args[1]) + : isFunctionOrArrowExpressionWithBody(args[1]) && + getFunctionParameters(args[1]).length <= 1) || + isAngularTestWrapper(args[1]) + ); + } + return false; +} + +export { isTestCall };