no-unnecessary-act.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.RULE_NAME = void 0;
  4. const utils_1 = require("@typescript-eslint/utils");
  5. const create_testing_library_rule_1 = require("../create-testing-library-rule");
  6. const node_utils_1 = require("../node-utils");
  7. exports.RULE_NAME = 'no-unnecessary-act';
  8. exports.default = (0, create_testing_library_rule_1.createTestingLibraryRule)({
  9. name: exports.RULE_NAME,
  10. meta: {
  11. type: 'problem',
  12. docs: {
  13. description: 'Disallow wrapping Testing Library utils or empty callbacks in `act`',
  14. recommendedConfig: {
  15. dom: false,
  16. angular: false,
  17. react: 'error',
  18. vue: false,
  19. marko: 'error',
  20. },
  21. },
  22. messages: {
  23. noUnnecessaryActTestingLibraryUtil: 'Avoid wrapping Testing Library util calls in `act`',
  24. noUnnecessaryActEmptyFunction: 'Avoid wrapping empty function in `act`',
  25. },
  26. schema: [
  27. {
  28. type: 'object',
  29. properties: {
  30. isStrict: {
  31. type: 'boolean',
  32. },
  33. },
  34. },
  35. ],
  36. },
  37. defaultOptions: [
  38. {
  39. isStrict: true,
  40. },
  41. ],
  42. create(context, [{ isStrict = true }], helpers) {
  43. function getStatementIdentifier(statement) {
  44. const callExpression = (0, node_utils_1.getStatementCallExpression)(statement);
  45. if (!callExpression &&
  46. !(0, node_utils_1.isExpressionStatement)(statement) &&
  47. !(0, node_utils_1.isReturnStatement)(statement)) {
  48. return null;
  49. }
  50. if (callExpression) {
  51. return (0, node_utils_1.getDeepestIdentifierNode)(callExpression);
  52. }
  53. if ((0, node_utils_1.isExpressionStatement)(statement) &&
  54. utils_1.ASTUtils.isAwaitExpression(statement.expression)) {
  55. return (0, node_utils_1.getPropertyIdentifierNode)(statement.expression.argument);
  56. }
  57. if ((0, node_utils_1.isReturnStatement)(statement) && statement.argument) {
  58. return (0, node_utils_1.getPropertyIdentifierNode)(statement.argument);
  59. }
  60. return null;
  61. }
  62. function hasSomeNonTestingLibraryCall(statements) {
  63. return statements.some((statement) => {
  64. const identifier = getStatementIdentifier(statement);
  65. if (!identifier) {
  66. return false;
  67. }
  68. return !helpers.isTestingLibraryUtil(identifier);
  69. });
  70. }
  71. function hasTestingLibraryCall(statements) {
  72. return statements.some((statement) => {
  73. const identifier = getStatementIdentifier(statement);
  74. if (!identifier) {
  75. return false;
  76. }
  77. return helpers.isTestingLibraryUtil(identifier);
  78. });
  79. }
  80. function checkNoUnnecessaryActFromBlockStatement(blockStatementNode) {
  81. const functionNode = blockStatementNode.parent;
  82. const callExpressionNode = functionNode === null || functionNode === void 0 ? void 0 : functionNode.parent;
  83. if (!callExpressionNode || !functionNode) {
  84. return;
  85. }
  86. const identifierNode = (0, node_utils_1.getDeepestIdentifierNode)(callExpressionNode);
  87. if (!identifierNode) {
  88. return;
  89. }
  90. if (!helpers.isActUtil(identifierNode)) {
  91. return;
  92. }
  93. if ((0, node_utils_1.isEmptyFunction)(functionNode)) {
  94. context.report({
  95. node: identifierNode,
  96. messageId: 'noUnnecessaryActEmptyFunction',
  97. });
  98. return;
  99. }
  100. const shouldBeReported = isStrict
  101. ? hasTestingLibraryCall(blockStatementNode.body)
  102. : !hasSomeNonTestingLibraryCall(blockStatementNode.body);
  103. if (shouldBeReported) {
  104. context.report({
  105. node: identifierNode,
  106. messageId: 'noUnnecessaryActTestingLibraryUtil',
  107. });
  108. }
  109. }
  110. function checkNoUnnecessaryActFromImplicitReturn(node) {
  111. var _a;
  112. const nodeIdentifier = (0, node_utils_1.getDeepestIdentifierNode)(node);
  113. if (!nodeIdentifier) {
  114. return;
  115. }
  116. const parentCallExpression = (_a = node.parent) === null || _a === void 0 ? void 0 : _a.parent;
  117. if (!parentCallExpression) {
  118. return;
  119. }
  120. const identifierNode = (0, node_utils_1.getDeepestIdentifierNode)(parentCallExpression);
  121. if (!identifierNode) {
  122. return;
  123. }
  124. if (!helpers.isActUtil(identifierNode)) {
  125. return;
  126. }
  127. if (!helpers.isTestingLibraryUtil(nodeIdentifier)) {
  128. return;
  129. }
  130. context.report({
  131. node: identifierNode,
  132. messageId: 'noUnnecessaryActTestingLibraryUtil',
  133. });
  134. }
  135. return {
  136. 'CallExpression > ArrowFunctionExpression > BlockStatement': checkNoUnnecessaryActFromBlockStatement,
  137. 'CallExpression > FunctionExpression > BlockStatement': checkNoUnnecessaryActFromBlockStatement,
  138. 'CallExpression > ArrowFunctionExpression > CallExpression': checkNoUnnecessaryActFromImplicitReturn,
  139. };
  140. },
  141. });