no-wait-for-side-effects.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.RULE_NAME = void 0;
  4. const create_testing_library_rule_1 = require("../create-testing-library-rule");
  5. const node_utils_1 = require("../node-utils");
  6. exports.RULE_NAME = 'no-wait-for-side-effects';
  7. exports.default = (0, create_testing_library_rule_1.createTestingLibraryRule)({
  8. name: exports.RULE_NAME,
  9. meta: {
  10. type: 'suggestion',
  11. docs: {
  12. description: 'Disallow the use of side effects in `waitFor`',
  13. recommendedConfig: {
  14. dom: 'error',
  15. angular: 'error',
  16. react: 'error',
  17. vue: 'error',
  18. marko: 'error',
  19. },
  20. },
  21. messages: {
  22. noSideEffectsWaitFor: 'Avoid using side effects within `waitFor` callback',
  23. },
  24. schema: [],
  25. },
  26. defaultOptions: [],
  27. create(context, _, helpers) {
  28. function isCallerWaitFor(node) {
  29. if (!node.parent) {
  30. return false;
  31. }
  32. const callExpressionNode = node.parent.parent;
  33. const callExpressionIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(callExpressionNode);
  34. return (!!callExpressionIdentifier &&
  35. helpers.isAsyncUtil(callExpressionIdentifier, ['waitFor']));
  36. }
  37. function isCallerThen(node) {
  38. if (!node.parent) {
  39. return false;
  40. }
  41. const callExpressionNode = node.parent.parent;
  42. return (0, node_utils_1.hasThenProperty)(callExpressionNode.callee);
  43. }
  44. function isRenderInVariableDeclaration(node) {
  45. return ((0, node_utils_1.isVariableDeclaration)(node) &&
  46. node.declarations.some(helpers.isRenderVariableDeclarator));
  47. }
  48. function isRenderInExpressionStatement(node) {
  49. if (!(0, node_utils_1.isExpressionStatement)(node) ||
  50. !(0, node_utils_1.isAssignmentExpression)(node.expression)) {
  51. return false;
  52. }
  53. const expressionIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(node.expression.right);
  54. if (!expressionIdentifier) {
  55. return false;
  56. }
  57. return helpers.isRenderUtil(expressionIdentifier);
  58. }
  59. function isRenderInAssignmentExpression(node) {
  60. if (!(0, node_utils_1.isAssignmentExpression)(node)) {
  61. return false;
  62. }
  63. const expressionIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(node.right);
  64. if (!expressionIdentifier) {
  65. return false;
  66. }
  67. return helpers.isRenderUtil(expressionIdentifier);
  68. }
  69. function isRenderInSequenceAssignment(node) {
  70. if (!(0, node_utils_1.isSequenceExpression)(node)) {
  71. return false;
  72. }
  73. return node.expressions.some(isRenderInAssignmentExpression);
  74. }
  75. function isSideEffectInVariableDeclaration(node) {
  76. return node.declarations.some((declaration) => {
  77. if ((0, node_utils_1.isCallExpression)(declaration.init)) {
  78. const test = (0, node_utils_1.getPropertyIdentifierNode)(declaration.init);
  79. if (!test) {
  80. return false;
  81. }
  82. return (helpers.isFireEventUtil(test) ||
  83. helpers.isUserEventUtil(test) ||
  84. helpers.isRenderUtil(test));
  85. }
  86. return false;
  87. });
  88. return false;
  89. }
  90. function getSideEffectNodes(body) {
  91. return body.filter((node) => {
  92. if (!(0, node_utils_1.isExpressionStatement)(node) && !(0, node_utils_1.isVariableDeclaration)(node)) {
  93. return false;
  94. }
  95. if (isRenderInVariableDeclaration(node) ||
  96. isRenderInExpressionStatement(node)) {
  97. return true;
  98. }
  99. if ((0, node_utils_1.isVariableDeclaration)(node) &&
  100. isSideEffectInVariableDeclaration(node)) {
  101. return true;
  102. }
  103. const expressionIdentifier = (0, node_utils_1.getPropertyIdentifierNode)(node);
  104. if (!expressionIdentifier) {
  105. return false;
  106. }
  107. return (helpers.isFireEventUtil(expressionIdentifier) ||
  108. helpers.isUserEventUtil(expressionIdentifier) ||
  109. helpers.isRenderUtil(expressionIdentifier));
  110. });
  111. }
  112. function reportSideEffects(node) {
  113. if (!isCallerWaitFor(node)) {
  114. return;
  115. }
  116. if (isCallerThen(node)) {
  117. return;
  118. }
  119. getSideEffectNodes(node.body).forEach((sideEffectNode) => context.report({
  120. node: sideEffectNode,
  121. messageId: 'noSideEffectsWaitFor',
  122. }));
  123. }
  124. function reportImplicitReturnSideEffect(node) {
  125. if (!isCallerWaitFor(node)) {
  126. return;
  127. }
  128. const expressionIdentifier = (0, node_utils_1.isCallExpression)(node)
  129. ? (0, node_utils_1.getPropertyIdentifierNode)(node.callee)
  130. : null;
  131. if (!expressionIdentifier &&
  132. !isRenderInAssignmentExpression(node) &&
  133. !isRenderInSequenceAssignment(node)) {
  134. return;
  135. }
  136. if (expressionIdentifier &&
  137. !helpers.isFireEventUtil(expressionIdentifier) &&
  138. !helpers.isUserEventUtil(expressionIdentifier) &&
  139. !helpers.isRenderUtil(expressionIdentifier)) {
  140. return;
  141. }
  142. context.report({
  143. node,
  144. messageId: 'noSideEffectsWaitFor',
  145. });
  146. }
  147. return {
  148. 'CallExpression > ArrowFunctionExpression > BlockStatement': reportSideEffects,
  149. 'CallExpression > ArrowFunctionExpression > CallExpression': reportImplicitReturnSideEffect,
  150. 'CallExpression > ArrowFunctionExpression > AssignmentExpression': reportImplicitReturnSideEffect,
  151. 'CallExpression > ArrowFunctionExpression > SequenceExpression': reportImplicitReturnSideEffect,
  152. 'CallExpression > FunctionExpression > BlockStatement': reportSideEffects,
  153. };
  154. },
  155. });