Skip to content

Commit e1c5e87

Browse files
author
Sunil Pai
authored
warn if passive effects get queued outside of an act() call. (#15763)
* warn if passive effects get queued outside of an act() call While the code itself isn't much (it adds the warning to mountEffect() and updateEffect() in ReactFiberHooks), it does change a lot of our tests. We follow a bad-ish pattern here, which is doing asserts inside act() scopes, but it makes sense for *us* because we're testing intermediate states, and we're manually flush/yield what we need in these tests. This commit has one last failing test. Working on it. * pass lint * pass failing test, fixes another - a test was failing in ReactDOMServerIntegrationHooks while testing an effect; the behaviour of yields was different from browser and server when wrapped with act(). further, because of how we initialized modules, act() around renders wasn't working corrrectly. solved by passing in ReactTestUtils in initModules, and checking on the finally yielded values in the specific test. - in ReactUpdates, while testing an infinite recursion detection, the test needed to be wrapped in an act(), which would have caused the recusrsion error to throw. solived by rethrowing the error from inside the act(). * pass ReactDOMServerSuspense * stray todo * a better message, consistent with the state update one.
1 parent 39b97e8 commit e1c5e87

File tree

35 files changed

+1005
-732
lines changed

35 files changed

+1005
-732
lines changed

packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,10 @@ describe('ReactHooksInspectionIntegration', () => {
146146
</div>
147147
);
148148
}
149-
let renderer = ReactTestRenderer.create(<Foo prop="prop" />);
149+
let renderer;
150+
act(() => {
151+
renderer = ReactTestRenderer.create(<Foo prop="prop" />);
152+
});
150153

151154
let childFiber = renderer.root.findByType(Foo)._currentFiber();
152155

packages/react-dom/src/__tests__/ReactDOMHooks-test.js

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,32 @@ describe('ReactDOMHooks', () => {
5353
return 3 * n;
5454
}
5555

56-
ReactDOM.render(<Example1 n={1} />, container);
57-
expect(container.textContent).toBe('1');
58-
expect(container2.textContent).toBe('');
59-
expect(container3.textContent).toBe('');
60-
Scheduler.flushAll();
61-
expect(container.textContent).toBe('1');
62-
expect(container2.textContent).toBe('2');
63-
expect(container3.textContent).toBe('3');
64-
65-
ReactDOM.render(<Example1 n={2} />, container);
66-
expect(container.textContent).toBe('2');
67-
expect(container2.textContent).toBe('2'); // Not flushed yet
68-
expect(container3.textContent).toBe('3'); // Not flushed yet
69-
Scheduler.flushAll();
70-
expect(container.textContent).toBe('2');
71-
expect(container2.textContent).toBe('4');
72-
expect(container3.textContent).toBe('6');
56+
// we explicitly catch the missing act() warnings
57+
// to simulate this tricky repro
58+
expect(() => {
59+
ReactDOM.render(<Example1 n={1} />, container);
60+
expect(container.textContent).toBe('1');
61+
expect(container2.textContent).toBe('');
62+
expect(container3.textContent).toBe('');
63+
Scheduler.flushAll();
64+
expect(container.textContent).toBe('1');
65+
expect(container2.textContent).toBe('2');
66+
expect(container3.textContent).toBe('3');
67+
68+
ReactDOM.render(<Example1 n={2} />, container);
69+
expect(container.textContent).toBe('2');
70+
expect(container2.textContent).toBe('2'); // Not flushed yet
71+
expect(container3.textContent).toBe('3'); // Not flushed yet
72+
Scheduler.flushAll();
73+
expect(container.textContent).toBe('2');
74+
expect(container2.textContent).toBe('4');
75+
expect(container3.textContent).toBe('6');
76+
}).toWarnDev([
77+
'An update to Example1 ran an effect',
78+
'An update to Example2 ran an effect',
79+
'An update to Example1 ran an effect',
80+
'An update to Example2 ran an effect',
81+
]);
7382
});
7483

