[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]]);