act-compat.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.asyncAct = asyncAct;
  7. exports.default = void 0;
  8. var React = _interopRequireWildcard(require("react"));
  9. var _reactDom = _interopRequireDefault(require("react-dom"));
  10. var testUtils = _interopRequireWildcard(require("react-dom/test-utils"));
  11. function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
  12. function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  13. const reactAct = testUtils.act;
  14. const actSupported = reactAct !== undefined; // act is supported react-dom@16.8.0
  15. // so for versions that don't have act from test utils
  16. // we do this little polyfill. No warnings, but it's
  17. // better than nothing.
  18. function actPolyfill(cb) {
  19. _reactDom.default.unstable_batchedUpdates(cb);
  20. _reactDom.default.render( /*#__PURE__*/React.createElement("div", null), document.createElement('div'));
  21. }
  22. const act = reactAct || actPolyfill;
  23. let youHaveBeenWarned = false;
  24. let isAsyncActSupported = null;
  25. function asyncAct(cb) {
  26. if (actSupported === true) {
  27. if (isAsyncActSupported === null) {
  28. return new Promise((resolve, reject) => {
  29. // patch console.error here
  30. const originalConsoleError = console.error;
  31. console.error = function error(...args) {
  32. /* if console.error fired *with that specific message* */
  33. /* istanbul ignore next */
  34. const firstArgIsString = typeof args[0] === 'string';
  35. if (firstArgIsString && args[0].indexOf('Warning: Do not await the result of calling ReactTestUtils.act') === 0) {
  36. // v16.8.6
  37. isAsyncActSupported = false;
  38. } else if (firstArgIsString && args[0].indexOf('Warning: The callback passed to ReactTestUtils.act(...) function must not return anything') === 0) {// no-op
  39. } else {
  40. originalConsoleError.apply(console, args);
  41. }
  42. };
  43. let cbReturn, result;
  44. try {
  45. result = reactAct(() => {
  46. cbReturn = cb();
  47. return cbReturn;
  48. });
  49. } catch (err) {
  50. console.error = originalConsoleError;
  51. reject(err);
  52. return;
  53. }
  54. result.then(() => {
  55. console.error = originalConsoleError; // if it got here, it means async act is supported
  56. isAsyncActSupported = true;
  57. resolve();
  58. }, err => {
  59. console.error = originalConsoleError;
  60. isAsyncActSupported = true;
  61. reject(err);
  62. }); // 16.8.6's act().then() doesn't call a resolve handler, so we need to manually flush here, sigh
  63. if (isAsyncActSupported === false) {
  64. console.error = originalConsoleError;
  65. /* istanbul ignore next */
  66. if (!youHaveBeenWarned) {
  67. // if act is supported and async act isn't and they're trying to use async
  68. // act, then they need to upgrade from 16.8 to 16.9.
  69. // This is a seamless upgrade, so we'll add a warning
  70. console.error(`It looks like you're using a version of react-dom that supports the "act" function, but not an awaitable version of "act" which you will need. Please upgrade to at least react-dom@16.9.0 to remove this warning.`);
  71. youHaveBeenWarned = true;
  72. }
  73. cbReturn.then(() => {
  74. // a faux-version.
  75. // todo - copy https://github.com/facebook/react/blob/master/packages/shared/enqueueTask.js
  76. Promise.resolve().then(() => {
  77. // use sync act to flush effects
  78. act(() => {});
  79. resolve();
  80. });
  81. }, reject);
  82. }
  83. });
  84. } else if (isAsyncActSupported === false) {
  85. // use the polyfill directly
  86. let result;
  87. act(() => {
  88. result = cb();
  89. });
  90. return result.then(() => {
  91. return Promise.resolve().then(() => {
  92. // use sync act to flush effects
  93. act(() => {});
  94. });
  95. });
  96. } // all good! regular act
  97. return act(cb);
  98. } // use the polyfill
  99. let result;
  100. act(() => {
  101. result = cb();
  102. });
  103. return result.then(() => {
  104. return Promise.resolve().then(() => {
  105. // use sync act to flush effects
  106. act(() => {});
  107. });
  108. });
  109. }
  110. var _default = act;
  111. /* eslint no-console:0 */
  112. exports.default = _default;