1
+/**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @flow
8
+ */
9
+
10
+describe('profiling HostRoot', () => {
11
+ let React;
12
+ let ReactDOM;
13
+ let Scheduler;
14
+ let store: Store;
15
+ let utils;
16
+ let getEffectDurations;
17
+
18
+ let effectDurations;
19
+ let passiveEffectDurations;
20
+
21
+ beforeEach(() => {
22
+ utils = require('./utils');
23
+ utils.beforeEachProfiling();
24
+
25
+ getEffectDurations = require('../backend/utils').getEffectDurations;
26
+
27
+ store = global.store;
28
+
29
+ React = require('react');
30
+ ReactDOM = require('react-dom');
31
+ Scheduler = require('scheduler');
32
+
33
+ effectDurations = [];
34
+ passiveEffectDurations = [];
35
+
36
+ // This is the DevTools hook installed by the env.beforEach()
37
+ // The hook is installed as a read-only property on the window,
38
+ // so for our test purposes we can just override the commit hook.
39
+ const hook = global.__REACT_DEVTOOLS_GLOBAL_HOOK__;
40
+ hook.onPostCommitFiberRoot = function onPostCommitFiberRoot(
41
+ rendererID,
42
+ root,
43
+ ) {
44
+ const {effectDuration, passiveEffectDuration} = getEffectDurations(root);
45
+ effectDurations.push(effectDuration);
46
+ passiveEffectDurations.push(passiveEffectDuration);
47
+ };
48
+ });
49
+
50
+ it('should expose passive and layout effect durations for render()', () => {
51
+ function App() {
52
+ React.useEffect(() => {
53
+ Scheduler.unstable_advanceTime(10);
54
+ });
55
+ React.useLayoutEffect(() => {
56
+ Scheduler.unstable_advanceTime(100);
57
+ });
58
+ return null;
59
+ }
60
+
61
+ utils.act(() => store.profilerStore.startProfiling());
62
+ utils.act(() => {
63
+ const container = document.createElement('div');
64
+ ReactDOM.render(<App />, container);
65
+ });
66
+ utils.act(() => store.profilerStore.stopProfiling());
67
+
68
+ expect(effectDurations).toHaveLength(1);
69
+ const effectDuration = effectDurations[0];
70
+ expect(effectDuration === null || effectDuration === 100).toBe(true);
71
+ expect(passiveEffectDurations).toHaveLength(1);
72
+ const passiveEffectDuration = passiveEffectDurations[0];
73
+ expect(passiveEffectDuration === null || passiveEffectDuration === 10).toBe(
74
+ true,
75
+ );
76
+ });
77
+
78
+ it('should expose passive and layout effect durations for createRoot()', () => {
79
+ function App() {
80
+ React.useEffect(() => {
81
+ Scheduler.unstable_advanceTime(10);
82
+ });
83
+ React.useLayoutEffect(() => {
84
+ Scheduler.unstable_advanceTime(100);
85
+ });
86
+ return null;
87
+ }
88
+
89
+ utils.act(() => store.profilerStore.startProfiling());
90
+ utils.act(() => {
91
+ const container = document.createElement('div');
92
+ const root = ReactDOM.unstable_createRoot(container);
93
+ root.render(<App />);
94
+ });
95
+ utils.act(() => store.profilerStore.stopProfiling());
96
+
97
+ expect(effectDurations).toHaveLength(1);
98
+ const effectDuration = effectDurations[0];
99
+ expect(effectDuration === null || effectDuration === 100).toBe(true);
100
+ expect(passiveEffectDurations).toHaveLength(1);
101
+ const passiveEffectDuration = passiveEffectDurations[0];
102
+ expect(passiveEffectDuration === null || passiveEffectDuration === 10).toBe(
103
+ true,
104
+ );
105
+ });
106
+
107
+ it('should properly reset passive and layout effect durations between commits', () => {
108
+ function App({shouldCascade}) {
109
+ const [, setState] = React.useState(false);
110
+ React.useEffect(() => {
111
+ Scheduler.unstable_advanceTime(10);
112
+ });
113
+ React.useLayoutEffect(() => {
114
+ Scheduler.unstable_advanceTime(100);
115
+ });
116
+ React.useLayoutEffect(() => {
117
+ if (shouldCascade) {
118
+ setState(true);
119
+ }
120
+ }, [shouldCascade]);
121
+ return null;
122
+ }
123
+
124
+ const container = document.createElement('div');
125
+ const root = ReactDOM.unstable_createRoot(container);
126
+
127
+ utils.act(() => store.profilerStore.startProfiling());
128
+ utils.act(() => root.render(<App />));
129
+ utils.act(() => root.render(<App shouldCascade={true} />));
130
+ utils.act(() => store.profilerStore.stopProfiling());
131
+
132
+ expect(effectDurations).toHaveLength(3);
133
+ expect(passiveEffectDurations).toHaveLength(3);
134
+
135
+ for (let i = 0; i < effectDurations.length; i++) {
136
+ const effectDuration = effectDurations[i];
137
+ expect(effectDuration === null || effectDuration === 100).toBe(true);
138
+ const passiveEffectDuration = passiveEffectDurations[i];
139
+ expect(
140
+ passiveEffectDuration === null || passiveEffectDuration === 10,
141
+ ).toBe(true);
142
+ }
143
+ });
144
+});