forked from facebook/react
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathReactUpdatePriority-test.js
136 lines (120 loc) · 3.81 KB
/
ReactUpdatePriority-test.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
let React;
let ReactNoop;
let Scheduler;
let ContinuousEventPriority;
let startTransition;
let useState;
let useEffect;
let act;
describe('ReactUpdatePriority', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
ReactNoop = require('react-noop-renderer');
Scheduler = require('scheduler');
act = require('jest-react').act;
ContinuousEventPriority = require('react-reconciler/constants')
.ContinuousEventPriority;
startTransition = React.startTransition;
useState = React.useState;
useEffect = React.useEffect;
});
function Text({text}) {
Scheduler.unstable_yieldValue(text);
return text;
}
test('setState inside passive effect triggered by sync update should have default priority', async () => {
const root = ReactNoop.createRoot();
function App() {
const [state, setState] = useState(1);
useEffect(() => {
setState(2);
}, []);
return <Text text={state} />;
}
await act(async () => {
ReactNoop.flushSync(() => {
root.render(<App />);
});
// Should not have flushed the effect update yet
expect(Scheduler).toHaveYielded([1]);
});
expect(Scheduler).toHaveYielded([2]);
});
test('setState inside passive effect triggered by idle update should have idle priority', async () => {
const root = ReactNoop.createRoot();
let setDefaultState;
function App() {
const [idleState, setIdleState] = useState(1);
const [defaultState, _setDefaultState] = useState(1);
setDefaultState = _setDefaultState;
useEffect(() => {
Scheduler.unstable_yieldValue('Idle update');
setIdleState(2);
}, []);
return <Text text={`Idle: ${idleState}, Default: ${defaultState}`} />;
}
await act(async () => {
ReactNoop.idleUpdates(() => {
root.render(<App />);
});
// Should not have flushed the effect update yet
expect(Scheduler).toFlushUntilNextPaint(['Idle: 1, Default: 1']);
// Schedule another update at default priority
setDefaultState(2);
// The default update flushes first, because
expect(Scheduler).toFlushUntilNextPaint([
// Idle update is scheduled
'Idle update',
// The default update flushes first, without including the idle update
'Idle: 1, Default: 2',
]);
});
// Now the idle update has flushed
expect(Scheduler).toHaveYielded(['Idle: 2, Default: 2']);
});
test('continuous updates should interrupt transitions', async () => {
const root = ReactNoop.createRoot();
let setCounter;
let setIsHidden;
function App() {
const [counter, _setCounter] = useState(1);
const [isHidden, _setIsHidden] = useState(false);
setCounter = _setCounter;
setIsHidden = _setIsHidden;
if (isHidden) {
return <Text text={'(hidden)'} />;
}
return (
<>
<Text text={'A' + counter} />
<Text text={'B' + counter} />
<Text text={'C' + counter} />
</>
);
}
await act(async () => {
root.render(<App />);
});
expect(Scheduler).toHaveYielded(['A1', 'B1', 'C1']);
expect(root).toMatchRenderedOutput('A1B1C1');
await act(async () => {
startTransition(() => {
setCounter(2);
});
expect(Scheduler).toFlushAndYieldThrough(['A2']);
ReactNoop.unstable_runWithPriority(ContinuousEventPriority, () => {
setIsHidden(true);
});
});
expect(Scheduler).toHaveYielded([
// Because the hide update has continuous priority, it should interrupt the
// in-progress transition
'(hidden)',
// When the transition resumes, it's a no-op because the children are
// now hidden.
'(hidden)',
]);
expect(root).toMatchRenderedOutput('(hidden)');
});
});