@samitouri / QOS-React-2 / commits / b77c12576d

[DevTools] Add React Version Pragma to Tests (#24576)

This PR adds the reactVersion pragma to tests. Tests without the reactVersion pragma won't be run if the reactVersion pragma isn't specified. Tested each React version manually with the pragma to make sure the tests pass

Luna Ruan committed May 18, 2022 at 09:37 UTC b77c12576d332d5cee07305a6afee68203d43e9c
21 files changed +248
packages/react-devtools-shared/src/__tests__/FastRefreshDevToolsIntegration-test.js
+2
@@ -123,6 +123,7 @@ describe('Fast Refresh', () => {
123 return ReactFreshRuntime.createSignatureFunctionForTransform();
124 }
125
126 + // @reactVersion >= 16.9
127 it('should not break the DevTools store', () => {
128 render(`
129 function Parent() {
@@ -186,6 +187,7 @@ describe('Fast Refresh', () => {
187 expect(container.firstChild).not.toBe(element);
188 });
189
190 + // @reactVersion >= 16.9
191 it('should not break when there are warnings in between patching', () => {
192 withErrorsOrWarningsIgnored(['Expected:'], () => {
193 render(`
packages/react-devtools-shared/src/__tests__/TimelineProfiler-test.js
+39
@@ -124,6 +124,7 @@ describe('Timeline profiler', () => {
124 setPerformanceMock(null);
125 });
126
127 + // @reactVersion >=18.0
128 it('should mark sync render without suspends or state updates', () => {
129 renderHelper(<div />);
130
@@ -145,6 +146,7 @@ describe('Timeline profiler', () => {
146 `);
147 });
148
149 + // @reactVersion >=18.0
150 it('should mark concurrent render without suspends or state updates', () => {
151 renderRootHelper(<div />);
152
@@ -175,6 +177,7 @@ describe('Timeline profiler', () => {
177 `);
178 });
179
180 + // @reactVersion >=18.0
181 it('should mark render yields', async () => {
182 function Bar() {
183 Scheduler.unstable_yieldValue('Bar');
@@ -204,6 +207,7 @@ describe('Timeline profiler', () => {
207 `);
208 });
209
210 + // @reactVersion >=18.0
211 it('should mark sync render with suspense that resolves', async () => {
212 const fakeSuspensePromise = Promise.resolve(true);
213 function Example() {
@@ -246,6 +250,7 @@ describe('Timeline profiler', () => {
250 `);
251 });
252
253 + // @reactVersion >=18.0
254 it('should mark sync render with suspense that rejects', async () => {
255 const fakeSuspensePromise = Promise.reject(new Error('error'));
256 function Example() {
@@ -284,6 +289,7 @@ describe('Timeline profiler', () => {
289 expect(clearedMarks).toContain(`--suspense-rejected-0-Example`);
290 });
291
292 + // @reactVersion >=18.0
293 it('should mark concurrent render with suspense that resolves', async () => {
294 const fakeSuspensePromise = Promise.resolve(true);
295 function Example() {
@@ -335,6 +341,7 @@ describe('Timeline profiler', () => {
341 `);
342 });
343
344 + // @reactVersion >=18.0
345 it('should mark concurrent render with suspense that rejects', async () => {
346 const fakeSuspensePromise = Promise.reject(new Error('error'));
347 function Example() {
@@ -386,6 +393,7 @@ describe('Timeline profiler', () => {
393 `);
394 });
395
396 + // @reactVersion >=18.0
397 it('should mark cascading class component state updates', () => {
398 class Example extends React.Component {
399 state = {didMount: false};
@@ -440,6 +448,7 @@ describe('Timeline profiler', () => {
448 `);
449 });
450
451 + // @reactVersion >=18.0
452 it('should mark cascading class component force updates', () => {
453 class Example extends React.Component {
454 componentDidMount() {
@@ -493,6 +502,7 @@ describe('Timeline profiler', () => {
502 `);
503 });
504
505 + // @reactVersion >=18.0
506 it('should mark render phase state updates for class component', () => {
507 class Example extends React.Component {
508 state = {didRender: false};
@@ -546,6 +556,7 @@ describe('Timeline profiler', () => {
556 `);
557 });
558
559 + // @reactVersion >=18.0
560 it('should mark render phase force updates for class component', () => {
561 let forced = false;
562 class Example extends React.Component {
@@ -600,6 +611,7 @@ describe('Timeline profiler', () => {
611 `);
612 });
613
614 + // @reactVersion >=18.0
615 it('should mark cascading layout updates', () => {
616 function Example() {
617 const [didMount, setDidMount] = React.useState(false);
@@ -654,6 +666,7 @@ describe('Timeline profiler', () => {
666 `);
667 });
668
669 + // @reactVersion >=18.0
670 it('should mark cascading passive updates', () => {
671 function Example() {
672 const [didMount, setDidMount] = React.useState(false);
@@ -703,6 +716,7 @@ describe('Timeline profiler', () => {
716 `);
717 });
718
719 + // @reactVersion >=18.0
720 it('should mark render phase updates', () => {
721 function Example() {
722 const [didRender, setDidRender] = React.useState(false);
@@ -737,6 +751,7 @@ describe('Timeline profiler', () => {
751 `);
752 });
753
754 + // @reactVersion >=18.0
755 it('should mark sync render that throws', async () => {
756 spyOn(console, 'error');
757
@@ -799,6 +814,7 @@ describe('Timeline profiler', () => {
814 `);
815 });
816
817 + // @reactVersion >=18.0
818 it('should mark concurrent render that throws', async () => {
819 spyOn(console, 'error');
820
@@ -879,6 +895,7 @@ describe('Timeline profiler', () => {
895 `);
896 });
897
898 + // @reactVersion >=18.0
899 it('should mark passive and layout effects', async () => {
900 function ComponentWithEffects() {
901 React.useLayoutEffect(() => {
@@ -1015,6 +1032,7 @@ describe('Timeline profiler', () => {
1032 });
1033
1034 describe('lane labels', () => {
1035 + // @reactVersion >=18.0
1036 it('regression test SyncLane', () => {
1037 renderHelper(<div />);
1038
@@ -1036,6 +1054,7 @@ describe('Timeline profiler', () => {
1054 `);
1055 });
1056
1057 + // @reactVersion >=18.0
1058 it('regression test DefaultLane', () => {
1059 renderRootHelper(<div />);
1060 expect(clearedMarks).toMatchInlineSnapshot(`
@@ -1045,6 +1064,7 @@ describe('Timeline profiler', () => {
1064 `);
1065 });
1066
1067 + // @reactVersion >=18.0
1068 it('regression test InputDiscreteLane', async () => {
1069 const targetRef = React.createRef(null);
1070
@@ -1086,6 +1106,7 @@ describe('Timeline profiler', () => {
1106 `);
1107 });
1108
1109 + // @reactVersion >=18.0
1110 it('regression test InputContinuousLane', async () => {
1111 const targetRef = React.createRef(null);
1112
@@ -1170,6 +1191,7 @@ describe('Timeline profiler', () => {
1191 utils.act(() => store.profilerStore.startProfiling());
1192 });
1193
1194 + // @reactVersion >=18.0
1195 it('should mark sync render without suspends or state updates', () => {
1196 renderHelper(<div />);
1197
@@ -1186,6 +1208,7 @@ describe('Timeline profiler', () => {
1208 `);
1209 });
1210
1211 + // @reactVersion >=18.0
1212 it('should mark concurrent render without suspends or state updates', () => {
1213 utils.act(() => renderRootHelper(<div />));
1214
@@ -1202,6 +1225,7 @@ describe('Timeline profiler', () => {
1225 `);
1226 });
1227
1228 + // @reactVersion >=18.0
1229 it('should mark concurrent render without suspends or state updates', () => {
1230 let updaterFn;
1231
@@ -1281,6 +1305,7 @@ describe('Timeline profiler', () => {
1305 expect(timelineData.batchUIDToMeasuresMap.size).toBe(2);
1306 });
1307
1308 + // @reactVersion >=18.0
1309 it('should mark render yields', async () => {
1310 function Bar() {
1311 Scheduler.unstable_yieldValue('Bar');
@@ -1365,6 +1390,7 @@ describe('Timeline profiler', () => {
1390 expect(timelineData.componentMeasures).toHaveLength(2);
1391 });
1392
1393 + // @reactVersion >=18.0
1394 it('should mark sync render with suspense that rejects', async () => {
1395 let rejectFn;
1396 let rejected = false;
@@ -1422,6 +1448,7 @@ describe('Timeline profiler', () => {
1448 expect(timelineData.componentMeasures).toHaveLength(2);
1449 });
1450
1451 + // @reactVersion >=18.0
1452 it('should mark concurrent render with suspense that resolves', async () => {
1453 let resolveFn;
1454 let resolved = false;
@@ -1479,6 +1506,7 @@ describe('Timeline profiler', () => {
1506 expect(timelineData.componentMeasures).toHaveLength(2);
1507 });
1508
1509 + // @reactVersion >=18.0
1510 it('should mark concurrent render with suspense that rejects', async () => {
1511 let rejectFn;
1512 let rejected = false;
@@ -1536,6 +1564,7 @@ describe('Timeline profiler', () => {
1564 expect(timelineData.componentMeasures).toHaveLength(2);
1565 });
1566
1567 + // @reactVersion >=18.0
1568 it('should mark cascading class component state updates', () => {
1569 class Example extends React.Component {
1570 state = {didMount: false};
@@ -1594,6 +1623,7 @@ describe('Timeline profiler', () => {
1623 `);
1624 });
1625
1626 + // @reactVersion >=18.0
1627 it('should mark cascading class component force updates', () => {
1628 let forced = false;
1629 class Example extends React.Component {
@@ -1651,6 +1681,7 @@ describe('Timeline profiler', () => {
1681 `);
1682 });
1683
1684 + // @reactVersion >=18.0
1685 it('should mark render phase state updates for class component', () => {
1686 class Example extends React.Component {
1687 state = {didRender: false};
@@ -1719,6 +1750,7 @@ describe('Timeline profiler', () => {
1750 `);
1751 });
1752
1753 + // @reactVersion >=18.0
1754 it('should mark render phase force updates for class component', () => {
1755 let forced = false;
1756 class Example extends React.Component {
@@ -1786,6 +1818,7 @@ describe('Timeline profiler', () => {
1818 `);
1819 });
1820
1821 + // @reactVersion >=18.0
1822 it('should mark cascading layout updates', () => {
1823 function Example() {
1824 const [didMount, setDidMount] = React.useState(false);
@@ -1848,6 +1881,7 @@ describe('Timeline profiler', () => {
1881 `);
1882 });
1883
1884 + // @reactVersion >=18.0
1885 it('should mark cascading passive updates', () => {
1886 function Example() {
1887 const [didMount, setDidMount] = React.useState(false);
@@ -1909,6 +1943,7 @@ describe('Timeline profiler', () => {
1943 `);
1944 });
1945
1946 + // @reactVersion >=18.0
1947 it('should mark render phase updates', () => {
1948 function Example() {
1949 const [didRender, setDidRender] = React.useState(false);
@@ -1956,6 +1991,7 @@ describe('Timeline profiler', () => {
1991 `);
1992 });
1993
1994 + // @reactVersion >=18.0
1995 it('should mark sync render that throws', async () => {
1996 spyOn(console, 'error');
1997
@@ -2049,6 +2085,7 @@ describe('Timeline profiler', () => {
2085 `);
2086 });
2087
2088 + // @reactVersion >=18.0
2089 it('should mark concurrent render that throws', async () => {
2090 spyOn(console, 'error');
2091
@@ -2167,6 +2204,7 @@ describe('Timeline profiler', () => {
2204 `);
2205 });
2206
2207 + // @reactVersion >=18.0
2208 it('should mark passive and layout effects', async () => {
2209 function ComponentWithEffects() {
2210 React.useLayoutEffect(() => {
@@ -2406,6 +2444,7 @@ describe('Timeline profiler', () => {
2444 });
2445
2446 describe('when not profiling', () => {
2447 + // @reactVersion >=18.0
2448 it('should not log any marks', () => {
2449 renderHelper(<div />);
2450
packages/react-devtools-shared/src/__tests__/bridge-test.js
+1
@@ -14,6 +14,7 @@ describe('Bridge', () => {
14 Bridge = require('react-devtools-shared/src/bridge').default;
15 });
16
17 + // @reactVersion >=16.0
18 it('should shutdown properly', () => {
19 const wall = {
20 listen: jest.fn(() => () => {}),
packages/react-devtools-shared/src/__tests__/componentStacks-test.js
+1
@@ -49,6 +49,7 @@ describe('component stack', () => {
49 React = require('react');
50 });
51
52 + // @reactVersion >=16.9
53 it('should log the current component stack along with an error or warning', () => {
54 const Grandparent = () => <Parent />;
55 const Parent = () => <Child />;
packages/react-devtools-shared/src/__tests__/console-test.js
+16
@@ -69,6 +69,7 @@ describe('console', () => {
69 );
70 }
71
72 + // @reactVersion >=18.0
73 it('should not patch console methods that are not explicitly overridden', () => {
74 expect(fakeConsole.error).not.toBe(mockError);
75 expect(fakeConsole.info).toBe(mockInfo);
@@ -76,6 +77,7 @@ describe('console', () => {
77 expect(fakeConsole.warn).not.toBe(mockWarn);
78 });
79
80 + // @reactVersion >=18.0
81 it('should patch the console when appendComponentStack is enabled', () => {
82 unpatchConsole();
83
@@ -92,6 +94,7 @@ describe('console', () => {
94 expect(fakeConsole.warn).not.toBe(mockWarn);
95 });
96
97 + // @reactVersion >=18.0
98 it('should patch the console when breakOnConsoleErrors is enabled', () => {
99 unpatchConsole();
100
@@ -108,6 +111,7 @@ describe('console', () => {
111 expect(fakeConsole.warn).not.toBe(mockWarn);
112 });
113
114 + // @reactVersion >=18.0
115 it('should patch the console when showInlineWarningsAndErrors is enabled', () => {
116 unpatchConsole();
117
@@ -124,6 +128,7 @@ describe('console', () => {
128 expect(fakeConsole.warn).not.toBe(mockWarn);
129 });
130
131 + // @reactVersion >=18.0
132 it('should only patch the console once', () => {
133 const {error, warn} = fakeConsole;
134
@@ -137,6 +142,7 @@ describe('console', () => {
142 expect(fakeConsole.warn).toBe(warn);
143 });
144
145 + // @reactVersion >=18.0
146 it('should un-patch when requested', () => {
147 expect(fakeConsole.error).not.toBe(mockError);
148 expect(fakeConsole.warn).not.toBe(mockWarn);
@@ -147,6 +153,7 @@ describe('console', () => {
153 expect(fakeConsole.warn).toBe(mockWarn);
154 });
155
156 + // @reactVersion >=18.0
157 it('should pass through logs when there is no current fiber', () => {
158 expect(mockLog).toHaveBeenCalledTimes(0);
159 expect(mockWarn).toHaveBeenCalledTimes(0);
@@ -165,6 +172,7 @@ describe('console', () => {
172 expect(mockError.mock.calls[0][0]).toBe('error');
173 });
174
175 + // @reactVersion >=18.0
176 it('should not append multiple stacks', () => {
177 global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true;
178
@@ -187,6 +195,7 @@ describe('console', () => {
195 expect(mockError.mock.calls[0][1]).toBe('\n in Child (at fake.js:123)');
196 });
197
198 + // @reactVersion >=18.0
199 it('should append component stacks to errors and warnings logged during render', () => {
200 global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true;
201
@@ -222,6 +231,7 @@ describe('console', () => {
231 );
232 });
233
234 + // @reactVersion >=18.0
235 it('should append component stacks to errors and warnings logged from effects', () => {
236 const Intermediate = ({children}) => children;
237 const Parent = ({children}) => (
@@ -274,6 +284,7 @@ describe('console', () => {
284 );
285 });
286
287 + // @reactVersion >=18.0
288 it('should append component stacks to errors and warnings logged from commit hooks', () => {
289 global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true;
290
@@ -332,6 +343,7 @@ describe('console', () => {
343 );
344 });
345
346 + // @reactVersion >=18.0
347 it('should append component stacks to errors and warnings logged from gDSFP', () => {
348 const Intermediate = ({children}) => children;
349 const Parent = ({children}) => (
@@ -371,6 +383,7 @@ describe('console', () => {
383 );
384 });
385
386 + // @reactVersion >=18.0
387 it('should append stacks after being uninstalled and reinstalled', () => {
388 global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = false;
389
@@ -410,6 +423,7 @@ describe('console', () => {
423 );
424 });
425
426 + // @reactVersion >=18.0
427 it('should be resilient to prepareStackTrace', () => {
428 global.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = true;
429
@@ -459,6 +473,7 @@ describe('console', () => {
473 );
474 });
475
476 + // @reactVersion >=18.0
477 it('should correctly log Symbols', () => {
478 const Component = ({children}) => {
479 fakeConsole.warn('Symbol:', Symbol(''));
@@ -753,6 +768,7 @@ describe('console error', () => {
768 legacyRender = utils.legacyRender;
769 });
770
771 + // @reactVersion >=18.0
772 it('error in console log throws without interfering with logging', () => {
773 const container = document.createElement('div');
774 const root = ReactDOMClient.createRoot(container);
packages/react-devtools-shared/src/__tests__/editing-test.js
+21
@@ -109,6 +109,7 @@ describe('editing interface', () => {
109 expect(inputRef.current.value).toBe('initial');
110 }
111
112 + // @reactVersion >= 16.9
113 it('should have editable values', async () => {
114 await mountTestApp();
115
@@ -175,6 +176,7 @@ describe('editing interface', () => {
176 });
177 });
178
179 + // @reactVersion >= 16.9
180 // Tests the combination of older frontend (DevTools UI) with newer backend (embedded within a renderer).
181 it('should still support overriding prop values with legacy backend methods', async () => {
182 await mountTestApp();
@@ -209,6 +211,7 @@ describe('editing interface', () => {
211 });
212 });
213
214 + // @reactVersion >= 17.0
215 it('should have editable paths', async () => {
216 await mountTestApp();
217
@@ -259,6 +262,7 @@ describe('editing interface', () => {
262 });
263 });
264
265 + // @reactVersion >= 16.9
266 it('should enable adding new object properties and array values', async () => {
267 await mountTestApp();
268
@@ -339,6 +343,7 @@ describe('editing interface', () => {
343 });
344 });
345
346 + // @reactVersion >= 17.0
347 it('should have deletable keys', async () => {
348 await mountTestApp();
349
@@ -390,6 +395,7 @@ describe('editing interface', () => {
395 });
396 });
397
398 + // @reactVersion >= 16.9
399 it('should support editing host component values', async () => {
400 await mountTestApp();
401
@@ -453,6 +459,7 @@ describe('editing interface', () => {
459 });
460 }
461
462 + // @reactVersion >= 16.9
463 it('should have editable values', async () => {
464 await mountTestApp();
465
@@ -490,6 +497,7 @@ describe('editing interface', () => {
497 });
498 });
499
500 + // @reactVersion >= 16.9
501 // Tests the combination of older frontend (DevTools UI) with newer backend (embedded within a renderer).
502 it('should still support overriding state values with legacy backend methods', async () => {
503 await mountTestApp();
@@ -513,6 +521,7 @@ describe('editing interface', () => {
521 });
522 });
523
524 + // @reactVersion >= 16.9
525 it('should have editable paths', async () => {
526 await mountTestApp();
527
@@ -547,6 +556,7 @@ describe('editing interface', () => {
556 });
557 });
558
559 + // @reactVersion >= 16.9
560 it('should enable adding new object properties and array values', async () => {
561 await mountTestApp();
562
@@ -595,6 +605,7 @@ describe('editing interface', () => {
605 });
606 });
607
608 + // @reactVersion >= 16.9
609 it('should have deletable keys', async () => {
610 await mountTestApp();
611
@@ -668,6 +679,7 @@ describe('editing interface', () => {
679 });
680 }
681
682 + // @reactVersion >= 16.9
683 it('should have editable values', async () => {
684 await mountTestApp();
685
@@ -712,6 +724,7 @@ describe('editing interface', () => {
724 });
725 });
726
727 + // @reactVersion >= 16.9
728 // Tests the combination of older frontend (DevTools UI) with newer backend (embedded within a renderer).
729 it('should still support overriding hook values with legacy backend methods', async () => {
730 await mountTestApp();
@@ -738,6 +751,7 @@ describe('editing interface', () => {
751 });
752 });
753
754 + // @reactVersion >= 17.0
755 it('should have editable paths', async () => {
756 await mountTestApp();
757
@@ -773,6 +787,7 @@ describe('editing interface', () => {
787 });
788 });
789
790 + // @reactVersion >= 16.9
791 it('should enable adding new object properties and array values', async () => {
792 await mountTestApp();
793
@@ -822,6 +837,7 @@ describe('editing interface', () => {
837 });
838 });
839
840 + // @reactVersion >= 17.0
841 it('should have deletable keys', async () => {
842 await mountTestApp();
843
@@ -925,6 +941,7 @@ describe('editing interface', () => {
941 });
942 }
943
944 + // @reactVersion >= 16.9
945 it('should have editable values', async () => {
946 await mountTestApp();
947
@@ -973,6 +990,7 @@ describe('editing interface', () => {
990 });
991 });
992
993 + // @reactVersion >= 16.9
994 // Tests the combination of older frontend (DevTools UI) with newer backend (embedded within a renderer).
995 it('should still support overriding context values with legacy backend methods', async () => {
996 await mountTestApp();
@@ -1003,6 +1021,7 @@ describe('editing interface', () => {
1021 });
1022 });
1023
1024 + // @reactVersion >= 16.9
1025 it('should have editable paths', async () => {
1026 await mountTestApp();
1027
@@ -1043,6 +1062,7 @@ describe('editing interface', () => {
1062 });
1063 });
1064
1065 + // @reactVersion >= 16.9
1066 it('should enable adding new object properties and array values', async () => {
1067 await mountTestApp();
1068
@@ -1096,6 +1116,7 @@ describe('editing interface', () => {
1116 });
1117 });
1118
1119 + // @reactVersion >= 16.9
1120 it('should have deletable keys', async () => {
1121 await mountTestApp();
1122
packages/react-devtools-shared/src/__tests__/events-test.js
+7
@@ -16,10 +16,12 @@ describe('events', () => {
16 dispatcher = new EventEmitter();
17 });
18
19 + // @reactVersion >=16
20 it('can dispatch an event with no listeners', () => {
21 dispatcher.emit('event', 123);
22 });
23
24 + // @reactVersion >=16
25 it('handles a listener being attached multiple times', () => {
26 const callback = jest.fn();
27
@@ -31,6 +33,7 @@ describe('events', () => {
33 expect(callback).toHaveBeenCalledWith(123);
34 });
35
36 + // @reactVersion >=16
37 it('notifies all attached listeners of events', () => {
38 const callback1 = jest.fn();
39 const callback2 = jest.fn();
@@ -48,6 +51,7 @@ describe('events', () => {
51 expect(callback3).not.toHaveBeenCalled();
52 });
53
54 + // @reactVersion >= 16.0
55 it('calls later listeners before re-throwing if an earlier one throws', () => {
56 const callbackThatThrows = jest.fn(() => {
57 throw Error('expected');
@@ -67,6 +71,7 @@ describe('events', () => {
71 expect(callback).toHaveBeenCalledWith(123);
72 });
73
74 + // @reactVersion >= 16.0
75 it('removes attached listeners', () => {
76 const callback1 = jest.fn();
77 const callback2 = jest.fn();
@@ -81,6 +86,7 @@ describe('events', () => {
86 expect(callback2).toHaveBeenCalledWith(123);
87 });
88
89 + // @reactVersion >= 16.0
90 it('removes all listeners', () => {
91 const callback1 = jest.fn();
92 const callback2 = jest.fn();
@@ -98,6 +104,7 @@ describe('events', () => {
104 expect(callback3).not.toHaveBeenCalled();
105 });
106
107 + // @reactVersion >= 16.0
108 it('should call the initial listeners even if others are added or removed during a dispatch', () => {
109 const callback1 = jest.fn(() => {
110 dispatcher.removeListener('event', callback2);
packages/react-devtools-shared/src/__tests__/legacy/editing-test.js
+12
@@ -84,6 +84,7 @@ describe('editing interface', () => {
84 });
85 }
86
87 + // @reactVersion >= 16.0
88 it('should have editable values', () => {
89 mountTestApp();
90
@@ -125,6 +126,7 @@ describe('editing interface', () => {
126 });
127 });
128
129 + // @reactVersion >= 16.0
130 it('should have editable paths', () => {
131 mountTestApp();
132
@@ -158,6 +160,7 @@ describe('editing interface', () => {
160 });
161 });
162
163 + // @reactVersion >= 16.0
164 it('should enable adding new object properties and array values', async () => {
165 await mountTestApp();
166
@@ -206,6 +209,7 @@ describe('editing interface', () => {
209 });
210 });
211
212 + // @reactVersion >= 16.0
213 it('should have deletable keys', () => {
214 mountTestApp();
215
@@ -282,6 +286,7 @@ describe('editing interface', () => {
286 });
287 }
288
289 + // @reactVersion >= 16.0
290 it('should have editable values', () => {
291 mountTestApp();
292
@@ -319,6 +324,7 @@ describe('editing interface', () => {
324 });
325 });
326
327 + // @reactVersion >= 16.0
328 it('should have editable paths', () => {
329 mountTestApp();
330
@@ -353,6 +359,7 @@ describe('editing interface', () => {
359 });
360 });
361
362 + // @reactVersion >= 16.0
363 it('should enable adding new object properties and array values', async () => {
364 await mountTestApp();
365
@@ -401,6 +408,7 @@ describe('editing interface', () => {
408 });
409 });
410
411 + // @reactVersion >= 16.0
412 it('should have deletable keys', () => {
413 mountTestApp();
414
@@ -502,6 +510,7 @@ describe('editing interface', () => {
510 });
511 }
512
513 + // @reactVersion >= 16.0
514 it('should have editable values', () => {
515 mountTestApp();
516
@@ -546,6 +555,7 @@ describe('editing interface', () => {
555 });
556 });
557
558 + // @reactVersion >= 16.0
559 it('should have editable paths', () => {
560 mountTestApp();
561
@@ -581,6 +591,7 @@ describe('editing interface', () => {
591 });
592 });
593
594 + // @reactVersion >= 16.0
595 it('should enable adding new object properties and array values', async () => {
596 await mountTestApp();
597
@@ -630,6 +641,7 @@ describe('editing interface', () => {
641 });
642 });
643
644 + // @reactVersion >= 16.0
645 it('should have deletable keys', () => {
646 mountTestApp();
647
packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js
+13
@@ -62,6 +62,7 @@ describe('InspectedElementContext', () => {
62 ReactDOM = require('react-dom');
63 });
64
65 + // @reactVersion >= 16.0
66 it('should inspect the currently selected element', async () => {
67 const Example = () => null;
68
@@ -89,6 +90,7 @@ describe('InspectedElementContext', () => {
90 `);
91 });
92
93 + // @reactVersion >= 16.0
94 it('should support simple data types', async () => {
95 const Example = () => null;
96
@@ -140,6 +142,7 @@ describe('InspectedElementContext', () => {
142 `);
143 });
144
145 + // @reactVersion >= 16.0
146 it('should support complex data types', async () => {
147 const Immutable = require('immutable');
148
@@ -324,6 +327,7 @@ describe('InspectedElementContext', () => {
327 `);
328 });
329
330 + // @reactVersion >= 16.0
331 it('should support objects with no prototype', async () => {
332 const Example = () => null;
333
@@ -353,6 +357,7 @@ describe('InspectedElementContext', () => {
357 `);
358 });
359
360 + // @reactVersion >= 16.0
361 it('should support objects with overridden hasOwnProperty', async () => {
362 const Example = () => null;
363
@@ -377,6 +382,7 @@ describe('InspectedElementContext', () => {
382 expect(inspectedElement.props.object.hasOwnProperty).toBe(true);
383 });
384
385 + // @reactVersion >= 16.0
386 it('should not consume iterables while inspecting', async () => {
387 const Example = () => null;
388
@@ -421,6 +427,7 @@ describe('InspectedElementContext', () => {
427 expect(iteratable.next().value).toBeUndefined();
428 });
429
430 + // @reactVersion >= 16.0
431 it('should support custom objects with enumerable properties and getters', async () => {
432 class CustomData {
433 _number = 42;
@@ -470,6 +477,7 @@ describe('InspectedElementContext', () => {
477 `);
478 });
479
480 + // @reactVersion >= 16.0
481 it('should support objects with with inherited keys', async () => {
482 const Example = () => null;
483
@@ -562,6 +570,7 @@ describe('InspectedElementContext', () => {
570 `);
571 });
572
573 + // @reactVersion >= 16.0
574 it('should allow component prop value and value`s prototype has same name params.', async () => {
575 const testData = Object.create(
576 {
@@ -621,6 +630,7 @@ describe('InspectedElementContext', () => {
630 `);
631 });
632
633 + // @reactVersion >= 16.0
634 it('should not dehydrate nested values until explicitly requested', async () => {
635 const Example = () => null;
636
@@ -723,6 +733,7 @@ describe('InspectedElementContext', () => {
733 `);
734 });
735
736 + // @reactVersion >= 16.0
737 it('should enable inspected values to be stored as global variables', () => {
738 const Example = () => null;
739
@@ -778,6 +789,7 @@ describe('InspectedElementContext', () => {
789 expect(global.$reactTemp1).toBe(nestedObject.a.b);
790 });
791
792 + // @reactVersion >= 16.0
793 it('should enable inspected values to be copied to the clipboard', () => {
794 const Example = () => null;
795
@@ -834,6 +846,7 @@ describe('InspectedElementContext', () => {
846 );
847 });
848
849 + // @reactVersion >= 16.0
850 it('should enable complex values to be copied to the clipboard', () => {
851 const Immutable = require('immutable');
852
packages/react-devtools-shared/src/__tests__/preprocessData-test.js
+27
@@ -107,6 +107,7 @@ describe('Timeline profiler', () => {
107 .getLanesFromTransportDecimalBitmask;
108 });
109
110 + // @reactVersion >= 18.0
111 it('should return array of lane numbers from bitmask string', () => {
112 expect(getLanesFromTransportDecimalBitmask('1')).toEqual([0]);
113 expect(getLanesFromTransportDecimalBitmask('512')).toEqual([9]);
@@ -126,6 +127,7 @@ describe('Timeline profiler', () => {
127 ).toEqual(Array.from(Array(31).keys()));
128 });
129
130 + // @reactVersion >= 18.0
131 it('should return empty array if laneBitmaskString is not a bitmask', () => {
132 expect(getLanesFromTransportDecimalBitmask('')).toEqual([]);
133 expect(getLanesFromTransportDecimalBitmask('hello')).toEqual([]);
@@ -133,6 +135,7 @@ describe('Timeline profiler', () => {
135 expect(getLanesFromTransportDecimalBitmask('-0')).toEqual([]);
136 });
137
138 + // @reactVersion >= 18.0
139 it('should ignore lanes outside REACT_TOTAL_NUM_LANES', () => {
140 const REACT_TOTAL_NUM_LANES = require('react-devtools-timeline/src/constants')
141 .REACT_TOTAL_NUM_LANES;
@@ -258,10 +261,12 @@ describe('Timeline profiler', () => {
261 startTime = 0;
262 });
263
264 + // @reactVersion >= 18.0
265 it('should throw given an empty timeline', async () => {
266 await expect(async () => preprocessData([])).rejects.toThrow();
267 });
268
269 + // @reactVersion >= 18.0
270 it('should throw given a timeline with no Profile event', async () => {
271 const randomSample = createUserTimingEntry({
272 dur: 100,
@@ -277,6 +282,7 @@ describe('Timeline profiler', () => {
282 ).rejects.toThrow();
283 });
284
285 + // @reactVersion >= 18.0
286 it('should throw given a timeline without an explicit profiler version mark nor any other React marks', async () => {
287 const cpuProfilerSample = creactCpuProfilerSample();
288
@@ -287,6 +293,7 @@ describe('Timeline profiler', () => {
293 );
294 });
295
296 + // @reactVersion >= 18.0
297 it('should throw given a timeline with React scheduling marks, but without an explicit profiler version mark', async () => {
298 const cpuProfilerSample = creactCpuProfilerSample();
299 const scheduleRenderSample = createUserTimingEntry({
@@ -300,6 +307,7 @@ describe('Timeline profiler', () => {
307 );
308 });
309
310 + // @reactVersion >= 18.0
311 it('should return empty data given a timeline with no React scheduling profiling marks', async () => {
312 const cpuProfilerSample = creactCpuProfilerSample();
313 const randomSample = createUserTimingEntry({
@@ -403,6 +411,7 @@ describe('Timeline profiler', () => {
411 `);
412 });
413
414 + // @reactVersion >= 18.0
415 it('should process legacy data format (before lane labels were added)', async () => {
416 const cpuProfilerSample = creactCpuProfilerSample();
417
@@ -602,6 +611,7 @@ describe('Timeline profiler', () => {
611 `);
612 });
613
614 + // @reactVersion >= 18.0
615 it('should process a sample legacy render sequence', async () => {
616 utils.legacyRender(<div />, document.createElement('div'));
617
@@ -788,6 +798,7 @@ describe('Timeline profiler', () => {
798 `);
799 });
800
801 + // @reactVersion >= 18.0
802 it('should process a sample createRoot render sequence', async () => {
803 function App() {
804 const [didMount, setDidMount] = React.useState(false);
@@ -1119,6 +1130,7 @@ describe('Timeline profiler', () => {
1130 `);
1131 });
1132
1133 + // @reactVersion >= 18.0
1134 it('should error if events and measures are incomplete', async () => {
1135 const container = document.createElement('div');
1136 utils.legacyRender(<div />, container);
@@ -1136,6 +1148,7 @@ describe('Timeline profiler', () => {
1148 expect(error).toHaveBeenCalled();
1149 });
1150
1151 + // @reactVersion >= 18.0
1152 it('should error if work is completed without being started', async () => {
1153 const container = document.createElement('div');
1154 utils.legacyRender(<div />, container);
@@ -1153,6 +1166,7 @@ describe('Timeline profiler', () => {
1166 expect(error).toHaveBeenCalled();
1167 });
1168
1169 + // @reactVersion >= 18.0
1170 it('should populate other user timing marks', async () => {
1171 const userTimingData = createUserTimingData([]);
1172 userTimingData.push(
@@ -1202,6 +1216,7 @@ describe('Timeline profiler', () => {
1216 `);
1217 });
1218
1219 + // @reactVersion >= 18.0
1220 it('should include a suspended resource "displayName" if one is set', async () => {
1221 let promise = null;
1222 let resolvedValue = null;
@@ -1245,6 +1260,7 @@ describe('Timeline profiler', () => {
1260
1261 describe('warnings', () => {
1262 describe('long event handlers', () => {
1263 + // @reactVersion >= 18.0
1264 it('should not warn when React scedules a (sync) update inside of a short event handler', async () => {
1265 function App() {
1266 return null;
@@ -1267,6 +1283,7 @@ describe('Timeline profiler', () => {
1283 expect(event.warning).toBe(null);
1284 });
1285
1286 + // @reactVersion >= 18.0
1287 it('should not warn about long events if the cause was non-React JavaScript', async () => {
1288 function App() {
1289 return null;
@@ -1291,6 +1308,7 @@ describe('Timeline profiler', () => {
1308 expect(event.warning).toBe(null);
1309 });
1310
1311 + // @reactVersion >= 18.0
1312 it('should warn when React scedules a long (sync) update inside of an event', async () => {
1313 function App() {
1314 return null;
@@ -1330,6 +1348,7 @@ describe('Timeline profiler', () => {
1348 );
1349 });
1350
1351 + // @reactVersion >= 18.0
1352 it('should not warn when React finishes a previously long (async) update with a short (sync) update inside of an event', async () => {
1353 function Yield({id, value}) {
1354 Scheduler.unstable_yieldValue(`${id}:${value}`);
@@ -1390,6 +1409,7 @@ describe('Timeline profiler', () => {
1409 });
1410
1411 describe('nested updates', () => {
1412 + // @reactVersion >= 18.0
1413 it('should not warn about short nested (state) updates during layout effects', async () => {
1414 function Component() {
1415 const [didMount, setDidMount] = React.useState(false);
@@ -1425,6 +1445,7 @@ describe('Timeline profiler', () => {
1445 expect(event.warning).toBe(null);
1446 });
1447
1448 + // @reactVersion >= 18.0
1449 it('should not warn about short (forced) updates during layout effects', async () => {
1450 class Component extends React.Component {
1451 _didMount: boolean = false;
@@ -1588,6 +1609,7 @@ describe('Timeline profiler', () => {
1609 );
1610 });
1611
1612 + // @reactVersion >= 18.0
1613 it('should not warn about transition updates scheduled during commit phase', async () => {
1614 function Component() {
1615 const [value, setValue] = React.useState(0);
@@ -1729,6 +1751,7 @@ describe('Timeline profiler', () => {
1751 });
1752
1753 describe('errors thrown while rendering', () => {
1754 + // @reactVersion >= 18.0
1755 it('shoult parse Errors thrown during render', async () => {
1756 spyOn(console, 'error');
1757
@@ -1776,6 +1799,7 @@ describe('Timeline profiler', () => {
1799 describe('suspend during an update', () => {
1800 // This also tests an edge case where the a component suspends while profiling
1801 // before the first commit is logged (so the lane-to-labels map will not yet exist).
1802 + // @reactVersion >= 18.0
1803 it('should warn about suspending during an udpate', async () => {
1804 let promise = null;
1805 let resolvedValue = null;
@@ -1833,6 +1857,7 @@ describe('Timeline profiler', () => {
1857 );
1858 });
1859
1860 + // @reactVersion >= 18.0
1861 it('should not warn about suspending during an transition', async () => {
1862 let promise = null;
1863 let resolvedValue = null;
@@ -1920,6 +1945,7 @@ describe('Timeline profiler', () => {
1945 global.IS_REACT_ACT_ENVIRONMENT = true;
1946 });
1947
1948 + // @reactVersion >= 18.0
1949 it('should process a sample legacy render sequence', async () => {
1950 utils.legacyRender(<div />, document.createElement('div'));
1951 utils.act(() => store.profilerStore.stopProfiling());
@@ -2089,6 +2115,7 @@ describe('Timeline profiler', () => {
2115 `);
2116 });
2117
2118 + // @reactVersion >= 18.0
2119 it('should process a sample createRoot render sequence', async () => {
2120 function App() {
2121 const [didMount, setDidMount] = React.useState(false);
packages/react-devtools-shared/src/__tests__/profilerChangeDescriptions-test.js
+1
@@ -26,6 +26,7 @@ describe('Profiler change descriptions', () => {
26 React = require('react');
27 });
28
29 + // @reactVersion >=18.0
30 it('should identify useContext as the cause for a re-render', () => {
31 const Context = React.createContext(0);
32
packages/react-devtools-shared/src/__tests__/profilerStore-test.js
+7
@@ -30,6 +30,7 @@ describe('ProfilerStore', () => {
30 ReactDOM = require('react-dom');
31 });
32
33 + // @reactVersion >= 16.9
34 it('should not remove profiling data when roots are unmounted', async () => {
35 const Parent = ({count}) =>
36 new Array(count)
@@ -66,6 +67,7 @@ describe('ProfilerStore', () => {
67 expect(store.profilerStore.getDataForRoot(rootB)).not.toBeNull();
68 });
69
70 + // @reactVersion >= 16.9
71 it('should not allow new/saved profiling data to be set while profiling is in progress', () => {
72 utils.act(() => store.profilerStore.startProfiling());
73 const fauxProfilingData = {
@@ -83,6 +85,7 @@ describe('ProfilerStore', () => {
85 expect(store.profilerStore.profilingData).toBe(fauxProfilingData);
86 });
87
88 + // @reactVersion >= 16.9
89 // This test covers current broken behavior (arguably) with the synthetic event system.
90 it('should filter empty commits', () => {
91 const inputRef = React.createRef();
@@ -124,6 +127,7 @@ describe('ProfilerStore', () => {
127 expect(data.operations).toHaveLength(1);
128 });
129
130 + // @reactVersion >= 16.9
131 it('should filter empty commits alt', () => {
132 let commitCount = 0;
133
@@ -175,6 +179,7 @@ describe('ProfilerStore', () => {
179 expect(data.operations).toHaveLength(1);
180 });
181
182 + // @reactVersion >= 16.9
183 it('should throw if component filters are modified while profiling', () => {
184 utils.act(() => store.profilerStore.startProfiling());
185
@@ -190,6 +195,7 @@ describe('ProfilerStore', () => {
195 }).toThrow('Cannot modify filter preferences while profiling');
196 });
197
198 + // @reactVersion >= 16.9
199 it('should not throw if state contains a property hasOwnProperty ', () => {
200 let setStateCallback;
201 const ControlledInput = () => {
@@ -222,6 +228,7 @@ describe('ProfilerStore', () => {
228 expect(data.operations).toHaveLength(1);
229 });
230
231 + // @reactVersion >= 18.0
232 it('should not throw while initializing context values for Fibers within a not-yet-mounted subtree', () => {
233 const promise = new Promise(resolve => {});
234 const SuspendingView = () => {
packages/react-devtools-shared/src/__tests__/profilingCache-test.js
+12
@@ -39,6 +39,7 @@ describe('ProfilingCache', () => {
39 Scheduler = require('scheduler');
40 });
41
42 + // @reactVersion >= 16.9
43 it('should collect data for each root (including ones added or mounted after profiling started)', () => {
44 const Parent = ({count}) => {
45 Scheduler.unstable_advanceTime(10);
@@ -150,6 +151,7 @@ describe('ProfilingCache', () => {
151 });
152 });
153
154 + // @reactVersion >= 16.9
155 it('should collect data for each commit', () => {
156 const Parent = ({count}) => {
157 Scheduler.unstable_advanceTime(10);
@@ -194,6 +196,7 @@ describe('ProfilingCache', () => {
196 });
197 });
198
199 + // @reactVersion >= 16.9
200 it('should record changed props/state/context/hooks', () => {
201 let instance = null;
202
@@ -512,6 +515,7 @@ describe('ProfilingCache', () => {
515 }
516 });
517
518 + // @reactVersion >= 18.0
519 it('should properly detect changed hooks', () => {
520 const Context = React.createContext(0);
521
@@ -730,6 +734,7 @@ describe('ProfilingCache', () => {
734 }
735 });
736
737 + // @reactVersion >= 16.9
738 it('should calculate durations based on actual children (not filtered children)', () => {
739 store.componentFilters = [utils.createDisplayNameFilter('^Parent$')];
740
@@ -788,6 +793,7 @@ describe('ProfilingCache', () => {
793 `);
794 });
795
796 + // @reactVersion >= 17.0
797 it('should calculate durations correctly for suspended views', async () => {
798 let data;
799 const getData = () => {
@@ -857,6 +863,7 @@ describe('ProfilingCache', () => {
863 `);
864 });
865
866 + // @reactVersion >= 16.9
867 it('should collect data for each rendered fiber', () => {
868 const Parent = ({count}) => {
869 Scheduler.unstable_advanceTime(10);
@@ -934,6 +941,7 @@ describe('ProfilingCache', () => {
941 }
942 });
943
944 + // @reactVersion >= 18.0
945 it('should handle unexpectedly shallow suspense trees', () => {
946 const container = document.createElement('div');
947
@@ -975,6 +983,7 @@ describe('ProfilingCache', () => {
983 });
984
985 // See https://github.com/facebook/react/issues/18831
986 + // @reactVersion >= 16.9
987 it('should not crash during route transitions with Suspense', () => {
988 const RouterContext = React.createContext();
989
@@ -1063,6 +1072,7 @@ describe('ProfilingCache', () => {
1072 expect(container.textContent).toBe('About');
1073 });
1074
1075 + // @reactVersion >= 18.0
1076 it('components that were deleted and added to updaters during the layout phase should not crash', () => {
1077 let setChildUnmounted;
1078 function Child() {
@@ -1093,6 +1103,7 @@ describe('ProfilingCache', () => {
1103 expect(updaters[0].displayName).toEqual('App');
1104 });
1105
1106 + // @reactVersion >= 18.0
1107 it('components in a deleted subtree and added to updaters during the layout phase should not crash', () => {
1108 let setChildUnmounted;
1109 function Child() {
@@ -1127,6 +1138,7 @@ describe('ProfilingCache', () => {
1138 expect(updaters[0].displayName).toEqual('App');
1139 });
1140
1141 + // @reactVersion >= 18.0
1142 it('components that were deleted should not be added to updaters during the passive phase', () => {
1143 let setChildUnmounted;
1144 function Child() {
packages/react-devtools-shared/src/__tests__/profilingCharts-test.js
+2
@@ -59,6 +59,7 @@ describe('profiling charts', () => {
59 }
60
61 describe('flamegraph chart', () => {
62 + // @reactVersion >= 16.9
63 it('should contain valid data', () => {
64 const Parent = (_: {||}) => {
65 Scheduler.unstable_advanceTime(10);
@@ -208,6 +209,7 @@ describe('profiling charts', () => {
209 });
210
211 describe('ranked chart', () => {
212 + // @reactVersion >= 16.9
213 it('should contain valid data', () => {
214 const Parent = (_: {||}) => {
215 Scheduler.unstable_advanceTime(10);
packages/react-devtools-shared/src/__tests__/profilingCommitTreeBuilder-test.js
+5
@@ -32,6 +32,7 @@ describe('commit tree', () => {
32 Scheduler = require('scheduler');
33 });
34
35 + // @reactVersion >= 16.9
36 it('should be able to rebuild the store tree for each commit', () => {
37 const Parent = ({count}) => {
38 Scheduler.unstable_advanceTime(10);
@@ -116,6 +117,7 @@ describe('commit tree', () => {
117 LazyComponent = React.lazy(() => fakeImport(LazyInnerComponent));
118 });
119
120 + // @reactVersion >= 16.9
121 it('should support Lazy components (legacy render)', async () => {
122 const container = document.createElement('div');
123
@@ -157,6 +159,7 @@ describe('commit tree', () => {
159 expect(commitTrees[2].nodes.size).toBe(2); // <Root> + <App>
160 });
161
162 + // @reactVersion >= 18.0
163 it('should support Lazy components (createRoot)', async () => {
164 const container = document.createElement('div');
165 const root = ReactDOMClient.createRoot(container);
@@ -199,6 +202,7 @@ describe('commit tree', () => {
202 expect(commitTrees[2].nodes.size).toBe(2); // <Root> + <App>
203 });
204
205 + // @reactVersion >= 16.9
206 it('should support Lazy components that are unmounted before resolving (legacy render)', async () => {
207 const container = document.createElement('div');
208
@@ -231,6 +235,7 @@ describe('commit tree', () => {
235 expect(commitTrees[1].nodes.size).toBe(2); // <Root> + <App>
236 });
237
238 + // @reactVersion >= 18.0
239 it('should support Lazy components that are unmounted before resolving (createRoot)', async () => {
240 const container = document.createElement('div');
241 const root = ReactDOMClient.createRoot(container);
packages/react-devtools-shared/src/__tests__/profilingHostRoot-test.js
+3
@@ -49,6 +49,7 @@ describe('profiling HostRoot', () => {
49 };
50 });
51
52 + // @reactVersion >=18.0
53 it('should expose passive and layout effect durations for render()', () => {
54 function App() {
55 React.useEffect(() => {
@@ -77,6 +78,7 @@ describe('profiling HostRoot', () => {
78 );
79 });
80
81 + // @reactVersion >=18.0
82 it('should expose passive and layout effect durations for createRoot()', () => {
83 function App() {
84 React.useEffect(() => {
@@ -106,6 +108,7 @@ describe('profiling HostRoot', () => {
108 );
109 });
110
111 + // @reactVersion >=18.0
112 it('should properly reset passive and layout effect durations between commits', () => {
113 function App({shouldCascade}) {
114 const [, setState] = React.useState(false);
packages/react-devtools-shared/src/__tests__/store-test.js
+39
@@ -35,6 +35,7 @@ describe('Store', () => {
35 withErrorsOrWarningsIgnored = utils.withErrorsOrWarningsIgnored;
36 });
37
38 + // @reactVersion >= 18.0
39 it('should not allow a root node to be collapsed', () => {
40 const Component = () => <div>Hi</div>;
41
@@ -55,6 +56,7 @@ describe('Store', () => {
56 );
57 });
58
59 + // @reactVersion >= 18.0
60 it('should properly handle a root with no visible nodes', () => {
61 const Root = ({children}) => children;
62
@@ -75,6 +77,7 @@ describe('Store', () => {
77 // Thec ase below is admittedly contrived and relies on side effects.
78 // I'mnot yet sure of how to reduce the GitHub reported production case to a test though.
79 // See https://github.com/facebook/react/issues/21445
80 + // @reactVersion >= 18.0
81 it('should handle when a component mounts before its owner', () => {
82 const promise = new Promise(resolve => {});
83
@@ -109,6 +112,7 @@ describe('Store', () => {
112 `);
113 });
114
115 + // @reactVersion >= 18.0
116 it('should handle multibyte character strings', () => {
117 const Component = () => null;
118 Component.displayName = '🟩💜🔵';
@@ -139,6 +143,7 @@ describe('Store', () => {
143 expect(store.getElementAtIndex(1).isStrictModeNonCompliant).toBe(false);
144 });
145
146 + // @reactVersion >= 18.0
147 it('should mark non strict root elements as not strict', () => {
148 const App = () => <Component />;
149 const Component = () => null;
@@ -177,6 +182,7 @@ describe('Store', () => {
182 store.collapseNodesByDefault = false;
183 });
184
185 + // @reactVersion >= 18.0
186 it('should support mount and update operations', () => {
187 const Grandparent = ({count}) => (
188 <React.Fragment>
@@ -222,6 +228,7 @@ describe('Store', () => {
228 expect(store).toMatchInlineSnapshot(``);
229 });
230
231 + // @reactVersion >= 18.0
232 it('should support mount and update operations for multiple roots', () => {
233 const Parent = ({count}) =>
234 new Array(count).fill(true).map((_, index) => <Child key={index} />);
@@ -276,6 +283,7 @@ describe('Store', () => {
283 expect(store).toMatchInlineSnapshot(``);
284 });
285
286 + // @reactVersion >= 18.0
287 it('should filter DOM nodes from the store tree', () => {
288 const Grandparent = () => (
289 <div>
@@ -305,6 +313,7 @@ describe('Store', () => {
313 `);
314 });
315
316 + // @reactVersion >= 18.0
317 it('should display Suspense nodes properly in various states', () => {
318 const Loading = () => <div>Loading...</div>;
319 const SuspendingComponent = () => {
@@ -348,6 +357,7 @@ describe('Store', () => {
357 `);
358 });
359
360 + // @reactVersion >= 18.0
361 it('should support nested Suspense nodes', () => {
362 const Component = () => null;
363 const Loading = () => <div>Loading...</div>;
@@ -719,6 +729,7 @@ describe('Store', () => {
729 `);
730 });
731
732 + // @reactVersion >= 18.0
733 it('should support collapsing parts of the tree', () => {
734 const Grandparent = ({count}) => (
735 <React.Fragment>
@@ -793,6 +804,7 @@ describe('Store', () => {
804 `);
805 });
806
807 + // @reactVersion >= 18.0
808 it('should support reordering of children', () => {
809 const Root = ({children}) => children;
810 const Component = () => null;
@@ -850,6 +862,7 @@ describe('Store', () => {
862 store.collapseNodesByDefault = true;
863 });
864
865 + // @reactVersion >= 18.0
866 it('should support mount and update operations', () => {
867 const Parent = ({count}) =>
868 new Array(count).fill(true).map((_, index) => <Child key={index} />);
@@ -891,6 +904,7 @@ describe('Store', () => {
904 expect(store).toMatchInlineSnapshot(``);
905 });
906
907 + // @reactVersion >= 18.0
908 it('should support mount and update operations for multiple roots', () => {
909 const Parent = ({count}) =>
910 new Array(count).fill(true).map((_, index) => <Child key={index} />);
@@ -931,6 +945,7 @@ describe('Store', () => {
945 expect(store).toMatchInlineSnapshot(``);
946 });
947
948 + // @reactVersion >= 18.0
949 it('should filter DOM nodes from the store tree', () => {
950 const Grandparent = () => (
951 <div>
@@ -973,6 +988,7 @@ describe('Store', () => {
988 `);
989 });
990
991 + // @reactVersion >= 18.0
992 it('should display Suspense nodes properly in various states', () => {
993 const Loading = () => <div>Loading...</div>;
994 const SuspendingComponent = () => {
@@ -1024,6 +1040,7 @@ describe('Store', () => {
1040 `);
1041 });
1042
1043 + // @reactVersion >= 18.0
1044 it('should support expanding parts of the tree', () => {
1045 const Grandparent = ({count}) => (
1046 <React.Fragment>
@@ -1103,6 +1120,7 @@ describe('Store', () => {
1120 `);
1121 });
1122
1123 + // @reactVersion >= 18.0
1124 it('should support expanding deep parts of the tree', () => {
1125 const Wrapper = ({forwardedRef}) => (
1126 <Nested depth={3} forwardedRef={forwardedRef} />
@@ -1177,6 +1195,7 @@ describe('Store', () => {
1195 `);
1196 });
1197
1198 + // @reactVersion >= 18.0
1199 it('should support reordering of children', () => {
1200 const Root = ({children}) => children;
1201 const Component = () => null;
@@ -1229,6 +1248,7 @@ describe('Store', () => {
1248 `);
1249 });
1250
1251 + // @reactVersion >= 18.0
1252 it('should not add new nodes when suspense is toggled', () => {
1253 const SuspenseTree = () => {
1254 return (
@@ -1295,6 +1315,7 @@ describe('Store', () => {
1315 store.collapseNodesByDefault = false;
1316 });
1317
1318 + // @reactVersion >= 18.0
1319 it('should support a single root with a single child', () => {
1320 const Grandparent = () => (
1321 <React.Fragment>
@@ -1312,6 +1333,7 @@ describe('Store', () => {
1333 }
1334 });
1335
1336 + // @reactVersion >= 18.0
1337 it('should support multiple roots with one children each', () => {
1338 const Grandparent = () => <Parent />;
1339 const Parent = () => <Child />;
@@ -1327,6 +1349,7 @@ describe('Store', () => {
1349 }
1350 });
1351
1352 + // @reactVersion >= 18.0
1353 it('should support a single root with multiple top level children', () => {
1354 const Grandparent = () => <Parent />;
1355 const Parent = () => <Child />;
@@ -1347,6 +1370,7 @@ describe('Store', () => {
1370 }
1371 });
1372
1373 + // @reactVersion >= 18.0
1374 it('should support multiple roots with multiple top level children', () => {
1375 const Grandparent = () => <Parent />;
1376 const Parent = () => <Child />;
@@ -1375,6 +1399,7 @@ describe('Store', () => {
1399 });
1400 });
1401
1402 + // @reactVersion >= 18.0
1403 it('detects and updates profiling support based on the attached roots', () => {
1404 const Component = () => null;
1405
@@ -1394,6 +1419,7 @@ describe('Store', () => {
1419 expect(store.rootSupportsBasicProfiling).toBe(false);
1420 });
1421
1422 + // @reactVersion >= 18.0
1423 it('should properly serialize non-string key values', () => {
1424 const Child = () => null;
1425
@@ -1516,6 +1542,7 @@ describe('Store', () => {
1542 LazyComponent = React.lazy(() => fakeImport(LazyInnerComponent));
1543 });
1544
1545 + // @reactVersion >= 18.0
1546 it('should support Lazy components (legacy render)', async () => {
1547 const container = document.createElement('div');
1548
@@ -1549,6 +1576,7 @@ describe('Store', () => {
1576 `);
1577 });
1578
1579 + // @reactVersion >= 18.0
1580 it('should support Lazy components in (createRoot)', async () => {
1581 const container = document.createElement('div');
1582 const root = ReactDOMClient.createRoot(container);
@@ -1583,6 +1611,7 @@ describe('Store', () => {
1611 `);
1612 });
1613
1614 + // @reactVersion >= 18.0
1615 it('should support Lazy components that are unmounted before they finish loading (legacy render)', async () => {
1616 const container = document.createElement('div');
1617
@@ -1604,6 +1633,7 @@ describe('Store', () => {
1633 `);
1634 });
1635
1636 + // @reactVersion >= 18.0
1637 it('should support Lazy components that are unmounted before they finish loading in (createRoot)', async () => {
1638 const container = document.createElement('div');
1639 const root = ReactDOMClient.createRoot(container);
@@ -1628,6 +1658,7 @@ describe('Store', () => {
1658 });
1659
1660 describe('inline errors and warnings', () => {
1661 + // @reactVersion >= 18.0
1662 it('during render are counted', () => {
1663 function Example() {
1664 console.error('test-only: render error');
@@ -1657,6 +1688,7 @@ describe('Store', () => {
1688 `);
1689 });
1690
1691 + // @reactVersion >= 18.0
1692 it('during layout get counted', () => {
1693 function Example() {
1694 React.useLayoutEffect(() => {
@@ -1698,6 +1730,7 @@ describe('Store', () => {
1730 jest.advanceTimersByTime(1000);
1731 }
1732
1733 + // @reactVersion >= 18.0
1734 it('are counted (after a delay)', () => {
1735 function Example() {
1736 React.useEffect(() => {
@@ -1731,6 +1764,7 @@ describe('Store', () => {
1764 expect(store).toMatchInlineSnapshot(``);
1765 });
1766
1767 + // @reactVersion >= 18.0
1768 it('are flushed early when there is a new commit', () => {
1769 function Example() {
1770 React.useEffect(() => {
@@ -1794,6 +1828,7 @@ describe('Store', () => {
1828 });
1829 });
1830
1831 + // @reactVersion >= 18.0
1832 it('from react get counted', () => {
1833 const container = document.createElement('div');
1834 function Example() {
@@ -1818,6 +1853,7 @@ describe('Store', () => {
1853 `);
1854 });
1855
1856 + // @reactVersion >= 18.0
1857 it('can be cleared for the whole app', () => {
1858 function Example() {
1859 console.error('test-only: render error');
@@ -1859,6 +1895,7 @@ describe('Store', () => {
1895 `);
1896 });
1897
1898 + // @reactVersion >= 18.0
1899 it('can be cleared for particular Fiber (only warnings)', () => {
1900 function Example() {
1901 console.error('test-only: render error');
@@ -1904,6 +1941,7 @@ describe('Store', () => {
1941 `);
1942 });
1943
1944 + // @reactVersion >= 18.0
1945 it('can be cleared for a particular Fiber (only errors)', () => {
1946 function Example() {
1947 console.error('test-only: render error');
@@ -1949,6 +1987,7 @@ describe('Store', () => {
1987 `);
1988 });
1989
1990 + // @reactVersion >= 18.0
1991 it('are updated when fibers are removed from the tree', () => {
1992 function ComponentWithWarning() {
1993 console.warn('test-only: render warning');
packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js
+9
@@ -41,6 +41,7 @@ describe('Store component filters', () => {
41 legacyRender = utils.legacyRender;
42 });
43
44 + // @reactVersion >= 16.0
45 it('should throw if filters are updated while profiling', () => {
46 act(() => store.profilerStore.startProfiling());
47 expect(() => (store.componentFilters = [])).toThrow(
@@ -48,6 +49,7 @@ describe('Store component filters', () => {
49 );
50 });
51
52 + // @reactVersion >= 16.0
53 it('should support filtering by element type', () => {
54 class ClassComponent extends React.Component<{|children: React$Node|}> {
55 render() {
@@ -135,6 +137,7 @@ describe('Store component filters', () => {
137 `);
138 });
139
140 + // @reactVersion >= 16.0
141 it('should ignore invalid ElementTypeRoot filter', () => {
142 const Component = () => <div>Hi</div>;
143
@@ -159,6 +162,7 @@ describe('Store component filters', () => {
162 `);
163 });
164
165 + // @reactVersion >= 16.2
166 it('should filter by display name', () => {
167 const Text = ({label}) => label;
168 const Foo = () => <Text label="foo" />;
@@ -219,6 +223,7 @@ describe('Store component filters', () => {
223 `);
224 });
225
226 + // @reactVersion >= 16.0
227 it('should filter by path', () => {
228 const Component = () => <div>Hi</div>;
229
@@ -252,6 +257,7 @@ describe('Store component filters', () => {
257 `);
258 });
259
260 + // @reactVersion >= 16.0
261 it('should filter HOCs', () => {
262 const Component = () => <div>Hi</div>;
263 const Foo = () => <Component />;
@@ -285,6 +291,7 @@ describe('Store component filters', () => {
291 `);
292 });
293
294 + // @reactVersion >= 16.0
295 it('should not send a bridge update if the set of enabled filters has not changed', () => {
296 act(() => (store.componentFilters = [utils.createHOCFilter(true)]));
297
@@ -315,6 +322,7 @@ describe('Store component filters', () => {
322 );
323 });
324
325 + // @reactVersion >= 18.0
326 it('should not break when Suspense nodes are filtered from the tree', () => {
327 const promise = new Promise(() => {});
328
@@ -363,6 +371,7 @@ describe('Store component filters', () => {
371 });
372
373 describe('inline errors and warnings', () => {
374 + // @reactVersion >= 17.0
375 it('only counts for unfiltered components', () => {
376 function ComponentWithWarning() {
377 console.warn('test-only: render warning');
packages/react-devtools-shared/src/__tests__/storeStressSync-test.js
+4
@@ -33,6 +33,7 @@ describe('StoreStress (Legacy Mode)', () => {
33
34 // This is a stress test for the tree mount/update/unmount traversal.
35 // It renders different trees that should produce the same output.
36 + // @reactVersion >= 16.9
37 it('should handle a stress test with different tree operations (Legacy Mode)', () => {
38 let setShowX;
39 const A = () => 'a';
@@ -174,6 +175,7 @@ describe('StoreStress (Legacy Mode)', () => {
175 expect(print(store)).toBe('');
176 });
177
178 + // @reactVersion >= 16.9
179 it('should handle stress test with reordering (Legacy Mode)', () => {
180 const A = () => 'a';
181 const B = () => 'b';
@@ -274,6 +276,7 @@ describe('StoreStress (Legacy Mode)', () => {
276 }
277 });
278
279 + // @reactVersion >= 18.0
280 it('should handle a stress test for Suspense (Legacy Mode)', async () => {
281 const A = () => 'a';
282 const B = () => 'b';
@@ -667,6 +670,7 @@ describe('StoreStress (Legacy Mode)', () => {
670 }
671 });
672
673 + // @reactVersion >= 18.0
674 it('should handle a stress test for Suspense without type change (Legacy Mode)', () => {
675 const A = () => 'a';
676 const B = () => 'b';
packages/react-devtools-shared/src/__tests__/storeStressTestConcurrent-test.js
+4
@@ -39,6 +39,7 @@ describe('StoreStressConcurrent', () => {
39
40 // This is a stress test for the tree mount/update/unmount traversal.
41 // It renders different trees that should produce the same output.
42 + // @reactVersion >= 18.0
43 it('should handle a stress test with different tree operations (Concurrent Mode)', () => {
44 let setShowX;
45 const A = () => 'a';
@@ -207,6 +208,7 @@ describe('StoreStressConcurrent', () => {
208 expect(print(store)).toBe('');
209 });
210
211 + // @reactVersion >= 18.0
212 it('should handle stress test with reordering (Concurrent Mode)', () => {
213 const A = () => 'a';
214 const B = () => 'b';
@@ -368,6 +370,7 @@ describe('StoreStressConcurrent', () => {
370 }
371 });
372
373 + // @reactVersion >= 18.0
374 it('should handle a stress test for Suspense (Concurrent Mode)', async () => {
375 const A = () => 'a';
376 const B = () => 'b';
@@ -841,6 +844,7 @@ describe('StoreStressConcurrent', () => {
844 }
845 });
846
847 + // @reactVersion >= 18.0
848 it('should handle a stress test for Suspense without type change (Concurrent Mode)', async () => {
849 const A = () => 'a';
850 const B = () => 'b';
packages/react-devtools-shared/src/__tests__/utils-test.js
+23
@@ -23,27 +23,32 @@ import {createElement} from 'react/src/ReactElement';
23
24 describe('utils', () => {
25 describe('getDisplayName', () => {
26 + // @reactVersion >= 16.0
27 it('should return a function name', () => {
28 function FauxComponent() {}
29 expect(getDisplayName(FauxComponent)).toEqual('FauxComponent');
30 });
31
32 + // @reactVersion >= 16.0
33 it('should return a displayName name if specified', () => {
34 function FauxComponent() {}
35 FauxComponent.displayName = 'OverrideDisplayName';
36 expect(getDisplayName(FauxComponent)).toEqual('OverrideDisplayName');
37 });
38
39 + // @reactVersion >= 16.0
40 it('should return the fallback for anonymous functions', () => {
41 expect(getDisplayName(() => {}, 'Fallback')).toEqual('Fallback');
42 });
43
44 + // @reactVersion >= 16.0
45 it('should return Anonymous for anonymous functions without a fallback', () => {
46 expect(getDisplayName(() => {})).toEqual('Anonymous');
47 });
48
49 // Simulate a reported bug:
50 // https://github.com/facebook/react/issues/16685
51 + // @reactVersion >= 16.0
52 it('should return a fallback when the name prop is not a string', () => {
53 const FauxComponent = {name: {}};
54 expect(getDisplayName(FauxComponent, 'Fallback')).toEqual('Fallback');
@@ -51,6 +56,7 @@ describe('utils', () => {
56 });
57
58 describe('getDisplayNameForReactElement', () => {
59 + // @reactVersion >= 16.0
60 it('should return correct display name for an element with function type', () => {
61 function FauxComponent() {}
62 FauxComponent.displayName = 'OverrideDisplayName';
@@ -60,16 +66,19 @@ describe('utils', () => {
66 );
67 });
68
69 + // @reactVersion >= 16.0
70 it('should return correct display name for an element with a type of StrictMode', () => {
71 const element = createElement(StrictMode);
72 expect(getDisplayNameForReactElement(element)).toEqual('StrictMode');
73 });
74
75 + // @reactVersion >= 16.0
76 it('should return correct display name for an element with a type of SuspenseList', () => {
77 const element = createElement(SuspenseList);
78 expect(getDisplayNameForReactElement(element)).toEqual('SuspenseList');
79 });
80
81 + // @reactVersion >= 16.0
82 it('should return NotImplementedInDevtools for an element with invalid symbol type', () => {
83 const element = createElement(Symbol('foo'));
84 expect(getDisplayNameForReactElement(element)).toEqual(
@@ -77,6 +86,7 @@ describe('utils', () => {
86 );
87 });
88
89 + // @reactVersion >= 16.0
90 it('should return NotImplementedInDevtools for an element with invalid type', () => {
91 const element = createElement(true);
92 expect(getDisplayNameForReactElement(element)).toEqual(
@@ -84,6 +94,7 @@ describe('utils', () => {
94 );
95 });
96
97 + // @reactVersion >= 16.0
98 it('should return Element for null type', () => {
99 const element = createElement();
100 expect(getDisplayNameForReactElement(element)).toEqual('Element');
@@ -91,42 +102,50 @@ describe('utils', () => {
102 });
103
104 describe('format', () => {
105 + // @reactVersion >= 16.0
106 it('should format simple strings', () => {
107 expect(format('a', 'b', 'c')).toEqual('a b c');
108 });
109
110 + // @reactVersion >= 16.0
111 it('should format multiple argument types', () => {
112 expect(format('abc', 123, true)).toEqual('abc 123 true');
113 });
114
115 + // @reactVersion >= 16.0
116 it('should support string substitutions', () => {
117 expect(format('a %s b %s c', 123, true)).toEqual('a 123 b true c');
118 });
119
120 + // @reactVersion >= 16.0
121 it('should gracefully handle Symbol types', () => {
122 expect(format(Symbol('a'), 'b', Symbol('c'))).toEqual(
123 'Symbol(a) b Symbol(c)',
124 );
125 });
126
127 + // @reactVersion >= 16.0
128 it('should gracefully handle Symbol type for the first argument', () => {
129 expect(format(Symbol('abc'), 123)).toEqual('Symbol(abc) 123');
130 });
131 });
132
133 describe('formatWithStyles', () => {
134 + // @reactVersion >= 16.0
135 it('should format empty arrays', () => {
136 expect(formatWithStyles([])).toEqual([]);
137 expect(formatWithStyles([], 'gray')).toEqual([]);
138 expect(formatWithStyles(undefined)).toEqual(undefined);
139 });
140
141 + // @reactVersion >= 16.0
142 it('should bail out of strings with styles', () => {
143 expect(
144 formatWithStyles(['%ca', 'color: green', 'b', 'c'], 'color: gray'),
145 ).toEqual(['%ca', 'color: green', 'b', 'c']);
146 });
147
148 + // @reactVersion >= 16.0
149 it('should format simple strings', () => {
150 expect(formatWithStyles(['a'])).toEqual(['a']);
151
@@ -145,6 +164,7 @@ describe('utils', () => {
164 ]);
165 });
166
167 + // @reactVersion >= 16.0
168 it('should format string substituions', () => {
169 expect(
170 formatWithStyles(['%s %s %s', 'a', 'b', 'c'], 'color: gray'),
@@ -157,6 +177,7 @@ describe('utils', () => {
177 ).toEqual(['%c%s %s', 'color: gray', 'a', 'b', 'c']);
178 });
179
180 + // @reactVersion >= 16.0
181 it('should support multiple argument types', () => {
182 const symbol = Symbol('a');
183 expect(
@@ -176,6 +197,7 @@ describe('utils', () => {
197 ]);
198 });
199
200 + // @reactVersion >= 16.0
201 it('should properly format escaped string substituions', () => {
202 expect(formatWithStyles(['%%s'], 'color: gray')).toEqual([
203 '%c%s',
@@ -190,6 +212,7 @@ describe('utils', () => {
212 expect(formatWithStyles(['%%c%c'], 'color: gray')).toEqual(['%%c%c']);
213 });
214
215 + // @reactVersion >= 16.0
216 it('should format non string inputs as the first argument', () => {
217 expect(formatWithStyles([{foo: 'bar'}])).toEqual([{foo: 'bar'}]);
218 expect(formatWithStyles([[1, 2, 3]])).toEqual([[1, 2, 3]]);