[tests] Fix assertions not flushed before act (#28745)
Fixes some easy cases blocking https://github.com/facebook/react/pull/28737, I'll follow up with more complex/interesting cases in other PRs.
Ricky committed
Apr 10, 2024 at 10:33 UTC
42eff4bc78a3636953c55096ca0b220c611a74cc
9 files changed
+29
-23
packages/react-dom/src/__tests__/ReactCompositeComponent-test.js
+2
-4
@@ -913,15 +913,13 @@ describe('ReactCompositeComponent', () => {
913
await act(() => {
914
root.render(<Wrapper name="A" />);
915
});
916
+
917
+ assertLog(['A componentWillMount', 'A render', 'A componentDidMount']);
918
await act(() => {
919
root.render(<Wrapper name="B" />);
920
});
921
922
assertLog([
921
- 'A componentWillMount',
922
- 'A render',
923
- 'A componentDidMount',
924
-
923
'B componentWillMount',
924
'B render',
925
'A componentWillUnmount',
packages/react-dom/src/__tests__/ReactDOMFizzDeferredValue-test.js
+2
@@ -111,9 +111,11 @@ describe('ReactDOMFizzForm', () => {
111
await readIntoContainer(stream);
112
expect(container.textContent).toEqual('Loading...');
113
114
+ assertLog(['Loading...']);
115
// After hydration, it's updated to the final value
116
await act(() => ReactDOMClient.hydrateRoot(container, <App />));
117
expect(container.textContent).toEqual('Final');
118
+ assertLog(['Loading...', 'Final']);
119
},
120
);
121
packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js
+2
-1
@@ -297,6 +297,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
297
});
298
expect(container.textContent).toEqual('not hovered');
299
300
+ assertLog(['not hovered']);
301
await act(async () => {
302
// Note: React does not use native mouseenter/mouseleave events
303
// but we should still correctly determine their priority.
@@ -308,7 +309,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => {
309
dispatchAndSetCurrentEvent(target.current, mouseEnterEvent);
310
311
// Since mouse end is not discrete, should not have updated yet
311
- assertLog(['not hovered']);
312
+ assertLog([]);
313
expect(container.textContent).toEqual('not hovered');
314
315
await waitFor(['hovered']);
packages/react-dom/src/__tests__/ReactDOMRoot-test.js
+2
-1
@@ -342,12 +342,13 @@ describe('ReactDOMRoot', () => {
342
root.render(<Foo value="a" />);
343
});
344
345
+ assertLog(['a']);
346
expect(container.textContent).toEqual('a');
347
348
await act(async () => {
349
root.render(<Foo value="b" />);
350
350
- assertLog(['a']);
351
+ assertLog([]);
352
expect(container.textContent).toEqual('a');
353
354
await waitFor(['b']);
packages/react-dom/src/__tests__/ReactDOMSuspensePlaceholder-test.js
+4
-2
@@ -17,6 +17,7 @@ let Suspense;
17
let Scheduler;
18
let act;
19
let textCache;
20
+let assertLog;
21
22
describe('ReactDOMSuspensePlaceholder', () => {
23
let container;
@@ -31,6 +32,7 @@ describe('ReactDOMSuspensePlaceholder', () => {
32
ReactDOMClient = require('react-dom/client');
33
Scheduler = require('scheduler');
34
act = require('internal-test-utils').act;
35
+ assertLog = require('internal-test-utils').assertLog;
36
Suspense = React.Suspense;
37
container = document.createElement('div');
38
document.body.appendChild(container);
@@ -157,11 +159,11 @@ describe('ReactDOMSuspensePlaceholder', () => {
159
});
160
161
expect(container.textContent).toEqual('Loading...');
160
-
162
+ assertLog(['A', 'Suspend! [B]', 'Loading...']);
163
await act(() => {
164
resolveText('B');
165
});
164
-
166
+ assertLog(['A', 'B', 'C']);
167
expect(container.textContent).toEqual('ABC');
168
});
169
packages/react-dom/src/__tests__/ReactEmptyComponent-test.js
+3
-6
@@ -115,17 +115,14 @@ describe('ReactEmptyComponent', () => {
115
root1.render(instance1);
116
});
117
118
+ assertLog(['mount undefined', 'update DIV']);
119
+
120
const root2 = ReactDOMClient.createRoot(container2);
121
await act(() => {
122
root2.render(instance2);
123
});
124
123
- assertLog([
124
- 'mount undefined',
125
- 'update DIV',
126
- 'mount DIV',
127
- 'update undefined',
128
- ]);
125
+ assertLog(['mount DIV', 'update undefined']);
126
});
127
128
it('should be able to switch in a list of children', async () => {
packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js
+6
-2
@@ -112,11 +112,13 @@ describe('updaters', () => {
112
root.render(<Parent />);
113
});
114
expect(allSchedulerTags).toEqual([[HostRoot]]);
115
+ assertLog(['onCommitRoot']);
116
117
await act(() => {
118
root.render(<Parent />);
119
});
120
expect(allSchedulerTags).toEqual([[HostRoot], [HostRoot]]);
121
+ assertLog(['onCommitRoot']);
122
});
123
124
it('should report a function component as the scheduler for a hooks update', async () => {
@@ -148,12 +150,13 @@ describe('updaters', () => {
150
expect(scheduleForA).not.toBeNull();
151
expect(scheduleForB).not.toBeNull();
152
expect(allSchedulerTypes).toEqual([[null]]);
153
+ assertLog(['onCommitRoot']);
154
155
await act(() => {
156
scheduleForA();
157
});
158
expect(allSchedulerTypes).toEqual([[null], [SchedulingComponentA]]);
156
-
159
+ assertLog(['onCommitRoot']);
160
await act(() => {
161
scheduleForB();
162
});
@@ -162,6 +165,7 @@ describe('updaters', () => {
165
[SchedulingComponentA],
166
[SchedulingComponentB],
167
]);
168
+ assertLog(['onCommitRoot']);
169
});
170
171
it('should report a class component as the scheduler for a setState update', async () => {
@@ -180,7 +184,7 @@ describe('updaters', () => {
184
root.render(<Parent />);
185
});
186
expect(allSchedulerTypes).toEqual([[null]]);
183
-
187
+ assertLog(['onCommitRoot']);
188
expect(instance).not.toBeNull();
189
await act(() => {
190
instance.setState({});
packages/use-subscription/src/__tests__/useSubscription-test.js
+3
-7
@@ -338,6 +338,8 @@ describe('useSubscription', () => {
338
observableB.next('b-3');
339
});
340
341
+ assertLog(['Grandchild: b-0', 'Child: b-3', 'Grandchild: b-3']);
342
+
343
// Update again
344
await act(() => root.render(<Parent observed={observableA} />));
345
@@ -345,13 +347,7 @@ describe('useSubscription', () => {
347
// We expect the last emitted update to be rendered (because of the commit phase value check)
348
// But the intermediate ones should be ignored,
349
// And the final rendered output should be the higher-priority observable.
348
- assertLog([
349
- 'Grandchild: b-0',
350
- 'Child: b-3',
351
- 'Grandchild: b-3',
352
- 'Child: a-0',
353
- 'Grandchild: a-0',
354
- ]);
350
+ assertLog(['Child: a-0', 'Grandchild: a-0']);
351
expect(log).toEqual([
352
'Parent.componentDidMount',
353
'Parent.componentDidUpdate',
packages/use-sync-external-store/src/__tests__/useSyncExternalStoreShared-test.js
+5
@@ -660,14 +660,17 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
660
// Object.is algorithm to compare values.
661
await act(() => root.render(<App />));
662
expect(container.textContent).toEqual('NaN');
663
+ assertLog([NaN]);
664
665
// Update to real number
666
await act(() => store.set(123));
667
expect(container.textContent).toEqual('123');
668
+ assertLog([123]);
669
670
// Update back to NaN
671
await act(() => store.set('not a number'));
672
expect(container.textContent).toEqual('NaN');
673
+ assertLog([NaN]);
674
});
675
676
describe('extra features implemented in user-space', () => {
@@ -968,6 +971,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
971
),
972
);
973
974
+ assertLog(['A']);
975
expect(container.textContent).toEqual('A');
976
977
if (__DEV__ && gate(flags => flags.enableUseSyncExternalStoreShim)) {
@@ -1017,6 +1021,7 @@ describe('Shared useSyncExternalStore behavior (shim and built-in)', () => {
1021
),
1022
);
1023
1024
+ assertLog(['A']);
1025
expect(container.textContent).toEqual('A');
1026
1027
if (__DEV__ && gate(flags => flags.enableUseSyncExternalStoreShim)) {