7584
it('should not bail out when an update is scheduled from within an event handler', () => {

packages/react-dom/src/__tests__/ReactDOMServerIntegrationAttributes-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
1313

1414
let React;
1515
let ReactDOM;
16+
let ReactTestUtils;
1617
let ReactDOMServer;
1718

1819
function initModules() {
@@ -21,11 +22,13 @@ function initModules() {
2122
React = require('react');
2223
ReactDOM = require('react-dom');
2324
ReactDOMServer = require('react-dom/server');
25+
ReactTestUtils = require('react-dom/test-utils');
2426

2527
// Make them available to the helpers.
2628
return {
2729
ReactDOM,
2830
ReactDOMServer,
31+
ReactTestUtils,
2932
};
3033
}
3134

packages/react-dom/src/__tests__/ReactDOMServerIntegrationBasic-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,21 @@ const TEXT_NODE_TYPE = 3;
1616
let React;
1717
let ReactDOM;
1818
let ReactDOMServer;
19+
let ReactTestUtils;
1920

2021
function initModules() {
2122
// Reset warning cache.
2223
jest.resetModuleRegistry();
2324
React = require('react');
2425
ReactDOM = require('react-dom');
2526
ReactDOMServer = require('react-dom/server');
27+
ReactTestUtils = require('react-dom/test-utils');
2628

2729
// Make them available to the helpers.
2830
return {
2931
ReactDOM,
3032
ReactDOMServer,
33+
ReactTestUtils,
3134
};
3235
}
3336

packages/react-dom/src/__tests__/ReactDOMServerIntegrationCheckbox-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,21 @@ const {disableInputAttributeSyncing} = require('shared/ReactFeatureFlags');
1616
let React;
1717
let ReactDOM;
1818
let ReactDOMServer;
19+
let ReactTestUtils;
1920

2021
function initModules() {
2122
// Reset warning cache.
2223
jest.resetModuleRegistry();
2324
React = require('react');
2425
ReactDOM = require('react-dom');
2526
ReactDOMServer = require('react-dom/server');
27+
ReactTestUtils = require('react-dom/test-utils');
2628

2729
// Make them available to the helpers.
2830
return {
2931
ReactDOM,
3032
ReactDOMServer,
33+
ReactTestUtils,
3134
};
3235
}
3336

packages/react-dom/src/__tests__/ReactDOMServerIntegrationClassContextType-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,21 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
1414
let React;
1515
let ReactDOM;
1616
let ReactDOMServer;
17+
let ReactTestUtils;
1718

1819
function initModules() {
1920
// Reset warning cache.
2021
jest.resetModuleRegistry();
2122
React = require('react');
2223
ReactDOM = require('react-dom');
2324
ReactDOMServer = require('react-dom/server');
25+
ReactTestUtils = require('react-dom/test-utils');
2426

2527
// Make them available to the helpers.
2628
return {
2729
ReactDOM,
2830
ReactDOMServer,
31+
ReactTestUtils,
2932
};
3033
}
3134

packages/react-dom/src/__tests__/ReactDOMServerIntegrationElements-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,20 @@ const TEXT_NODE_TYPE = 3;
1616
let React;
1717
let ReactDOM;
1818
let ReactDOMServer;
19+
let ReactTestUtils;
1920

2021
function initModules() {
2122
jest.resetModuleRegistry();
2223
React = require('react');
2324
ReactDOM = require('react-dom');
2425
ReactDOMServer = require('react-dom/server');
26+
ReactTestUtils = require('react-dom/test-utils');
2527

2628
// Make them available to the helpers.
2729
return {
2830
ReactDOM,
2931
ReactDOMServer,
32+
ReactTestUtils,
3033
};
3134
}
3235

packages/react-dom/src/__tests__/ReactDOMServerIntegrationFragment-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,21 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
1414
let React;
1515
let ReactDOM;
1616
let ReactDOMServer;
17+
let ReactTestUtils;
1718

1819
function initModules() {
1920
// Reset warning cache.
2021
jest.resetModuleRegistry();
2122
React = require('react');
2223
ReactDOM = require('react-dom');
2324
ReactDOMServer = require('react-dom/server');
25+
ReactTestUtils = require('react-dom/test-utils');
2426

2527
// Make them available to the helpers.
2628
return {
2729
ReactDOM,
2830
ReactDOMServer,
31+
ReactTestUtils,
2932
};
3033
}
3134

packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ let React;
1717
let ReactFeatureFlags;
1818
let ReactDOM;
1919
let ReactDOMServer;
20+
let ReactTestUtils;
2021
let useState;
2122
let useReducer;
2223
let useEffect;
@@ -41,6 +42,7 @@ function initModules() {
4142
React = require('react');
4243
ReactDOM = require('react-dom');
4344
ReactDOMServer = require('react-dom/server');
45+
ReactTestUtils = require('react-dom/test-utils');
4446
useState = React.useState;
4547
useReducer = React.useReducer;
4648
useEffect = React.useEffect;
@@ -67,6 +69,7 @@ function initModules() {
6769
return {
6870
ReactDOM,
6971
ReactDOMServer,
72+
ReactTestUtils,
7073
};
7174
}
7275

@@ -539,18 +542,30 @@ describe('ReactDOMServerHooks', () => {
539542
});
540543

541544
describe('useEffect', () => {
545+
const yields = [];
542546
itRenders('should ignore effects on the server', async render => {
543547
function Counter(props) {
544548
useEffect(() => {
545-
yieldValue('should not be invoked');
549+
yieldValue('invoked on client');
546550
});
547551
return <Text text={'Count: ' + props.count} />;
548552
}
553+
549554
const domNode = await render(<Counter count={0} />);
550-
expect(clearYields()).toEqual(['Count: 0']);
555+
yields.push(clearYields());
551556
expect(domNode.tagName).toEqual('SPAN');
552557
expect(domNode.textContent).toEqual('Count: 0');
553558
});
559+
560+
it('verifies yields in order', () => {
561+
expect(yields).toEqual([
562+
['Count: 0'], // server render
563+
['Count: 0'], // server stream
564+
['Count: 0', 'invoked on client'], // clean render
565+
['Count: 0', 'invoked on client'], // hydrated render
566+
// nothing yielded for bad markup
567+
]);
568+
});
554569
});
555570

556571
describe('useCallback', () => {

packages/react-dom/src/__tests__/ReactDOMServerIntegrationInput-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,21 @@ const {disableInputAttributeSyncing} = require('shared/ReactFeatureFlags');
1616
let React;
1717
let ReactDOM;
1818
let ReactDOMServer;
19+
let ReactTestUtils;
1920

2021
function initModules() {
2122
// Reset warning cache.
2223
jest.resetModuleRegistry();
2324
React = require('react');
2425
ReactDOM = require('react-dom');
2526
ReactDOMServer = require('react-dom/server');
27+
ReactTestUtils = require('react-dom/test-utils');
2628

2729
// Make them available to the helpers.
2830
return {
2931
ReactDOM,
3032
ReactDOMServer,
33+
ReactTestUtils,
3134
};
3235
}
3336

packages/react-dom/src/__tests__/ReactDOMServerIntegrationLegacyContext-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ let PropTypes;
1515
let React;
1616
let ReactDOM;
1717
let ReactDOMServer;
18+
let ReactTestUtils;
1819

1920
function initModules() {
2021
// Reset warning cache.
@@ -23,11 +24,13 @@ function initModules() {
2324
React = require('react');
2425
ReactDOM = require('react-dom');
2526
ReactDOMServer = require('react-dom/server');
27+
ReactTestUtils = require('react-dom/test-utils');
2628

2729
// Make them available to the helpers.
2830
return {
2931
ReactDOM,
3032
ReactDOMServer,
33+
ReactTestUtils,
3134
};
3235
}
3336

packages/react-dom/src/__tests__/ReactDOMServerIntegrationModes-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,21 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
1414
let React;
1515
let ReactDOM;
1616
let ReactDOMServer;
17+
let ReactTestUtils;
1718

1819
function initModules() {
1920
// Reset warning cache.
2021
jest.resetModuleRegistry();
2122
React = require('react');
2223
ReactDOM = require('react-dom');
2324
ReactDOMServer = require('react-dom/server');
25+
ReactTestUtils = require('react-dom/test-utils');
2426

2527
// Make them available to the helpers.
2628
return {
2729
ReactDOM,
2830
ReactDOMServer,
31+
ReactTestUtils,
2932
};
3033
}
3134

packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,21 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
1414
let React;
1515
let ReactDOM;
1616
let ReactDOMServer;
17+
let ReactTestUtils;
1718

1819
function initModules() {
1920
// Reset warning cache.
2021
jest.resetModuleRegistry();
2122
React = require('react');
2223
ReactDOM = require('react-dom');
2324
ReactDOMServer = require('react-dom/server');
25+
ReactTestUtils = require('react-dom/test-utils');
2426

2527
// Make them available to the helpers.
2628
return {
2729
ReactDOM,
2830
ReactDOMServer,
31+
ReactTestUtils,
2932
};
3033
}
3134

packages/react-dom/src/__tests__/ReactDOMServerIntegrationReconnecting-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
1414
let React;
1515
let ReactDOM;
1616
let ReactDOMServer;
17+
let ReactTestUtils;
1718

1819
function initModules() {
1920
// Reset warning cache.
@@ -22,11 +23,13 @@ function initModules() {
2223
React = require('react');
2324
ReactDOM = require('react-dom');
2425
ReactDOMServer = require('react-dom/server');
26+
ReactTestUtils = require('react-dom/test-utils');
2527

2628
// Make them available to the helpers.
2729
return {
2830
ReactDOM,
2931
ReactDOMServer,
32+
ReactTestUtils,
3033
};
3134
}
3235

packages/react-dom/src/__tests__/ReactDOMServerIntegrationRefs-test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,21 @@ const ReactDOMServerIntegrationUtils = require('./utils/ReactDOMServerIntegratio
1414
let React;
1515
let ReactDOM;
1616
let ReactDOMServer;
17+
let ReactTestUtils;
1718

1819
function initModules() {
1920
// Reset warning cache.
2021
jest.resetModuleRegistry();
2122
React = require('react');
2223
ReactDOM = require('react-dom');
2324
ReactDOMServer = require('react-dom/server');
25+
ReactTestUtils = require('react-dom/test-utils');
2426

2527
// Make them available to the helpers.
2628
return {
2729
ReactDOM,
2830
ReactDOMServer,
31+
ReactTestUtils,
2932
};
3033
}
3134

0 commit comments

Comments
 (0)