diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
index 5c092f5853288..6ab8fe74a9cf0 100644
--- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
+++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js
@@ -146,7 +146,10 @@ describe('ReactHooksInspectionIntegration', () => {
);
}
- let renderer = ReactTestRenderer.create();
+ let renderer;
+ act(() => {
+ renderer = ReactTestRenderer.create();
+ });
let childFiber = renderer.root.findByType(Foo)._currentFiber();
diff --git a/packages/react-dom/src/__tests__/ReactDOMHooks-test.js b/packages/react-dom/src/__tests__/ReactDOMHooks-test.js
index 4f24770546176..ec23c88fa981f 100644
--- a/packages/react-dom/src/__tests__/ReactDOMHooks-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMHooks-test.js
@@ -53,23 +53,32 @@ describe('ReactDOMHooks', () => {
return 3 * n;
}
- ReactDOM.render(, container);
- expect(container.textContent).toBe('1');
- expect(container2.textContent).toBe('');
- expect(container3.textContent).toBe('');
- Scheduler.flushAll();
- expect(container.textContent).toBe('1');
- expect(container2.textContent).toBe('2');
- expect(container3.textContent).toBe('3');
-
- ReactDOM.render(, container);
- expect(container.textContent).toBe('2');
- expect(container2.textContent).toBe('2'); // Not flushed yet
- expect(container3.textContent).toBe('3'); // Not flushed yet
- Scheduler.flushAll();
- expect(container.textContent).toBe('2');
- expect(container2.textContent).toBe('4');
- expect(container3.textContent).toBe('6');
+ // we explicitly catch the missing act() warnings
+ // to simulate this tricky repro
+ expect(() => {
+ ReactDOM.render(, container);
+ expect(container.textContent).toBe('1');
+ expect(container2.textContent).toBe('');
+ expect(container3.textContent).toBe('');
+ Scheduler.flushAll();
+ expect(container.textContent).toBe('1');
+ expect(container2.textContent).toBe('2');
+ expect(container3.textContent).toBe('3');
+
+ ReactDOM.render(, container);
+ expect(container.textContent).toBe('2');
+ expect(container2.textContent).toBe('2'); // Not flushed yet
+ expect(container3.textContent).toBe('3'); // Not flushed yet
+ Scheduler.flushAll();
+ expect(container.textContent).toBe('2');
+ expect(container2.textContent).toBe('4');
+ expect(container3.textContent).toBe('6');
+ }).toWarnDev([
+ 'An update to Example1 ran an effect',
+ 'An update to Example2 ran an effect',
+ 'An update to Example1 ran an effect',
+ 'An update to Example2 ran an effect',
+ ]);
});
it('should not bail out when an update is scheduled from within an event handler', () => {
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js
index 50fd7ae16bc8e..c60ed8770b310 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js
@@ -13,6 +13,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
+let ReactTestUtils;
let ReactDOMServer;
function initModules() {
@@ -21,11 +22,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationBasic-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationBasic-test.js
index 114907ef7d177..72ac5ff06b49f 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationBasic-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationBasic-test.js
@@ -16,6 +16,7 @@ const TEXT_NODE_TYPE = 3;
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -23,11 +24,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationCheckbox-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationCheckbox-test.js
index 03e7c4b984480..3280ed5e0626c 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationCheckbox-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationCheckbox-test.js
@@ -16,6 +16,7 @@ const {disableInputAttributeSyncing} = require('shared/ReactFeatureFlags');
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -23,11 +24,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationClassContextType-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationClassContextType-test.js
index 19839aa7cd6c2..a24e969d0f527 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationClassContextType-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationClassContextType-test.js
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -21,11 +22,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js
index 535191d66e8a7..8b66321f8692a 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js
@@ -16,17 +16,20 @@ const TEXT_NODE_TYPE = 3;
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
jest.resetModuleRegistry();
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationFragment-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationFragment-test.js
index 8c93ee9eea556..d1144aebdaedf 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationFragment-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationFragment-test.js
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -21,11 +22,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js
index a0a91763a82cf..b4f99453cd328 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js
@@ -17,6 +17,7 @@ let React;
let ReactFeatureFlags;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
let useState;
let useReducer;
let useEffect;
@@ -41,6 +42,7 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
useState = React.useState;
useReducer = React.useReducer;
useEffect = React.useEffect;
@@ -67,6 +69,7 @@ function initModules() {
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
@@ -539,18 +542,30 @@ describe('ReactDOMServerHooks', () => {
});
describe('useEffect', () => {
+ const yields = [];
itRenders('should ignore effects on the server', async render => {
function Counter(props) {
useEffect(() => {
- yieldValue('should not be invoked');
+ yieldValue('invoked on client');
});
return ;
}
+
const domNode = await render();
- expect(clearYields()).toEqual(['Count: 0']);
+ yields.push(clearYields());
expect(domNode.tagName).toEqual('SPAN');
expect(domNode.textContent).toEqual('Count: 0');
});
+
+ it('verifies yields in order', () => {
+ expect(yields).toEqual([
+ ['Count: 0'], // server render
+ ['Count: 0'], // server stream
+ ['Count: 0', 'invoked on client'], // clean render
+ ['Count: 0', 'invoked on client'], // hydrated render
+ // nothing yielded for bad markup
+ ]);
+ });
});
describe('useCallback', () => {
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationInput-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationInput-test.js
index d637755d02c0b..9ca1c92d8d427 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationInput-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationInput-test.js
@@ -16,6 +16,7 @@ const {disableInputAttributeSyncing} = require('shared/ReactFeatureFlags');
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -23,11 +24,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js
index e801902011b61..4c78919bd8480 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js
@@ -15,6 +15,7 @@ let PropTypes;
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -23,11 +24,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationModes-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationModes-test.js
index b9f8a5c48c8a1..188ab02991868 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationModes-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationModes-test.js
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -21,11 +22,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js
index 071dd8715751c..6089daa80af29 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -21,11 +22,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationReconnecting-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationReconnecting-test.js
index b6428b1fa3824..aba74c2f34fcf 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationReconnecting-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationReconnecting-test.js
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -22,11 +23,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js
index ccb9a60607833..4d39fce80c885 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -21,11 +22,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationSelect-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationSelect-test.js
index 486b2a81a6925..3871ad975e743 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationSelect-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationSelect-test.js
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -21,11 +22,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationSpecialTypes-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationSpecialTypes-test.js
index b56d36b626a76..2cc696ae6e4e8 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationSpecialTypes-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationSpecialTypes-test.js
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
let forwardRef;
let memo;
let yieldedValues;
@@ -26,6 +27,7 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
forwardRef = React.forwardRef;
memo = React.memo;
@@ -43,6 +45,7 @@ function initModules() {
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationTextarea-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationTextarea-test.js
index 2b0faddcd2c44..261b6c041495a 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationTextarea-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationTextarea-test.js
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -21,11 +22,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationUntrustedURL-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationUntrustedURL-test.internal.js
index 21a4cc1b6dc87..897e2d51183b2 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationUntrustedURL-test.internal.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationUntrustedURL-test.internal.js
@@ -16,6 +16,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function runTests(itRenders, itRejectsRendering, expectToReject) {
itRenders('a http link with the word javascript in it', async render => {
@@ -152,11 +153,13 @@ describe('ReactDOMServerIntegration - Untrusted URLs', () => {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
@@ -185,11 +188,13 @@ describe('ReactDOMServerIntegration - Untrusted URLs - disableJavaScriptURLs', (
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationUserInteraction-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationUserInteraction-test.js
index 558aad7648b40..c0e2733c54169 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationUserInteraction-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationUserInteraction-test.js
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -21,11 +22,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMServerSuspense-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerSuspense-test.internal.js
index bab90592430de..434fc6c8a507f 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerSuspense-test.internal.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerSuspense-test.internal.js
@@ -15,6 +15,7 @@ let React;
let ReactDOM;
let ReactDOMServer;
let ReactFeatureFlags;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -26,11 +27,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactDOMserverIntegrationProgress-test.js b/packages/react-dom/src/__tests__/ReactDOMserverIntegrationProgress-test.js
index 4a8eb06faace6..5ff530b10a858 100644
--- a/packages/react-dom/src/__tests__/ReactDOMserverIntegrationProgress-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMserverIntegrationProgress-test.js
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
let React;
let ReactDOM;
let ReactDOMServer;
+let ReactTestUtils;
function initModules() {
// Reset warning cache.
@@ -21,11 +22,13 @@ function initModules() {
React = require('react');
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
+ ReactTestUtils = require('react-dom/test-utils');
// Make them available to the helpers.
return {
ReactDOM,
ReactDOMServer,
+ ReactTestUtils,
};
}
diff --git a/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js b/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js
index 3b19a87ecbf87..478d30d136538 100644
--- a/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js
+++ b/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js
@@ -12,8 +12,8 @@
let PropTypes;
let React;
let ReactDOM;
+let act;
let ReactFeatureFlags;
-let Scheduler;
describe('ReactErrorBoundaries', () => {
let log;
@@ -45,7 +45,7 @@ describe('ReactErrorBoundaries', () => {
ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
ReactDOM = require('react-dom');
React = require('react');
- Scheduler = require('scheduler');
+ act = require('react-dom/test-utils').act;
log = [];
@@ -1835,25 +1835,26 @@ describe('ReactErrorBoundaries', () => {
it('catches errors in useEffect', () => {
const container = document.createElement('div');
- ReactDOM.render(
-
- Initial value
- ,
- container,
- );
- expect(log).toEqual([
- 'ErrorBoundary constructor',
- 'ErrorBoundary componentWillMount',
- 'ErrorBoundary render success',
- 'BrokenUseEffect render',
- 'ErrorBoundary componentDidMount',
- ]);
-
- expect(container.firstChild.textContent).toBe('Initial value');
- log.length = 0;
-
- // Flush passive effects and handle the error
- Scheduler.flushAll();
+ act(() => {
+ ReactDOM.render(
+
+ Initial value
+ ,
+ container,
+ );
+ expect(log).toEqual([
+ 'ErrorBoundary constructor',
+ 'ErrorBoundary componentWillMount',
+ 'ErrorBoundary render success',
+ 'BrokenUseEffect render',
+ 'ErrorBoundary componentDidMount',
+ ]);
+
+ expect(container.firstChild.textContent).toBe('Initial value');
+ log.length = 0;
+ });
+
+ // verify flushed passive effects and handle the error
expect(log).toEqual([
'BrokenUseEffect useEffect [!]',
// Handle the error
diff --git a/packages/react-dom/src/__tests__/ReactUpdates-test.js b/packages/react-dom/src/__tests__/ReactUpdates-test.js
index 0b6a4b2792f3f..6d7435fe4cde7 100644
--- a/packages/react-dom/src/__tests__/ReactUpdates-test.js
+++ b/packages/react-dom/src/__tests__/ReactUpdates-test.js
@@ -12,6 +12,7 @@
let React;
let ReactDOM;
let ReactTestUtils;
+let act;
let Scheduler;
describe('ReactUpdates', () => {
@@ -20,6 +21,7 @@ describe('ReactUpdates', () => {
React = require('react');
ReactDOM = require('react-dom');
ReactTestUtils = require('react-dom/test-utils');
+ act = ReactTestUtils.act;
Scheduler = require('scheduler');
});
@@ -1322,30 +1324,31 @@ describe('ReactUpdates', () => {
}
const root = ReactDOM.unstable_createRoot(container);
- root.render();
- if (__DEV__) {
- expect(Scheduler).toFlushAndYieldThrough([
- 'Foo',
- 'Foo',
- 'Baz',
- 'Foo#effect',
- ]);
- } else {
- expect(Scheduler).toFlushAndYieldThrough(['Foo', 'Baz', 'Foo#effect']);
- }
-
- const hiddenDiv = container.firstChild.firstChild;
- expect(hiddenDiv.hidden).toBe(true);
- expect(hiddenDiv.innerHTML).toBe('');
-
- // Run offscreen update
- if (__DEV__) {
- expect(Scheduler).toFlushAndYield(['Bar', 'Bar']);
- } else {
- expect(Scheduler).toFlushAndYield(['Bar']);
- }
- expect(hiddenDiv.hidden).toBe(true);
- expect(hiddenDiv.innerHTML).toBe('
bar 0
');
+ let hiddenDiv;
+ act(() => {
+ root.render();
+ if (__DEV__) {
+ expect(Scheduler).toFlushAndYieldThrough([
+ 'Foo',
+ 'Foo',
+ 'Baz',
+ 'Foo#effect',
+ ]);
+ } else {
+ expect(Scheduler).toFlushAndYieldThrough(['Foo', 'Baz', 'Foo#effect']);
+ }
+ hiddenDiv = container.firstChild.firstChild;
+ expect(hiddenDiv.hidden).toBe(true);
+ expect(hiddenDiv.innerHTML).toBe('');
+ // Run offscreen update
+ if (__DEV__) {
+ expect(Scheduler).toFlushAndYield(['Bar', 'Bar']);
+ } else {
+ expect(Scheduler).toFlushAndYield(['Bar']);
+ }
+ expect(hiddenDiv.hidden).toBe(true);
+ expect(hiddenDiv.innerHTML).toBe('bar 0
');
+ });
ReactDOM.flushSync(() => {
setCounter(1);
@@ -1623,12 +1626,18 @@ describe('ReactUpdates', () => {
};
try {
const container = document.createElement('div');
- ReactDOM.render(, container);
- while (error === null) {
- Scheduler.unstable_flushNumberOfYields(1);
- }
- expect(error).toContain('Warning: Maximum update depth exceeded.');
- expect(stack).toContain('in NonTerminating');
+ expect(() => {
+ act(() => {
+ ReactDOM.render(, container);
+ while (error === null) {
+ Scheduler.unstable_flushNumberOfYields(1);
+ }
+ expect(error).toContain('Warning: Maximum update depth exceeded.');
+ expect(stack).toContain('in NonTerminating');
+ // rethrow error to prevent going into an infinite loop when act() exits
+ throw error;
+ });
+ }).toThrow('Maximum update depth exceeded.');
} finally {
console.error = originalConsoleError;
}
@@ -1651,7 +1660,9 @@ describe('ReactUpdates', () => {
}
const container = document.createElement('div');
- ReactDOM.render(, container);
+ act(() => {
+ ReactDOM.render(, container);
+ });
// Verify we can flush them asynchronously without warning
for (let i = 0; i < LIMIT * 2; i++) {
@@ -1660,16 +1671,16 @@ describe('ReactUpdates', () => {
expect(container.textContent).toBe('50');
// Verify restarting from 0 doesn't cross the limit
- expect(() => {
+ act(() => {
_setStep(0);
- }).toWarnDev(
- 'An update to Terminating inside a test was not wrapped in act',
- );
- expect(container.textContent).toBe('0');
- for (let i = 0; i < LIMIT * 2; i++) {
+ // flush once to update the dom
Scheduler.unstable_flushNumberOfYields(1);
- }
- expect(container.textContent).toBe('50');
+ expect(container.textContent).toBe('0');
+ for (let i = 0; i < LIMIT * 2; i++) {
+ Scheduler.unstable_flushNumberOfYields(1);
+ }
+ expect(container.textContent).toBe('50');
+ });
});
it('can have many updates inside useEffect without triggering a warning', () => {
@@ -1685,8 +1696,11 @@ describe('ReactUpdates', () => {
}
const container = document.createElement('div');
- ReactDOM.render(, container);
- expect(Scheduler).toFlushAndYield(['Done']);
+ act(() => {
+ ReactDOM.render(, container);
+ });
+
+ expect(Scheduler).toHaveYielded(['Done']);
expect(container.textContent).toBe('1000');
});
}
diff --git a/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js b/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js
index 55350b42a378e..c4f7f7bada09f 100644
--- a/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js
+++ b/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js
@@ -14,9 +14,10 @@ const stream = require('stream');
module.exports = function(initModules) {
let ReactDOM;
let ReactDOMServer;
+ let ReactTestUtils;
function resetModules() {
- ({ReactDOM, ReactDOMServer} = initModules());
+ ({ReactDOM, ReactDOMServer, ReactTestUtils} = initModules());
}
function shouldUseDocument(reactElement) {
@@ -48,9 +49,13 @@ module.exports = function(initModules) {
function asyncReactDOMRender(reactElement, domElement, forceHydrate) {
return new Promise(resolve => {
if (forceHydrate) {
- ReactDOM.hydrate(reactElement, domElement);
+ ReactTestUtils.act(() => {
+ ReactDOM.hydrate(reactElement, domElement);
+ });
} else {
- ReactDOM.render(reactElement, domElement);
+ ReactTestUtils.act(() => {
+ ReactDOM.render(reactElement, domElement);
+ });
}
// We can't use the callback for resolution because that will not catch
// errors. They're thrown.
diff --git a/packages/react-reconciler/src/ReactFiberHooks.js b/packages/react-reconciler/src/ReactFiberHooks.js
index 7f9372bdc7159..1ed7ecb7247f7 100644
--- a/packages/react-reconciler/src/ReactFiberHooks.js
+++ b/packages/react-reconciler/src/ReactFiberHooks.js
@@ -35,6 +35,7 @@ import {
computeExpirationForFiber,
flushPassiveEffects,
requestCurrentTime,
+ warnIfNotCurrentlyActingEffectsInDEV,
warnIfNotCurrentlyActingUpdatesInDev,
warnIfNotScopedWithMatchingAct,
markRenderEventTimeAndConfig,
@@ -898,6 +899,14 @@ function mountEffect(
create: () => (() => void) | void,
deps: Array | void | null,
): void {
+ if (__DEV__) {
+ // $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests
+ if ('undefined' !== typeof jest) {
+ warnIfNotCurrentlyActingEffectsInDEV(
+ ((currentlyRenderingFiber: any): Fiber),
+ );
+ }
+ }
return mountEffectImpl(
UpdateEffect | PassiveEffect,
UnmountPassive | MountPassive,
@@ -910,6 +919,14 @@ function updateEffect(
create: () => (() => void) | void,
deps: Array | void | null,
): void {
+ if (__DEV__) {
+ // $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests
+ if ('undefined' !== typeof jest) {
+ warnIfNotCurrentlyActingEffectsInDEV(
+ ((currentlyRenderingFiber: any): Fiber),
+ );
+ }
+ }
return updateEffectImpl(
UpdateEffect | PassiveEffect,
UnmountPassive | MountPassive,
diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.js b/packages/react-reconciler/src/ReactFiberWorkLoop.js
index 57b0913dd8d91..ebf98cf617b41 100644
--- a/packages/react-reconciler/src/ReactFiberWorkLoop.js
+++ b/packages/react-reconciler/src/ReactFiberWorkLoop.js
@@ -2429,6 +2429,29 @@ export function warnIfNotScopedWithMatchingAct(fiber: Fiber): void {
}
}
+export function warnIfNotCurrentlyActingEffectsInDEV(fiber: Fiber): void {
+ if (__DEV__) {
+ if (ReactCurrentActingRendererSigil.current !== ReactActingRendererSigil) {
+ warningWithoutStack(
+ false,
+ 'An update to %s ran an effect, but was not wrapped in act(...).\n\n' +
+ 'When testing, code that causes React state updates should be ' +
+ 'wrapped into act(...):\n\n' +
+ 'act(() => {\n' +
+ ' /* fire events that update state */\n' +
+ '});\n' +
+ '/* assert on the output */\n\n' +
+ "This ensures that you're testing the behavior the user would see " +
+ 'in the browser.' +
+ ' Learn more at https://fb.me/react-wrap-tests-with-act' +
+ '%s',
+ getComponentName(fiber.type),
+ getStackByFiberInDevAndProd(fiber),
+ );
+ }
+ }
+}
+
function warnIfNotCurrentlyActingUpdatesInDEV(fiber: Fiber): void {
if (__DEV__) {
if (
diff --git a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
index 74152cbcc6c31..ea6e3103edfe1 100644
--- a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
@@ -652,7 +652,9 @@ describe('ReactHooks', () => {
}
expect(() => {
- ReactTestRenderer.create();
+ act(() => {
+ ReactTestRenderer.create();
+ });
}).toWarnDev([
'Warning: useEffect received a final argument that is not an array (instead, received `string`). ' +
'When specified, the final argument must be an array.',
@@ -664,7 +666,9 @@ describe('ReactHooks', () => {
'When specified, the final argument must be an array.',
]);
expect(() => {
- ReactTestRenderer.create();
+ act(() => {
+ ReactTestRenderer.create();
+ });
}).toWarnDev([
'Warning: useEffect received a final argument that is not an array (instead, received `number`). ' +
'When specified, the final argument must be an array.',
@@ -676,7 +680,9 @@ describe('ReactHooks', () => {
'When specified, the final argument must be an array.',
]);
expect(() => {
- ReactTestRenderer.create();
+ act(() => {
+ ReactTestRenderer.create();
+ });
}).toWarnDev([
'Warning: useEffect received a final argument that is not an array (instead, received `object`). ' +
'When specified, the final argument must be an array.',
@@ -687,9 +693,12 @@ describe('ReactHooks', () => {
'Warning: useCallback received a final argument that is not an array (instead, received `object`). ' +
'When specified, the final argument must be an array.',
]);
- ReactTestRenderer.create();
- ReactTestRenderer.create();
- ReactTestRenderer.create();
+
+ act(() => {
+ ReactTestRenderer.create();
+ ReactTestRenderer.create();
+ ReactTestRenderer.create();
+ });
});
it('warns if deps is not an array for useImperativeHandle', () => {
@@ -980,8 +989,11 @@ describe('ReactHooks', () => {
return null;
}
- const root = ReactTestRenderer.create();
- expect(() => root.update()).toThrow(
+ expect(() => {
+ act(() => {
+ ReactTestRenderer.create();
+ });
+ }).toThrow(
// The exact message doesn't matter, just make sure we don't allow this
'Context can only be read while React is rendering',
);
@@ -1173,7 +1185,9 @@ describe('ReactHooks', () => {
}
// Verify it doesn't think we're still inside a Hook.
// Should have no warnings.
- ReactTestRenderer.create();
+ act(() => {
+ ReactTestRenderer.create();
+ });
// Verify warnings don't get permanently disabled.
expect(() => {
@@ -1499,10 +1513,15 @@ describe('ReactHooks', () => {
return null;
/* eslint-enable no-unused-vars */
}
- let root = ReactTestRenderer.create();
+ let root;
+ act(() => {
+ root = ReactTestRenderer.create();
+ });
expect(() => {
try {
- root.update();
+ act(() => {
+ root.update();
+ });
} catch (error) {
// Swapping certain types of hooks will cause runtime errors.
// This is okay as far as this test is concerned.
@@ -1521,7 +1540,9 @@ describe('ReactHooks', () => {
// further warnings for this component are silenced
try {
- root.update();
+ act(() => {
+ root.update();
+ });
} catch (error) {
// Swapping certain types of hooks will cause runtime errors.
// This is okay as far as this test is concerned.
@@ -1542,10 +1563,16 @@ describe('ReactHooks', () => {
return null;
/* eslint-enable no-unused-vars */
}
- let root = ReactTestRenderer.create();
+ let root;
+ act(() => {
+ root = ReactTestRenderer.create();
+ });
+
expect(() => {
try {
- root.update();
+ act(() => {
+ root.update();
+ });
} catch (error) {
// Swapping certain types of hooks will cause runtime errors.
// This is okay as far as this test is concerned.
@@ -1604,9 +1631,15 @@ describe('ReactHooks', () => {
return null;
/* eslint-enable no-unused-vars */
}
- let root = ReactTestRenderer.create();
+ let root;
+ act(() => {
+ root = ReactTestRenderer.create();
+ });
+
expect(() => {
- root.update();
+ act(() => {
+ root.update();
+ });
}).toThrow('Rendered fewer hooks than expected.');
});
});
@@ -1767,6 +1800,7 @@ describe('ReactHooks', () => {
globalListener();
globalListener();
}).toWarnDev([
+ 'An update to C ran an effect',
'An update to C inside a test was not wrapped in act',
'An update to C inside a test was not wrapped in act',
// Note: should *not* warn about updates on unmounted component.
@@ -1908,11 +1942,14 @@ describe('ReactHooks', () => {
return 'Throw!';
}
- const root = ReactTestRenderer.create(
-
-
- ,
- );
+ let root;
+ act(() => {
+ root = ReactTestRenderer.create(
+
+
+ ,
+ );
+ });
expect(root).toMatchRenderedOutput('Throw!');
act(() => setShouldThrow(true));
diff --git a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js
index 496cd6d1f7579..8c49c606a87de 100644
--- a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js
@@ -622,21 +622,25 @@ describe('ReactHooksWithNoopRenderer', () => {
});
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
- // Effects are deferred until after the commit
- expect(Scheduler).toFlushAndYield(['Passive effect [0]']);
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ // Effects are deferred until after the commit
+ expect(Scheduler).toFlushAndYield(['Passive effect [0]']);
+ });
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
- // Effects are deferred until after the commit
- expect(Scheduler).toFlushAndYield(['Passive effect [1]']);
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
+ // Effects are deferred until after the commit
+ expect(Scheduler).toFlushAndYield(['Passive effect [1]']);
+ });
});
it('flushes passive effects even with sibling deletions', () => {
@@ -653,25 +657,24 @@ describe('ReactHooksWithNoopRenderer', () => {
return ;
}
let passive = ;
- ReactNoop.render([, passive]);
- expect(Scheduler).toFlushAndYieldThrough([
- 'Layout',
- 'Passive',
- 'Layout effect',
- ]);
- expect(ReactNoop.getChildren()).toEqual([
- span('Layout'),
- span('Passive'),
- ]);
-
- // Destroying the first child shouldn't prevent the passive effect from
- // being executed
- ReactNoop.render([passive]);
- expect(Scheduler).toFlushAndYield(['Passive effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Passive')]);
-
- // (No effects are left to flush.)
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render([, passive]);
+ expect(Scheduler).toFlushAndYieldThrough([
+ 'Layout',
+ 'Passive',
+ 'Layout effect',
+ ]);
+ expect(ReactNoop.getChildren()).toEqual([
+ span('Layout'),
+ span('Passive'),
+ ]);
+ // Destroying the first child shouldn't prevent the passive effect from
+ // being executed
+ ReactNoop.render([passive]);
+ expect(Scheduler).toFlushAndYield(['Passive effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Passive')]);
+ });
+ // exiting act calls flushPassiveEffects(), but there are none left to flush.
expect(Scheduler).toHaveYielded([]);
});
@@ -728,18 +731,20 @@ describe('ReactHooksWithNoopRenderer', () => {
});
return ;
}
- ReactNoop.render([, ]);
- expect(Scheduler).toFlushAndYield([
- 'Passive',
- 'Layout',
- 'Layout effect',
- 'Passive effect',
- 'New Root',
- ]);
- expect(ReactNoop.getChildren()).toEqual([
- span('Passive'),
- span('Layout'),
- ]);
+ act(() => {
+ ReactNoop.render([, ]);
+ expect(Scheduler).toFlushAndYield([
+ 'Passive',
+ 'Layout',
+ 'Layout effect',
+ 'Passive effect',
+ 'New Root',
+ ]);
+ expect(ReactNoop.getChildren()).toEqual([
+ span('Passive'),
+ span('Layout'),
+ ]);
+ });
});
it(
@@ -762,25 +767,25 @@ describe('ReactHooksWithNoopRenderer', () => {
});
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough([0, 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span(0)]);
-
- // Before the effects have a chance to flush, schedule another update
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough([
- // The previous effect flushes before the reconciliation
- 'Committed state when effect was fired: 0',
- 1,
- 'Sync effect',
- ]);
- expect(ReactNoop.getChildren()).toEqual([span(1)]);
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough([0, 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span(0)]);
+ // Before the effects have a chance to flush, schedule another update
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough([
+ // The previous effect flushes before the reconciliation
+ 'Committed state when effect was fired: 0',
+ 1,
+ 'Sync effect',
+ ]);
+ expect(ReactNoop.getChildren()).toEqual([span(1)]);
+ });
- ReactNoop.flushPassiveEffects();
expect(Scheduler).toHaveYielded([
'Committed state when effect was fired: 1',
]);
@@ -799,26 +804,30 @@ describe('ReactHooksWithNoopRenderer', () => {
);
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough([
- 'Count: (empty)',
- 'Sync effect',
- ]);
- expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);
- ReactNoop.flushPassiveEffects();
- expect(Scheduler).toHaveYielded(['Schedule update [0]']);
- expect(Scheduler).toFlushAndYield(['Count: 0']);
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough([
+ 'Count: (empty)',
+ 'Sync effect',
+ ]);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);
+ ReactNoop.flushPassiveEffects();
+ expect(Scheduler).toHaveYielded(['Schedule update [0]']);
+ expect(Scheduler).toFlushAndYield(['Count: 0']);
+ });
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
- ReactNoop.flushPassiveEffects();
- expect(Scheduler).toHaveYielded(['Schedule update [1]']);
- expect(Scheduler).toFlushAndYield(['Count: 1']);
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ ReactNoop.flushPassiveEffects();
+ expect(Scheduler).toHaveYielded(['Schedule update [1]']);
+ expect(Scheduler).toFlushAndYield(['Count: 1']);
+ });
});
it('updates have async priority even if effects are flushed early', () => {
@@ -833,32 +842,33 @@ describe('ReactHooksWithNoopRenderer', () => {
);
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough([
- 'Count: (empty)',
- 'Sync effect',
- ]);
- expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);
-
- // Rendering again should flush the previous commit's effects
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough([
- 'Schedule update [0]',
- 'Count: 0',
- ]);
- expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough([
+ 'Count: (empty)',
+ 'Sync effect',
+ ]);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);
- expect(Scheduler).toFlushAndYieldThrough(['Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ // Rendering again should flush the previous commit's effects
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough([
+ 'Schedule update [0]',
+ 'Count: 0',
+ ]);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);
- ReactNoop.flushPassiveEffects();
- expect(Scheduler).toHaveYielded(['Schedule update [1]']);
- expect(Scheduler).toFlushAndYield(['Count: 1']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
+ expect(Scheduler).toFlushAndYieldThrough(['Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ ReactNoop.flushPassiveEffects();
+ expect(Scheduler).toHaveYielded(['Schedule update [1]']);
+ expect(Scheduler).toFlushAndYield(['Count: 1']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
+ });
});
it('flushes passive effects when flushing discrete updates', () => {
@@ -873,15 +883,18 @@ describe('ReactHooksWithNoopRenderer', () => {
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ // we explicitly wait for missing act() warnings here since
+ // it's a lot harder to simulate this condition inside an act scope
+ expect(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ }).toWarnDev(['An update to Counter ran an effect']);
// A discrete event forces the passive effect to be flushed --
// updateCount(1) happens first, so 2 wins.
-
ReactNoop.flushDiscreteUpdates();
ReactNoop.discreteUpdates(() => {
// (use batchedUpdates to silence the act() warning)
@@ -890,7 +903,13 @@ describe('ReactHooksWithNoopRenderer', () => {
});
});
expect(Scheduler).toHaveYielded(['Will set count to 1']);
- expect(Scheduler).toFlushAndYield(['Count: 2']);
+ expect(() => {
+ expect(Scheduler).toFlushAndYield(['Count: 2']);
+ }).toWarnDev([
+ 'An update to Counter ran an effect',
+ 'An update to Counter ran an effect',
+ ]);
+
expect(ReactNoop.getChildren()).toEqual([span('Count: 2')]);
});
@@ -921,17 +940,21 @@ describe('ReactHooksWithNoopRenderer', () => {
}
const tracingEvent = {id: 0, name: 'hello', timestamp: 0};
- SchedulerTracing.unstable_trace(
- tracingEvent.name,
- tracingEvent.timestamp,
- () => {
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- },
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ // we explicitly wait for missing act() warnings here since
+ // it's a lot harder to simulate this condition inside an act scope
+ expect(() => {
+ SchedulerTracing.unstable_trace(
+ tracingEvent.name,
+ tracingEvent.timestamp,
+ () => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ },
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ }).toWarnDev(['An update to Counter ran an effect']);
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(0);
@@ -939,11 +962,19 @@ describe('ReactHooksWithNoopRenderer', () => {
// updateCount(1) happens first, so 2 wins.
ReactNoop.flushDiscreteUpdates();
ReactNoop.discreteUpdates(() => {
- // use batchedUpdates to silence the act warning
- ReactNoop.batchedUpdates(() => _updateCount(2));
+ // (use batchedUpdates to silence the act() warning)
+ ReactNoop.batchedUpdates(() => {
+ _updateCount(2);
+ });
});
expect(Scheduler).toHaveYielded(['Will set count to 1']);
- expect(Scheduler).toFlushAndYield(['Count: 2']);
+ expect(() => {
+ expect(Scheduler).toFlushAndYield(['Count: 2']);
+ }).toWarnDev([
+ 'An update to Counter ran an effect',
+ 'An update to Counter ran an effect',
+ ]);
+
expect(ReactNoop.getChildren()).toEqual([span('Count: 2')]);
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
@@ -971,12 +1002,14 @@ describe('ReactHooksWithNoopRenderer', () => {
);
return ;
}
- ReactNoop.renderLegacySyncRoot();
- // Even in sync mode, effects are deferred until after paint
- expect(Scheduler).toHaveYielded(['Count: (empty)']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);
- // Now fire the effects
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.renderLegacySyncRoot();
+ // Even in sync mode, effects are deferred until after paint
+ expect(Scheduler).toFlushAndYieldThrough(['Count: (empty)']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);
+ });
+
+ // effects get fored on exiting act()
// There were multiple updates, but there should only be a
// single render
expect(Scheduler).toHaveYielded(['Count: 0']);
@@ -998,18 +1031,19 @@ describe('ReactHooksWithNoopRenderer', () => {
);
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough([
- 'Count: (empty)',
- 'Sync effect',
- ]);
- expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);
-
- expect(() => {
- ReactNoop.flushPassiveEffects();
- }).toThrow('flushSync was called from inside a lifecycle method');
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough([
+ 'Count: (empty)',
+ 'Sync effect',
+ ]);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: (empty)')]);
+ expect(() => {
+ ReactNoop.flushPassiveEffects();
+ }).toThrow('flushSync was called from inside a lifecycle method');
+ });
});
it('unmounts previous effect', () => {
@@ -1022,20 +1056,24 @@ describe('ReactHooksWithNoopRenderer', () => {
});
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ });
+
expect(Scheduler).toHaveYielded(['Did create [0]']);
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
+ });
+
expect(Scheduler).toHaveYielded(['Did destroy [0]', 'Did create [1]']);
});
@@ -1049,12 +1087,14 @@ describe('ReactHooksWithNoopRenderer', () => {
});
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ });
+
expect(Scheduler).toHaveYielded(['Did create [0]']);
ReactNoop.render(null);
@@ -1072,20 +1112,24 @@ describe('ReactHooksWithNoopRenderer', () => {
}, []);
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ });
+
expect(Scheduler).toHaveYielded(['Did create [0]']);
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
+ });
+
expect(Scheduler).toHaveYielded([]);
ReactNoop.render(null);
@@ -1104,20 +1148,24 @@ describe('ReactHooksWithNoopRenderer', () => {
useEffect(effect);
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ });
+
expect(Scheduler).toHaveYielded(['Did create']);
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
+ });
+
expect(Scheduler).toHaveYielded(['Did destroy', 'Did create']);
ReactNoop.render(null);
@@ -1139,42 +1187,50 @@ describe('ReactHooksWithNoopRenderer', () => {
);
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ });
+
expect(Scheduler).toHaveYielded(['Did create [Count: 0]']);
expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- // Count changed
- expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ // Count changed
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
+ });
+
expect(Scheduler).toHaveYielded([
'Did destroy [Count: 0]',
'Did create [Count: 1]',
]);
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- // Nothing changed, so no effect should have fired
- expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ // Nothing changed, so no effect should have fired
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
+ });
+
expect(Scheduler).toHaveYielded([]);
expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- // Label changed
- expect(Scheduler).toFlushAndYieldThrough(['Total: 1', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Total: 1')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ // Label changed
+ expect(Scheduler).toFlushAndYieldThrough(['Total: 1', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Total: 1')]);
+ });
+
expect(Scheduler).toHaveYielded([
'Did destroy [Count: 1]',
'Did create [Total: 1]',
@@ -1191,20 +1247,23 @@ describe('ReactHooksWithNoopRenderer', () => {
});
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ });
+
expect(Scheduler).toHaveYielded(['Did commit 1 [0]', 'Did commit 2 [0]']);
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
+ });
expect(Scheduler).toHaveYielded(['Did commit 1 [1]', 'Did commit 2 [1]']);
});
@@ -1224,20 +1283,23 @@ describe('ReactHooksWithNoopRenderer', () => {
});
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ });
+
expect(Scheduler).toHaveYielded(['Mount A [0]', 'Mount B [0]']);
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
+ });
expect(Scheduler).toHaveYielded([
'Unmount A [0]',
'Unmount B [0]',
@@ -1265,12 +1327,15 @@ describe('ReactHooksWithNoopRenderer', () => {
});
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
- expect(() => ReactNoop.flushPassiveEffects()).toThrow('Oops');
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ expect(() => ReactNoop.flushPassiveEffects()).toThrow('Oops');
+ });
+
expect(Scheduler).toHaveYielded([
'Mount A [0]',
'Oops!',
@@ -1301,31 +1366,35 @@ describe('ReactHooksWithNoopRenderer', () => {
});
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
- ReactNoop.flushPassiveEffects();
- expect(Scheduler).toHaveYielded(['Mount A [0]', 'Mount B [0]']);
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ ReactNoop.flushPassiveEffects();
+ expect(Scheduler).toHaveYielded(['Mount A [0]', 'Mount B [0]']);
+ });
- // This update will trigger an errror
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
- expect(() => ReactNoop.flushPassiveEffects()).toThrow('Oops');
- expect(Scheduler).toHaveYielded([
- 'Unmount A [0]',
- 'Unmount B [0]',
- 'Mount A [1]',
- 'Oops!',
- // Clean up effect A. There's no effect B to clean-up, because it
- // never mounted.
- 'Unmount A [1]',
- ]);
- expect(ReactNoop.getChildren()).toEqual([]);
+ act(() => {
+ // This update will trigger an errror
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
+ expect(() => ReactNoop.flushPassiveEffects()).toThrow('Oops');
+ expect(Scheduler).toHaveYielded([
+ 'Unmount A [0]',
+ 'Unmount B [0]',
+ 'Mount A [1]',
+ 'Oops!',
+ // Clean up effect A. There's no effect B to clean-up, because it
+ // never mounted.
+ 'Unmount A [1]',
+ ]);
+ expect(ReactNoop.getChildren()).toEqual([]);
+ });
});
it('handles errors on unmount', () => {
@@ -1347,27 +1416,31 @@ describe('ReactHooksWithNoopRenderer', () => {
});
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
- ReactNoop.flushPassiveEffects();
- expect(Scheduler).toHaveYielded(['Mount A [0]', 'Mount B [0]']);
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ ReactNoop.flushPassiveEffects();
+ expect(Scheduler).toHaveYielded(['Mount A [0]', 'Mount B [0]']);
+ });
- // This update will trigger an errror
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
- expect(() => ReactNoop.flushPassiveEffects()).toThrow('Oops');
- expect(Scheduler).toHaveYielded([
- 'Oops!',
- // B unmounts even though an error was thrown in the previous effect
- 'Unmount B [0]',
- ]);
- expect(ReactNoop.getChildren()).toEqual([]);
+ act(() => {
+ // This update will trigger an errror
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 1', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 1')]);
+ expect(() => ReactNoop.flushPassiveEffects()).toThrow('Oops');
+ expect(Scheduler).toHaveYielded([
+ 'Oops!',
+ // B unmounts even though an error was thrown in the previous effect
+ 'Unmount B [0]',
+ ]);
+ expect(ReactNoop.getChildren()).toEqual([]);
+ });
});
it('works with memo', () => {
@@ -1470,27 +1543,27 @@ describe('ReactHooksWithNoopRenderer', () => {
return null;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough([
- 'Mount layout [current: 0]',
- 'Sync effect',
- ]);
- expect(committedText).toEqual('0');
-
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough([
- 'Mount normal [current: 0]',
- 'Unmount layout [current: 0]',
- 'Mount layout [current: 1]',
- 'Sync effect',
- ]);
- expect(committedText).toEqual('1');
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough([
+ 'Mount layout [current: 0]',
+ 'Sync effect',
+ ]);
+ expect(committedText).toEqual('0');
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough([
+ 'Mount normal [current: 0]',
+ 'Unmount layout [current: 0]',
+ 'Mount layout [current: 1]',
+ 'Sync effect',
+ ]);
+ expect(committedText).toEqual('1');
+ });
- ReactNoop.flushPassiveEffects();
expect(Scheduler).toHaveYielded([
'Unmount normal [current: 1]',
'Mount normal [current: 1]',
@@ -1684,8 +1757,10 @@ describe('ReactHooksWithNoopRenderer', () => {
return null;
}
- ReactNoop.render();
- expect(Scheduler).toFlushAndYield([]);
+ act(() => {
+ ReactNoop.render();
+ });
+ expect(Scheduler).toHaveYielded([]);
ping(1);
ping(2);
@@ -1963,28 +2038,32 @@ describe('ReactHooksWithNoopRenderer', () => {
return null;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Sync effect']);
- ReactNoop.flushPassiveEffects();
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Sync effect']);
+ });
+
expect(Scheduler).toHaveYielded(['Mount A']);
- ReactNoop.render();
- expect(() => {
+ act(() => {
+ ReactNoop.render();
expect(() => {
- expect(Scheduler).toFlushAndYield([]);
- }).toThrow('Rendered more hooks than during the previous render');
- }).toWarnDev([
- 'Warning: React has detected a change in the order of Hooks called by App. ' +
- 'This will lead to bugs and errors if not fixed. For more information, ' +
- 'read the Rules of Hooks: https://fb.me/rules-of-hooks\n\n' +
- ' Previous render Next render\n' +
- ' ------------------------------------------------------\n' +
- '1. useEffect useEffect\n' +
- '2. undefined useEffect\n' +
- ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n',
- ]);
+ expect(() => {
+ expect(Scheduler).toFlushAndYield([]);
+ }).toThrow('Rendered more hooks than during the previous render');
+ }).toWarnDev([
+ 'Warning: React has detected a change in the order of Hooks called by App. ' +
+ 'This will lead to bugs and errors if not fixed. For more information, ' +
+ 'read the Rules of Hooks: https://fb.me/rules-of-hooks\n\n' +
+ ' Previous render Next render\n' +
+ ' ------------------------------------------------------\n' +
+ '1. useEffect useEffect\n' +
+ '2. undefined useEffect\n' +
+ ' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n',
+ ]);
+ });
// Uncomment if/when we support this again
// ReactNoop.flushPassiveEffects();
@@ -2026,15 +2105,17 @@ describe('ReactHooksWithNoopRenderer', () => {
return count;
}
- ReactNoop.render();
- expect(Scheduler).toFlushAndYield([
- 'Render: -1',
- 'Effect: 1',
- 'Reducer: 1',
- 'Reducer: 1',
- 'Render: 1',
- ]);
- expect(ReactNoop).toMatchRenderedOutput('1');
+ act(() => {
+ ReactNoop.render();
+ expect(Scheduler).toFlushAndYield([
+ 'Render: -1',
+ 'Effect: 1',
+ 'Reducer: 1',
+ 'Reducer: 1',
+ 'Render: 1',
+ ]);
+ expect(ReactNoop).toMatchRenderedOutput('1');
+ });
act(() => {
setCounter(2);
@@ -2109,19 +2190,19 @@ describe('ReactHooksWithNoopRenderer', () => {
return ;
}
- ReactNoop.render(, () =>
- Scheduler.yieldValue('Sync effect'),
- );
- expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
-
- // Enqueuing this update forces the passive effect to be flushed --
- // updateCount(1) happens first, so 2 wins.
- // (use batchedUpdates to silence the act() warning)
- ReactNoop.batchedUpdates(() => _updateCount(2));
- expect(Scheduler).toHaveYielded(['Will set count to 1']);
- expect(Scheduler).toFlushAndYield(['Count: 2']);
- expect(ReactNoop.getChildren()).toEqual([span('Count: 2')]);
+ act(() => {
+ ReactNoop.render(, () =>
+ Scheduler.yieldValue('Sync effect'),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
+ // Enqueuing this update forces the passive effect to be flushed --
+ // updateCount(1) happens first, so 2 wins.
+ act(() => _updateCount(2));
+ expect(Scheduler).toHaveYielded(['Will set count to 1']);
+ expect(Scheduler).toFlushAndYield(['Count: 2']);
+ expect(ReactNoop.getChildren()).toEqual([span('Count: 2')]);
+ });
});
});
});
diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalScheduling-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalScheduling-test.internal.js
index ddc62c60aa6fa..9064249f96dc4 100644
--- a/packages/react-reconciler/src/__tests__/ReactIncrementalScheduling-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactIncrementalScheduling-test.internal.js
@@ -111,30 +111,30 @@ describe('ReactIncrementalScheduling', () => {
expect(ReactNoop.getChildrenAsJSX('c')).toEqual('c:1');
// Schedule deferred work in the reverse order
- ReactNoop.batchedUpdates(() => {
+ ReactNoop.act(() => {
ReactNoop.renderToRootWithID(, 'c');
ReactNoop.renderToRootWithID(, 'b');
- });
- // Ensure it starts in the order it was scheduled
- expect(Scheduler).toFlushAndYieldThrough(['c:2']);
+ // Ensure it starts in the order it was scheduled
+ expect(Scheduler).toFlushAndYieldThrough(['c:2']);
+
+ expect(ReactNoop.getChildrenAsJSX('a')).toEqual('a:1');
+ expect(ReactNoop.getChildrenAsJSX('b')).toEqual('b:1');
+ expect(ReactNoop.getChildrenAsJSX('c')).toEqual('c:2');
+ // Schedule last bit of work, it will get processed the last
- expect(ReactNoop.getChildrenAsJSX('a')).toEqual('a:1');
- expect(ReactNoop.getChildrenAsJSX('b')).toEqual('b:1');
- expect(ReactNoop.getChildrenAsJSX('c')).toEqual('c:2');
- // Schedule last bit of work, it will get processed the last
- ReactNoop.batchedUpdates(() => {
ReactNoop.renderToRootWithID(, 'a');
- });
- // Keep performing work in the order it was scheduled
- expect(Scheduler).toFlushAndYieldThrough(['b:2']);
- expect(ReactNoop.getChildrenAsJSX('a')).toEqual('a:1');
- expect(ReactNoop.getChildrenAsJSX('b')).toEqual('b:2');
- expect(ReactNoop.getChildrenAsJSX('c')).toEqual('c:2');
- expect(Scheduler).toFlushAndYieldThrough(['a:2']);
- expect(ReactNoop.getChildrenAsJSX('a')).toEqual('a:2');
- expect(ReactNoop.getChildrenAsJSX('b')).toEqual('b:2');
- expect(ReactNoop.getChildrenAsJSX('c')).toEqual('c:2');
+ // Keep performing work in the order it was scheduled
+ expect(Scheduler).toFlushAndYieldThrough(['b:2']);
+ expect(ReactNoop.getChildrenAsJSX('a')).toEqual('a:1');
+ expect(ReactNoop.getChildrenAsJSX('b')).toEqual('b:2');
+ expect(ReactNoop.getChildrenAsJSX('c')).toEqual('c:2');
+
+ expect(Scheduler).toFlushAndYieldThrough(['a:2']);
+ expect(ReactNoop.getChildrenAsJSX('a')).toEqual('a:2');
+ expect(ReactNoop.getChildrenAsJSX('b')).toEqual('b:2');
+ expect(ReactNoop.getChildrenAsJSX('c')).toEqual('c:2');
+ });
});
it('schedules sync updates when inside componentDidMount/Update', () => {
diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.internal.js
index 26af1eb0014aa..8e46223f7fc3e 100644
--- a/packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.internal.js
@@ -476,70 +476,74 @@ describe('ReactIncrementalUpdates', () => {
// First, as a sanity check, assert what happens when four low pri
// updates in separate batches are all flushed in the same callback
- ReactNoop.render();
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- ReactNoop.render();
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- ReactNoop.render();
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- ReactNoop.render();
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- // Each update flushes in a separate commit.
- // Note: This isn't necessarily the ideal behavior. It might be better to
- // batch all of these updates together. The fact that they don't is an
- // implementation detail. The important part of this unit test is what
- // happens when they expire, in which case they really should be batched to
- // avoid blocking the main thread for a long time.
- expect(Scheduler).toFlushAndYield([
- 'Render: ',
- 'Commit: ',
- 'Render: he',
- 'Commit: he',
- 'Render: hell',
- 'Commit: hell',
- 'Render: hello',
- 'Commit: hello',
- ]);
+ ReactNoop.act(() => {
+ ReactNoop.render();
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ ReactNoop.render();
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ ReactNoop.render();
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ ReactNoop.render();
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ // Each update flushes in a separate commit.
+ // Note: This isn't necessarily the ideal behavior. It might be better to
+ // batch all of these updates together. The fact that they don't is an
+ // implementation detail. The important part of this unit test is what
+ // happens when they expire, in which case they really should be batched to
+ // avoid blocking the main thread for a long time.
+ expect(Scheduler).toFlushAndYield([
+ 'Render: ',
+ 'Commit: ',
+ 'Render: he',
+ 'Commit: he',
+ 'Render: hell',
+ 'Commit: hell',
+ 'Render: hello',
+ 'Commit: hello',
+ ]);
+ });
- // Now do the same thing over again, but this time, expire all the updates
- // instead of flushing them normally.
- ReactNoop.render();
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- ReactNoop.render();
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- ReactNoop.render();
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- ReactNoop.render();
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- // All the updates should render and commit in a single batch.
- Scheduler.advanceTime(10000);
- expect(Scheduler).toHaveYielded(['Render: goodbye']);
- // Passive effect
- expect(Scheduler).toFlushAndYield(['Commit: goodbye']);
+ ReactNoop.act(() => {
+ // Now do the same thing over again, but this time, expire all the updates
+ // instead of flushing them normally.
+ ReactNoop.render();
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ ReactNoop.render();
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ ReactNoop.render();
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ ReactNoop.render();
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ // All the updates should render and commit in a single batch.
+ Scheduler.advanceTime(10000);
+ expect(Scheduler).toHaveYielded(['Render: goodbye']);
+ // Passive effect
+ expect(Scheduler).toFlushAndYield(['Commit: goodbye']);
+ });
});
it('flushes all expired updates in a single batch across multiple roots', () => {
@@ -559,92 +563,95 @@ describe('ReactIncrementalUpdates', () => {
ReactNoop.renderToRootWithID(null, 'other-root');
});
}
+ ReactNoop.act(() => {
+ // First, as a sanity check, assert what happens when four low pri
+ // updates in separate batches are all flushed in the same callback
+ ReactNoop.renderToRootWithID(, 'a');
+ ReactNoop.renderToRootWithID(, 'b');
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ ReactNoop.renderToRootWithID(, 'a');
+ ReactNoop.renderToRootWithID(, 'b');
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ ReactNoop.renderToRootWithID(, 'a');
+ ReactNoop.renderToRootWithID(, 'b');
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ ReactNoop.renderToRootWithID(, 'a');
+ ReactNoop.renderToRootWithID(, 'b');
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ // Each update flushes in a separate commit.
+ // Note: This isn't necessarily the ideal behavior. It might be better to
+ // batch all of these updates together. The fact that they don't is an
+ // implementation detail. The important part of this unit test is what
+ // happens when they expire, in which case they really should be batched to
+ // avoid blocking the main thread for a long time.
+ expect(Scheduler).toFlushAndYield([
+ 'Render: ',
+ 'Commit: ',
+ 'Render: ',
+ 'Commit: ',
+ 'Render: he',
+ 'Commit: he',
+ 'Render: he',
+ 'Commit: he',
+ 'Render: hell',
+ 'Commit: hell',
+ 'Render: hell',
+ 'Commit: hell',
+ 'Render: hello',
+ 'Commit: hello',
+ 'Render: hello',
+ 'Commit: hello',
+ ]);
+ });
- // First, as a sanity check, assert what happens when four low pri
- // updates in separate batches are all flushed in the same callback
- ReactNoop.renderToRootWithID(, 'a');
- ReactNoop.renderToRootWithID(, 'b');
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- ReactNoop.renderToRootWithID(, 'a');
- ReactNoop.renderToRootWithID(, 'b');
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- ReactNoop.renderToRootWithID(, 'a');
- ReactNoop.renderToRootWithID(, 'b');
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- ReactNoop.renderToRootWithID(, 'a');
- ReactNoop.renderToRootWithID(, 'b');
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- // Each update flushes in a separate commit.
- // Note: This isn't necessarily the ideal behavior. It might be better to
- // batch all of these updates together. The fact that they don't is an
- // implementation detail. The important part of this unit test is what
- // happens when they expire, in which case they really should be batched to
- // avoid blocking the main thread for a long time.
- expect(Scheduler).toFlushAndYield([
- 'Render: ',
- 'Commit: ',
- 'Render: ',
- 'Commit: ',
- 'Render: he',
- 'Commit: he',
- 'Render: he',
- 'Commit: he',
- 'Render: hell',
- 'Commit: hell',
- 'Render: hell',
- 'Commit: hell',
- 'Render: hello',
- 'Commit: hello',
- 'Render: hello',
- 'Commit: hello',
- ]);
-
- // Now do the same thing over again, but this time, expire all the updates
- // instead of flushing them normally.
- ReactNoop.renderToRootWithID(, 'a');
- ReactNoop.renderToRootWithID(, 'b');
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- ReactNoop.renderToRootWithID(, 'a');
- ReactNoop.renderToRootWithID(, 'b');
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- ReactNoop.renderToRootWithID(, 'a');
- ReactNoop.renderToRootWithID(, 'b');
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- ReactNoop.renderToRootWithID(, 'a');
- ReactNoop.renderToRootWithID(, 'b');
- Scheduler.advanceTime(1000);
- expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
- interrupt();
-
- // All the updates should render and commit in a single batch.
- Scheduler.advanceTime(10000);
- expect(Scheduler).toHaveYielded([
- 'Render: goodbye',
- 'Commit: goodbye',
- 'Render: goodbye',
- ]);
- // Passive effect
- expect(Scheduler).toFlushAndYield(['Commit: goodbye']);
+ ReactNoop.act(() => {
+ // Now do the same thing over again, but this time, expire all the updates
+ // instead of flushing them normally.
+ ReactNoop.renderToRootWithID(, 'a');
+ ReactNoop.renderToRootWithID(, 'b');
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ ReactNoop.renderToRootWithID(, 'a');
+ ReactNoop.renderToRootWithID(, 'b');
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ ReactNoop.renderToRootWithID(, 'a');
+ ReactNoop.renderToRootWithID(, 'b');
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ ReactNoop.renderToRootWithID(, 'a');
+ ReactNoop.renderToRootWithID(, 'b');
+ Scheduler.advanceTime(1000);
+ expect(Scheduler).toFlushAndYieldThrough(['Render: ']);
+ interrupt();
+
+ // All the updates should render and commit in a single batch.
+ Scheduler.advanceTime(10000);
+ expect(Scheduler).toHaveYielded([
+ 'Render: goodbye',
+ 'Commit: goodbye',
+ 'Render: goodbye',
+ ]);
+ // Passive effect
+ expect(Scheduler).toFlushAndYield(['Commit: goodbye']);
+ });
});
});
diff --git a/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.internal.js
index dec4bfbfc57b1..7f123fbb66238 100644
--- a/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.internal.js
+++ b/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.internal.js
@@ -133,21 +133,22 @@ describe('ReactSchedulerIntegration', () => {
});
return null;
}
+ ReactNoop.act(() => {
+ ReactNoop.render();
+ expect(Scheduler).toFlushAndYield([
+ 'Render priority: Normal',
+ 'Passive priority: Normal',
+ ]);
- ReactNoop.render();
- expect(Scheduler).toFlushAndYield([
- 'Render priority: Normal',
- 'Passive priority: Normal',
- ]);
+ runWithPriority(UserBlockingPriority, () => {
+ ReactNoop.render();
+ });
- runWithPriority(UserBlockingPriority, () => {
- ReactNoop.render();
+ expect(Scheduler).toFlushAndYield([
+ 'Render priority: UserBlocking',
+ 'Passive priority: UserBlocking',
+ ]);
});
-
- expect(Scheduler).toFlushAndYield([
- 'Render priority: UserBlocking',
- 'Passive priority: UserBlocking',
- ]);
});
it('after completing a level of work, infers priority of the next batch based on its expiration time', () => {
diff --git a/packages/react-refresh/src/__tests__/ReactFresh-test.js b/packages/react-refresh/src/__tests__/ReactFresh-test.js
index f56a3bd5bf03e..790a418013b6b 100644
--- a/packages/react-refresh/src/__tests__/ReactFresh-test.js
+++ b/packages/react-refresh/src/__tests__/ReactFresh-test.js
@@ -2676,14 +2676,16 @@ describe('ReactFresh', () => {
expect(container.firstChild.nextSibling.nextSibling).toBe(secondP);
// Perform a hot update that fixes the error.
- patch(() => {
- function Hello() {
- const [x] = React.useState('');
- React.useEffect(() => {}, []); // Removes the bad effect code.
- x.slice(); // Doesn't throw initially.
- return Fixed!
;
- }
- $RefreshReg$(Hello, 'Hello');
+ act(() => {
+ patch(() => {
+ function Hello() {
+ const [x] = React.useState('');
+ React.useEffect(() => {}, []); // Removes the bad effect code.
+ x.slice(); // Doesn't throw initially.
+ return Fixed!
;
+ }
+ $RefreshReg$(Hello, 'Hello');
+ });
});
// This should remount the error boundary (but not anything above it).
@@ -2693,15 +2695,18 @@ describe('ReactFresh', () => {
// Verify next hot reload doesn't remount anything.
const helloNode = container.firstChild.nextSibling;
- patch(() => {
- function Hello() {
- const [x] = React.useState('');
- React.useEffect(() => {}, []);
- x.slice();
- return Nice.
;
- }
- $RefreshReg$(Hello, 'Hello');
+ act(() => {
+ patch(() => {
+ function Hello() {
+ const [x] = React.useState('');
+ React.useEffect(() => {}, []);
+ x.slice();
+ return Nice.
;
+ }
+ $RefreshReg$(Hello, 'Hello');
+ });
});
+
expect(container.firstChild.nextSibling).toBe(helloNode);
expect(helloNode.textContent).toBe('Nice.');
}
diff --git a/packages/react/src/__tests__/ReactDOMTracing-test.internal.js b/packages/react/src/__tests__/ReactDOMTracing-test.internal.js
index 10442f72aeff3..3e90fb3c50342 100644
--- a/packages/react/src/__tests__/ReactDOMTracing-test.internal.js
+++ b/packages/react/src/__tests__/ReactDOMTracing-test.internal.js
@@ -104,34 +104,32 @@ describe('ReactDOMTracing', () => {
const root = ReactDOM.unstable_createRoot(container);
SchedulerTracing.unstable_trace('initialization', 0, () => {
interaction = Array.from(SchedulerTracing.unstable_getCurrent())[0];
+ TestUtils.act(() => {
+ root.render(
+
+
+ ,
+ );
+ expect(onInteractionTraced).toHaveBeenCalledTimes(1);
+ expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
+ interaction,
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['App', 'App:mount']);
+ expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
+ expect(onRender).toHaveBeenCalledTimes(1);
+ expect(onRender).toHaveLastRenderedWithInteractions(
+ new Set([interaction]),
+ );
+ expect(Scheduler).toFlushAndYieldThrough(['Child', 'Child:mount']);
+ expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
+ expect(onRender).toHaveBeenCalledTimes(2);
+ expect(onRender).toHaveLastRenderedWithInteractions(
+ new Set([interaction]),
+ );
- root.render(
-
-
- ,
- );
+ expect(Scheduler).toFlushAndYield(['Child', 'Child:update']);
+ });
});
-
- expect(onInteractionTraced).toHaveBeenCalledTimes(1);
- expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
- interaction,
- );
-
- expect(Scheduler).toFlushAndYieldThrough(['App', 'App:mount']);
- expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
- expect(onRender).toHaveBeenCalledTimes(1);
- expect(onRender).toHaveLastRenderedWithInteractions(
- new Set([interaction]),
- );
-
- expect(Scheduler).toFlushAndYieldThrough(['Child', 'Child:mount']);
- expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
- expect(onRender).toHaveBeenCalledTimes(2);
- expect(onRender).toHaveLastRenderedWithInteractions(
- new Set([interaction]),
- );
-
- expect(Scheduler).toFlushAndYield(['Child', 'Child:update']);
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
expect(
onInteractionScheduledWorkCompleted,
@@ -172,33 +170,34 @@ describe('ReactDOMTracing', () => {
SchedulerTracing.unstable_trace('initialization', 0, () => {
interaction = Array.from(SchedulerTracing.unstable_getCurrent())[0];
- root.render(
-
-
- ,
- );
- });
-
- expect(onInteractionTraced).toHaveBeenCalledTimes(1);
- expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
- interaction,
- );
+ TestUtils.act(() => {
+ root.render(
+
+
+ ,
+ );
+ expect(onInteractionTraced).toHaveBeenCalledTimes(1);
+ expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
+ interaction,
+ );
- expect(Scheduler).toFlushAndYieldThrough(['App', 'App:mount']);
- expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
- expect(onRender).toHaveBeenCalledTimes(1);
- expect(onRender).toHaveLastRenderedWithInteractions(
- new Set([interaction]),
- );
+ expect(Scheduler).toFlushAndYieldThrough(['App', 'App:mount']);
+ expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
+ expect(onRender).toHaveBeenCalledTimes(1);
+ expect(onRender).toHaveLastRenderedWithInteractions(
+ new Set([interaction]),
+ );
- expect(wrapped).not.toBeNull();
+ expect(wrapped).not.toBeNull();
- expect(Scheduler).toFlushAndYield(['Child']);
- expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
- expect(onRender).toHaveBeenCalledTimes(2);
- expect(onRender).toHaveLastRenderedWithInteractions(
- new Set([interaction]),
- );
+ expect(Scheduler).toFlushAndYield(['Child']);
+ expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
+ expect(onRender).toHaveBeenCalledTimes(2);
+ expect(onRender).toHaveLastRenderedWithInteractions(
+ new Set([interaction]),
+ );
+ });
+ });
wrapped();
expect(onInteractionTraced).toHaveBeenCalledTimes(1);
@@ -249,34 +248,35 @@ describe('ReactDOMTracing', () => {
const root = ReactDOM.unstable_createRoot(container);
SchedulerTracing.unstable_trace('initialization', 0, () => {
interaction = Array.from(SchedulerTracing.unstable_getCurrent())[0];
+ TestUtils.act(() => {
+ root.render(
+
+
+ ,
+ );
+ expect(onInteractionTraced).toHaveBeenCalledTimes(1);
+ expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
+ interaction,
+ );
- root.render(
-
-
- ,
- );
- });
-
- expect(onInteractionTraced).toHaveBeenCalledTimes(1);
- expect(onInteractionTraced).toHaveBeenLastNotifiedOfInteraction(
- interaction,
- );
+ expect(Scheduler).toFlushAndYieldThrough(['App', 'App:mount']);
+ expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
+ expect(onRender).toHaveBeenCalledTimes(1);
+ expect(onRender).toHaveLastRenderedWithInteractions(
+ new Set([interaction]),
+ );
- expect(Scheduler).toFlushAndYieldThrough(['App', 'App:mount']);
- expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
- expect(onRender).toHaveBeenCalledTimes(1);
- expect(onRender).toHaveLastRenderedWithInteractions(
- new Set([interaction]),
- );
+ expect(Scheduler).toFlushAndYieldThrough(['Child', 'Child:mount']);
+ expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
+ expect(onRender).toHaveBeenCalledTimes(2);
+ expect(onRender).toHaveLastRenderedWithInteractions(
+ new Set([interaction]),
+ );
- expect(Scheduler).toFlushAndYieldThrough(['Child', 'Child:mount']);
- expect(onInteractionScheduledWorkCompleted).not.toHaveBeenCalled();
- expect(onRender).toHaveBeenCalledTimes(2);
- expect(onRender).toHaveLastRenderedWithInteractions(
- new Set([interaction]),
- );
+ expect(Scheduler).toFlushAndYield(['Child', 'Child:update']);
+ });
+ });
- expect(Scheduler).toFlushAndYield(['Child', 'Child:update']);
expect(onInteractionScheduledWorkCompleted).toHaveBeenCalledTimes(1);
expect(
onInteractionScheduledWorkCompleted,
diff --git a/packages/react/src/__tests__/withComponentStack-test.js b/packages/react/src/__tests__/withComponentStack-test.js
index e46d7f2e54997..3f9a709816e85 100644
--- a/packages/react/src/__tests__/withComponentStack-test.js
+++ b/packages/react/src/__tests__/withComponentStack-test.js
@@ -44,16 +44,13 @@ describe('withComponentStack', () => {
let React = null;
let ReactTestRenderer = null;
let error = null;
- let scheduler = null;
let warn = null;
beforeEach(() => {
jest.resetModules();
- jest.mock('scheduler', () => require('scheduler/unstable_mock'));
React = require('react');
ReactTestRenderer = require('react-test-renderer');
- scheduler = require('scheduler');
error = React.error;
warn = React.warn;
@@ -178,10 +175,9 @@ describe('withComponentStack', () => {
});
return null;
}
-
- ReactTestRenderer.create();
-
- scheduler.flushAll(); // Flush passive effects
+ ReactTestRenderer.act(() => {
+ ReactTestRenderer.create();
+ });
expectMessageAndStack(
'logged in child render method',