Remove usage of ReactDOMFeatureFlags.useFiber, assuming true (#10796)
Dan Abramov committed
Sep 27, 2017 at 17:14 UTC
a947d3f92fba61ba9107861dde9e4ea89ad87442
33 files changed
+2699
-3643
src/isomorphic/children/__tests__/ReactChildren-test.js
+35
-39
@@ -9,8 +9,6 @@
9
10
'use strict';
11
12
-const ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
13
-
12
describe('ReactChildren', () => {
13
var React;
14
var ReactTestUtils;
@@ -878,52 +876,50 @@ describe('ReactChildren', () => {
876
);
877
});
878
881
- if (ReactDOMFeatureFlags.useFiber) {
882
- describe('with fragments enabled', () => {
883
- it('warns for keys for arrays of elements in a fragment', () => {
884
- spyOn(console, 'error');
885
- class ComponentReturningArray extends React.Component {
886
- render() {
887
- return [<div />, <div />];
888
- }
879
+ describe('with fragments enabled', () => {
880
+ it('warns for keys for arrays of elements in a fragment', () => {
881
+ spyOn(console, 'error');
882
+ class ComponentReturningArray extends React.Component {
883
+ render() {
884
+ return [<div />, <div />];
885
}
886
+ }
887
891
- ReactTestUtils.renderIntoDocument(<ComponentReturningArray />);
888
+ ReactTestUtils.renderIntoDocument(<ComponentReturningArray />);
889
893
- expectDev(console.error.calls.count()).toBe(1);
894
- expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
895
- 'Warning: ' +
896
- 'Each child in an array or iterator should have a unique "key" prop.' +
897
- ' See https://fb.me/react-warning-keys for more information.' +
898
- '\n in ComponentReturningArray (at **)',
899
- );
900
- });
890
+ expectDev(console.error.calls.count()).toBe(1);
891
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
892
+ 'Warning: ' +
893
+ 'Each child in an array or iterator should have a unique "key" prop.' +
894
+ ' See https://fb.me/react-warning-keys for more information.' +
895
+ '\n in ComponentReturningArray (at **)',
896
+ );
897
+ });
898
902
- it('does not warn when there are keys on elements in a fragment', () => {
903
- spyOn(console, 'error');
904
- class ComponentReturningArray extends React.Component {
905
- render() {
906
- return [<div key="foo" />, <div key="bar" />];
907
- }
899
+ it('does not warn when there are keys on elements in a fragment', () => {
900
+ spyOn(console, 'error');
901
+ class ComponentReturningArray extends React.Component {
902
+ render() {
903
+ return [<div key="foo" />, <div key="bar" />];
904
}
905
+ }
906
910
- ReactTestUtils.renderIntoDocument(<ComponentReturningArray />);
907
+ ReactTestUtils.renderIntoDocument(<ComponentReturningArray />);
908
912
- expectDev(console.error.calls.count()).toBe(0);
913
- });
909
+ expectDev(console.error.calls.count()).toBe(0);
910
+ });
911
915
- it('warns for keys for arrays at the top level', () => {
916
- spyOn(console, 'error');
912
+ it('warns for keys for arrays at the top level', () => {
913
+ spyOn(console, 'error');
914
918
- ReactTestUtils.renderIntoDocument([<div />, <div />]);
915
+ ReactTestUtils.renderIntoDocument([<div />, <div />]);
916
920
- expectDev(console.error.calls.count()).toBe(1);
921
- expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
922
- 'Warning: ' +
923
- 'Each child in an array or iterator should have a unique "key" prop.' +
924
- ' See https://fb.me/react-warning-keys for more information.',
925
- );
926
- });
917
+ expectDev(console.error.calls.count()).toBe(1);
918
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
919
+ 'Warning: ' +
920
+ 'Each child in an array or iterator should have a unique "key" prop.' +
921
+ ' See https://fb.me/react-warning-keys for more information.',
922
+ );
923
});
928
- }
924
+ });
925
});
src/isomorphic/classic/element/__tests__/ReactElement-test.js
+1
-8
@@ -12,7 +12,6 @@
12
var React;
13
var ReactDOM;
14
var ReactTestUtils;
15
-var ReactDOMFeatureFlags;
15
16
describe('ReactElement', () => {
17
var ComponentClass;
@@ -29,7 +28,6 @@ describe('ReactElement', () => {
28
React = require('react');
29
ReactDOM = require('react-dom');
30
ReactTestUtils = require('react-dom/test-utils');
32
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
31
// NOTE: We're explicitly not using JSX here. This is intended to test
32
// classic JS without JSX.
33
ComponentClass = class extends React.Component {
@@ -235,12 +233,7 @@ describe('ReactElement', () => {
233
var instance = ReactTestUtils.renderIntoDocument(
234
React.createElement(Wrapper),
235
);
238
-
239
- if (ReactDOMFeatureFlags.useFiber) {
240
- expect(element._owner.stateNode).toBe(instance);
241
- } else {
242
- expect(element._owner.getPublicInstance()).toBe(instance);
243
- }
236
+ expect(element._owner.stateNode).toBe(instance);
237
});
238
239
it('merges an additional argument onto the children prop', () => {
src/renderers/__tests__/EventPluginHub-test.js
+4
-10
@@ -14,13 +14,11 @@ jest.mock('isEventSupported');
14
describe('EventPluginHub', () => {
15
var React;
16
var ReactTestUtils;
17
- var ReactDOMFeatureFlags;
17
18
beforeEach(() => {
19
jest.resetModules();
20
React = require('react');
21
ReactTestUtils = require('react-dom/test-utils');
23
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
22
});
23
24
it('should prevent non-function listeners, at dispatch', () => {
@@ -33,14 +31,10 @@ describe('EventPluginHub', () => {
31
}).toThrowError(
32
'Expected `onClick` listener to be a function, instead got a value of `string` type.',
33
);
36
- if (ReactDOMFeatureFlags.useFiber) {
37
- expectDev(console.error.calls.count()).toBe(1);
38
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
39
- 'Expected `onClick` listener to be a function, instead got a value of `string` type.',
40
- );
41
- } else {
42
- expectDev(console.error.calls.count()).toBe(0);
43
- }
34
+ expectDev(console.error.calls.count()).toBe(1);
35
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
36
+ 'Expected `onClick` listener to be a function, instead got a value of `string` type.',
37
+ );
38
});
39
40
it('should not prevent null listeners, at dispatch', () => {
src/renderers/__tests__/ReactComponent-test.js
+71
-89
@@ -14,8 +14,6 @@ var ReactDOM;
14
var ReactDOMServer;
15
var ReactTestUtils;
16
17
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
18
-
17
describe('ReactComponent', () => {
18
function normalizeCodeLocInfo(str) {
19
return str && str.replace(/\(at .+?:\d+\)/g, '(at **)');
@@ -297,21 +295,11 @@ describe('ReactComponent', () => {
295
'outer componentDidMount',
296
'start update',
297
// Previous (equivalent) refs get cleared
300
- ...(ReactDOMFeatureFlags.useFiber
301
- ? [
302
- // Fiber renders first, resets refs later
303
- 'inner 1 render',
304
- 'inner 2 render',
305
- 'ref 1 got null',
306
- 'ref 2 got null',
307
- ]
308
- : [
309
- // Stack resets refs before rendering
310
- 'ref 1 got null',
311
- 'inner 1 render',
312
- 'ref 2 got null',
313
- 'inner 2 render',
314
- ]),
298
+ // Fiber renders first, resets refs later
299
+ 'inner 1 render',
300
+ 'inner 2 render',
301
+ 'ref 1 got null',
302
+ 'ref 2 got null',
303
'inner 1 componentDidUpdate',
304
'ref 1 got instance 1',
305
'inner 2 componentDidUpdate',
@@ -406,8 +394,7 @@ describe('ReactComponent', () => {
394
'Objects are not valid as a React child (found: object with keys ' +
395
'{x, y, z}). If you meant to render a collection of children, use ' +
396
'an array instead.' +
409
- // Fiber gives a slightly better stack with the nearest host components
410
- (ReactDOMFeatureFlags.useFiber ? '\n in div (at **)' : ''),
397
+ '\n in div (at **)',
398
);
399
});
400
@@ -434,8 +421,7 @@ describe('ReactComponent', () => {
421
'Objects are not valid as a React child (found: object with keys ' +
422
'{a, b, c}). If you meant to render a collection of children, use ' +
423
'an array instead.\n' +
437
- // Fiber gives a slightly better stack with the nearest host components
438
- (ReactDOMFeatureFlags.useFiber ? ' in div (at **)\n' : '') +
424
+ ' in div (at **)\n' +
425
' in Foo (at **)',
426
);
427
});
@@ -458,8 +444,7 @@ describe('ReactComponent', () => {
444
'Objects are not valid as a React child (found: object with keys ' +
445
'{x, y, z}). If you meant to render a collection of children, use ' +
446
'an array instead.' +
461
- // Fiber gives a slightly better stack with the nearest host components
462
- (ReactDOMFeatureFlags.useFiber ? '\n in div (at **)' : ''),
447
+ '\n in div (at **)',
448
);
449
});
450
@@ -486,79 +471,76 @@ describe('ReactComponent', () => {
471
'Objects are not valid as a React child (found: object with keys ' +
472
'{a, b, c}). If you meant to render a collection of children, use ' +
473
'an array instead.\n' +
489
- // Fiber gives a slightly better stack with the nearest host components
490
- (ReactDOMFeatureFlags.useFiber ? ' in div (at **)\n' : '') +
474
+ ' in div (at **)\n' +
475
' in Foo (at **)',
476
);
477
});
478
495
- if (ReactDOMFeatureFlags.useFiber) {
496
- describe('with new features', () => {
497
- it('warns on function as a return value from a function', () => {
498
- function Foo() {
499
- return Foo;
500
- }
501
- spyOn(console, 'error');
502
- var container = document.createElement('div');
503
- ReactDOM.render(<Foo />, container);
504
- expectDev(console.error.calls.count()).toBe(1);
505
- expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
506
- 'Warning: Functions are not valid as a React child. This may happen if ' +
507
- 'you return a Component instead of <Component /> from render. ' +
508
- 'Or maybe you meant to call this function rather than return it.\n' +
509
- ' in Foo (at **)',
510
- );
511
- });
479
+ describe('with new features', () => {
480
+ it('warns on function as a return value from a function', () => {
481
+ function Foo() {
482
+ return Foo;
483
+ }
484
+ spyOn(console, 'error');
485
+ var container = document.createElement('div');
486
+ ReactDOM.render(<Foo />, container);
487
+ expectDev(console.error.calls.count()).toBe(1);
488
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
489
+ 'Warning: Functions are not valid as a React child. This may happen if ' +
490
+ 'you return a Component instead of <Component /> from render. ' +
491
+ 'Or maybe you meant to call this function rather than return it.\n' +
492
+ ' in Foo (at **)',
493
+ );
494
+ });
495
513
- it('warns on function as a return value from a class', () => {
514
- class Foo extends React.Component {
515
- render() {
516
- return Foo;
517
- }
496
+ it('warns on function as a return value from a class', () => {
497
+ class Foo extends React.Component {
498
+ render() {
499
+ return Foo;
500
}
519
- spyOn(console, 'error');
520
- var container = document.createElement('div');
521
- ReactDOM.render(<Foo />, container);
522
- expectDev(console.error.calls.count()).toBe(1);
523
- expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
524
- 'Warning: Functions are not valid as a React child. This may happen if ' +
525
- 'you return a Component instead of <Component /> from render. ' +
526
- 'Or maybe you meant to call this function rather than return it.\n' +
527
- ' in Foo (at **)',
528
- );
529
- });
501
+ }
502
+ spyOn(console, 'error');
503
+ var container = document.createElement('div');
504
+ ReactDOM.render(<Foo />, container);
505
+ expectDev(console.error.calls.count()).toBe(1);
506
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
507
+ 'Warning: Functions are not valid as a React child. This may happen if ' +
508
+ 'you return a Component instead of <Component /> from render. ' +
509
+ 'Or maybe you meant to call this function rather than return it.\n' +
510
+ ' in Foo (at **)',
511
+ );
512
+ });
513
531
- it('warns on function as a child to host component', () => {
532
- function Foo() {
533
- return <div><span>{Foo}</span></div>;
534
- }
535
- spyOn(console, 'error');
536
- var container = document.createElement('div');
537
- ReactDOM.render(<Foo />, container);
538
- expectDev(console.error.calls.count()).toBe(1);
539
- expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
540
- 'Warning: Functions are not valid as a React child. This may happen if ' +
541
- 'you return a Component instead of <Component /> from render. ' +
542
- 'Or maybe you meant to call this function rather than return it.\n' +
543
- ' in span (at **)\n' +
544
- ' in div (at **)\n' +
545
- ' in Foo (at **)',
546
- );
547
- });
514
+ it('warns on function as a child to host component', () => {
515
+ function Foo() {
516
+ return <div><span>{Foo}</span></div>;
517
+ }
518
+ spyOn(console, 'error');
519
+ var container = document.createElement('div');
520
+ ReactDOM.render(<Foo />, container);
521
+ expectDev(console.error.calls.count()).toBe(1);
522
+ expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
523
+ 'Warning: Functions are not valid as a React child. This may happen if ' +
524
+ 'you return a Component instead of <Component /> from render. ' +
525
+ 'Or maybe you meant to call this function rather than return it.\n' +
526
+ ' in span (at **)\n' +
527
+ ' in div (at **)\n' +
528
+ ' in Foo (at **)',
529
+ );
530
+ });
531
549
- it('does not warn for function-as-a-child that gets resolved', () => {
550
- function Bar(props) {
551
- return props.children();
552
- }
553
- function Foo() {
554
- return <Bar>{() => 'Hello'}</Bar>;
555
- }
556
- spyOn(console, 'error');
557
- var container = document.createElement('div');
558
- ReactDOM.render(<Foo />, container);
559
- expect(container.innerHTML).toBe('Hello');
560
- expectDev(console.error.calls.count()).toBe(0);
561
- });
532
+ it('does not warn for function-as-a-child that gets resolved', () => {
533
+ function Bar(props) {
534
+ return props.children();
535
+ }
536
+ function Foo() {
537
+ return <Bar>{() => 'Hello'}</Bar>;
538
+ }
539
+ spyOn(console, 'error');
540
+ var container = document.createElement('div');
541
+ ReactDOM.render(<Foo />, container);
542
+ expect(container.innerHTML).toBe('Hello');
543
+ expectDev(console.error.calls.count()).toBe(0);
544
});
563
- }
545
+ });
546
});
src/renderers/__tests__/ReactComponentTreeHook-test.js
+7
-76
@@ -9,13 +9,9 @@
9
10
'use strict';
11
12
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
13
-var describeStack = ReactDOMFeatureFlags.useFiber ? describe.skip : describe;
14
-
15
-describe('ReactComponentTreeHook', () => {
12
+describe.skip('ReactComponentTreeHook', () => {
13
var React;
14
var ReactDOM;
18
- var ReactDOMServer;
15
var ReactInstanceMap;
16
var ReactComponentTreeHook;
17
var ReactDebugCurrentFiber;
@@ -26,7 +22,6 @@ describe('ReactComponentTreeHook', () => {
22
23
React = require('react');
24
ReactDOM = require('react-dom');
29
- ReactDOMServer = require('react-dom/server');
25
ReactInstanceMap = require('ReactInstanceMap');
26
ReactDebugCurrentFiber = require('ReactDebugCurrentFiber');
27
ReactComponentTreeHook = require('ReactComponentTreeHook');
@@ -37,9 +32,8 @@ describe('ReactComponentTreeHook', () => {
32
describe('stack addenda', () => {
33
it('gets created', () => {
34
function getAddendum(element) {
40
- var addendum = ReactDOMFeatureFlags.useFiber
41
- ? ReactDebugCurrentFiber.getCurrentFiberStackAddendum() || ''
42
- : ReactComponentTreeHook.getCurrentStackAddendum();
35
+ var addendum =
36
+ ReactDebugCurrentFiber.getCurrentFiberStackAddendum() || '';
37
return addendum.replace(/\(at .+?:\d+\)/g, '(at **)');
38
}
39
@@ -107,68 +101,6 @@ describe('ReactComponentTreeHook', () => {
101
// Make sure owner is fetched for the top element too.
102
// expectDev(getAddendum(rOwnedByQ)).toBe('\n in R (created by Q)');
103
});
110
-
111
- // These are features and regression tests that only affect
112
- // the Stack implementation of the stack addendum.
113
- if (!ReactDOMFeatureFlags.useFiber) {
114
- it('can be retrieved by ID', () => {
115
- function getAddendum(id) {
116
- var addendum = ReactComponentTreeHook.getStackAddendumByID(id);
117
- return addendum.replace(/\(at .+?:\d+\)/g, '(at **)');
118
- }
119
-
120
- class Q extends React.Component {
121
- render() {
122
- return null;
123
- }
124
- }
125
-
126
- var q = ReactDOM.render(<Q />, document.createElement('div'));
127
- expectDev(getAddendum(ReactInstanceMap.get(q)._debugID)).toBe(
128
- '\n in Q (at **)',
129
- );
130
-
131
- spyOn(console, 'error');
132
- getAddendum(-17);
133
- expectDev(console.error.calls.count()).toBe(1);
134
- expectDev(console.error.calls.argsFor(0)[0]).toBe(
135
- 'Warning: ReactComponentTreeHook: Missing React element for ' +
136
- 'debugID -17 when building stack',
137
- );
138
- });
139
-
140
- it('is created during mounting', () => {
141
- // https://github.com/facebook/react/issues/7187
142
- var el = document.createElement('div');
143
- var portalEl = document.createElement('div');
144
- class Foo extends React.Component {
145
- componentWillMount() {
146
- ReactDOM.render(<div />, portalEl);
147
- }
148
- render() {
149
- return <div><div /></div>;
150
- }
151
- }
152
- ReactDOM.render(<Foo />, el);
153
- });
154
-
155
- it('is created when calling renderToString during render', () => {
156
- // https://github.com/facebook/react/issues/7190
157
- var el = document.createElement('div');
158
- class Foo extends React.Component {
159
- render() {
160
- return (
161
- <div>
162
- <div>
163
- {ReactDOMServer.renderToString(<div />)}
164
- </div>
165
- </div>
166
- );
167
- }
168
- }
169
- ReactDOM.render(<Foo />, el);
170
- });
171
- }
104
});
105
106
// The rest of this file is not relevant for Fiber.
@@ -227,7 +159,7 @@ describe('ReactComponentTreeHook', () => {
159
expectWrapperTreeToEqual(null);
160
}
161
230
- describeStack('mount', () => {
162
+ describe('mount', () => {
163
it('uses displayName or Unknown for classic components', () => {
164
class Foo extends React.Component {
165
render() {
@@ -699,7 +631,7 @@ describe('ReactComponentTreeHook', () => {
631
});
632
});
633
702
- describeStack('update', () => {
634
+ describe('update', () => {
635
describe('host component', () => {
636
it('updates text of a single text child', () => {
637
var elementBefore = <div>Hi.</div>;
@@ -1919,7 +1851,7 @@ describe('ReactComponentTreeHook', () => {
1851
});
1852
});
1853
1922
- describeStack('misc', () => {
1854
+ describe('misc', () => {
1855
it('tracks owner correctly', () => {
1856
class Foo extends React.Component {
1857
render() {
@@ -2089,7 +2021,7 @@ describe('ReactComponentTreeHook', () => {
2021
});
2022
});
2023
2092
- describeStack('in environment without Map, Set and Array.from', () => {
2024
+ describe('in environment without Map, Set and Array.from', () => {
2025
var realMap;
2026
var realSet;
2027
var realArrayFrom;
@@ -2107,7 +2039,6 @@ describe('ReactComponentTreeHook', () => {
2039
2040
React = require('react');
2041
ReactDOM = require('react-dom');
2110
- ReactDOMServer = require('react-dom/server');
2042
ReactInstanceMap = require('ReactInstanceMap');
2043
ReactComponentTreeHook = require('ReactComponentTreeHook');
2044
ReactComponentTreeTestUtils = require('ReactComponentTreeTestUtils');
src/renderers/__tests__/ReactCompositeComponent-test.js
+10
-18
@@ -13,7 +13,6 @@ var ChildUpdates;
13
var MorphingComponent;
14
var React;
15
var ReactDOM;
16
-var ReactDOMFeatureFlags;
16
var ReactDOMServer;
17
var ReactCurrentOwner;
18
var ReactTestUtils;
@@ -26,7 +25,6 @@ describe('ReactCompositeComponent', () => {
25
jest.resetModules();
26
React = require('react');
27
ReactDOM = require('react-dom');
29
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
28
ReactDOMServer = require('react-dom/server');
29
ReactCurrentOwner = require('react')
30
.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner;
@@ -123,25 +121,19 @@ describe('ReactCompositeComponent', () => {
121
var container = document.createElement('div');
122
container.innerHTML = markup;
123
ReactDOM.render(<Parent />, container);
126
- if (ReactDOMFeatureFlags.useFiber) {
127
- expectDev(console.warn.calls.count()).toBe(1);
128
- expectDev(console.warn.calls.argsFor(0)[0]).toContain(
129
- 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
130
- 'will stop working in React v17. Replace the ReactDOM.render() call ' +
131
- 'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
132
- );
133
- } else {
134
- expectDev(console.warn.calls.count()).toBe(0);
135
- }
124
+ expectDev(console.warn.calls.count()).toBe(1);
125
+ expectDev(console.warn.calls.argsFor(0)[0]).toContain(
126
+ 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
127
+ 'will stop working in React v17. Replace the ReactDOM.render() call ' +
128
+ 'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
129
+ );
130
131
// New explicit API
132
console.warn.calls.reset();
139
- if (ReactDOMFeatureFlags.useFiber) {
140
- container = document.createElement('div');
141
- container.innerHTML = markup;
142
- ReactDOM.hydrate(<Parent />, container);
143
- expectDev(console.warn.calls.count()).toBe(0);
144
- }
133
+ container = document.createElement('div');
134
+ container.innerHTML = markup;
135
+ ReactDOM.hydrate(<Parent />, container);
136
+ expectDev(console.warn.calls.count()).toBe(0);
137
});
138
139
it('should react to state changes from callbacks', () => {
src/renderers/__tests__/ReactCompositeComponentState-test.js
+39
-63
@@ -11,7 +11,6 @@
11
12
var React;
13
var ReactDOM;
14
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
14
15
var TestComponent;
16
@@ -179,17 +178,9 @@ describe('ReactCompositeComponent-state', () => {
178
// setState({color:'green'}) only enqueues a pending state.
179
['componentWillReceiveProps-end', 'yellow'],
180
// pending state queue is processed
182
- ];
183
-
184
- if (ReactDOMFeatureFlags.useFiber) {
185
- // In Stack, this is never called because replaceState drops all updates
186
- // from the queue. In Fiber, we keep updates in the queue to support
181
+ // We keep updates in the queue to support
182
// replaceState(prevState => newState).
188
- // TODO: Fix Stack to match Fiber.
189
- expected.push(['before-setState-receiveProps', 'yellow']);
190
- }
191
-
192
- expected.push(
183
+ ['before-setState-receiveProps', 'yellow'],
184
['before-setState-again-receiveProps', undefined],
185
['after-setState-receiveProps', 'green'],
186
['shouldComponentUpdate-currentState', 'yellow'],
@@ -220,7 +211,7 @@ describe('ReactCompositeComponent-state', () => {
211
// unmountComponent()
212
// state is available within `componentWillUnmount()`
213
['componentWillUnmount', 'blue'],
223
- );
214
+ ];
215
216
expect(stateListener.mock.calls.join('\n')).toEqual(expected.join('\n'));
217
});
@@ -289,20 +280,7 @@ describe('ReactCompositeComponent-state', () => {
280
child.setState({bar: false});
281
});
282
// We expect the same thing to happen if we bail out in the middle.
292
- expect(ops).toEqual(
293
- ReactDOMFeatureFlags.useFiber
294
- ? [
295
- // Fiber works as expected
296
- 'child did update',
297
- 'parent did update',
298
- ]
299
- : [
300
- // Stack treats these as two separate updates and therefore the order
301
- // is inverse.
302
- 'parent did update',
303
- 'child did update',
304
- ],
305
- );
283
+ expect(ops).toEqual(['child did update', 'parent did update']);
284
});
285
286
it('should batch unmounts', () => {
@@ -445,45 +423,43 @@ describe('ReactCompositeComponent-state', () => {
423
);
424
});
425
448
- if (ReactDOMFeatureFlags.useFiber) {
449
- it('should treat assigning to this.state inside cWM as a replaceState, with a warning', () => {
450
- spyOn(console, 'error');
451
-
452
- let ops = [];
453
- class Test extends React.Component {
454
- state = {step: 1, extra: true};
455
- componentWillMount() {
456
- this.setState({step: 2}, () => {
457
- // Tests that earlier setState callbacks are not dropped
458
- ops.push(
459
- `callback -- step: ${this.state.step}, extra: ${!!this.state.extra}`,
460
- );
461
- });
462
- // Treat like replaceState
463
- this.state = {step: 3};
464
- }
465
- render() {
426
+ it('should treat assigning to this.state inside cWM as a replaceState, with a warning', () => {
427
+ spyOn(console, 'error');
428
+
429
+ let ops = [];
430
+ class Test extends React.Component {
431
+ state = {step: 1, extra: true};
432
+ componentWillMount() {
433
+ this.setState({step: 2}, () => {
434
+ // Tests that earlier setState callbacks are not dropped
435
ops.push(
467
- `render -- step: ${this.state.step}, extra: ${!!this.state.extra}`,
436
+ `callback -- step: ${this.state.step}, extra: ${!!this.state.extra}`,
437
);
469
- return null;
470
- }
438
+ });
439
+ // Treat like replaceState
440
+ this.state = {step: 3};
441
}
442
+ render() {
443
+ ops.push(
444
+ `render -- step: ${this.state.step}, extra: ${!!this.state.extra}`,
445
+ );
446
+ return null;
447
+ }
448
+ }
449
473
- // Mount
474
- const container = document.createElement('div');
475
- ReactDOM.render(<Test />, container);
476
-
477
- expect(ops).toEqual([
478
- 'render -- step: 3, extra: false',
479
- 'callback -- step: 3, extra: false',
480
- ]);
481
- expect(console.error.calls.count()).toEqual(1);
482
- expect(console.error.calls.argsFor(0)[0]).toEqual(
483
- 'Warning: Test.componentWillMount(): Assigning directly to ' +
484
- "this.state is deprecated (except inside a component's constructor). " +
485
- 'Use setState instead.',
486
- );
487
- });
488
- }
450
+ // Mount
451
+ const container = document.createElement('div');
452
+ ReactDOM.render(<Test />, container);
453
+
454
+ expect(ops).toEqual([
455
+ 'render -- step: 3, extra: false',
456
+ 'callback -- step: 3, extra: false',
457
+ ]);
458
+ expect(console.error.calls.count()).toEqual(1);
459
+ expect(console.error.calls.argsFor(0)[0]).toEqual(
460
+ 'Warning: Test.componentWillMount(): Assigning directly to ' +
461
+ "this.state is deprecated (except inside a component's constructor). " +
462
+ 'Use setState instead.',
463
+ );
464
+ });
465
});
src/renderers/__tests__/ReactEmptyComponent-test.js
+15
-36
@@ -14,8 +14,6 @@ var ReactDOM;
14
var ReactTestUtils;
15
var TogglingComponent;
16
17
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
18
-
17
var log;
18
19
describe('ReactEmptyComponent', () => {
@@ -69,20 +67,18 @@ describe('ReactEmptyComponent', () => {
67
expect(container2.children.length).toBe(0);
68
});
69
72
- if (ReactDOMFeatureFlags.useFiber) {
73
- it('should still throw when rendering to undefined', () => {
74
- class Component extends React.Component {
75
- render() {}
76
- }
70
+ it('should still throw when rendering to undefined', () => {
71
+ class Component extends React.Component {
72
+ render() {}
73
+ }
74
78
- expect(function() {
79
- ReactTestUtils.renderIntoDocument(<Component />);
80
- }).toThrowError(
81
- 'Component(...): Nothing was returned from render. This usually means a return statement is missing. ' +
82
- 'Or, to render nothing, return null.',
83
- );
84
- });
85
- }
75
+ expect(function() {
76
+ ReactTestUtils.renderIntoDocument(<Component />);
77
+ }).toThrowError(
78
+ 'Component(...): Nothing was returned from render. This usually means a return statement is missing. ' +
79
+ 'Or, to render nothing, return null.',
80
+ );
81
+ });
82
83
it('should be able to switch between rendering null and a normal tag', () => {
84
var instance1 = (
@@ -233,15 +229,8 @@ describe('ReactEmptyComponent', () => {
229
230
it('can render null at the top level', () => {
231
var div = document.createElement('div');
236
- if (ReactDOMFeatureFlags.useFiber) {
237
- ReactDOM.render(null, div);
238
- expect(div.innerHTML).toBe('');
239
- } else {
240
- // Stack does not implement this.
241
- expect(function() {
242
- ReactDOM.render(null, div);
243
- }).toThrowError('ReactDOM.render(): Invalid component element.');
244
- }
232
+ ReactDOM.render(null, div);
233
+ expect(div.innerHTML).toBe('');
234
});
235
236
it('does not break when updating during mount', () => {
@@ -293,21 +282,11 @@ describe('ReactEmptyComponent', () => {
282
283
ReactDOM.render(<Empty />, container);
284
var noscript1 = container.firstChild;
296
- if (ReactDOMFeatureFlags.useFiber) {
297
- expect(noscript1).toBe(null);
298
- } else {
299
- expect(noscript1.nodeName).toBe('#comment');
300
- }
285
+ expect(noscript1).toBe(null);
286
287
// This update shouldn't create a DOM node
288
ReactDOM.render(<Empty />, container);
289
var noscript2 = container.firstChild;
305
- if (ReactDOMFeatureFlags.useFiber) {
306
- expect(noscript1).toBe(null);
307
- } else {
308
- expect(noscript2.nodeName).toBe('#comment');
309
- }
310
-
311
- expect(noscript1).toBe(noscript2);
290
+ expect(noscript2).toBe(null);
291
});
292
});
src/renderers/__tests__/ReactErrorBoundaries-test.js
+536
-753
@@ -9,8 +9,6 @@
9
10
'use strict';
11
12
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
13
-
12
var PropTypes;
13
var React;
14
var ReactDOM;
@@ -399,12 +397,7 @@ describe('ReactErrorBoundaries', () => {
397
log.push('NoopErrorBoundary componentWillUnmount');
398
}
399
componentDidCatch() {
402
- if (ReactDOMFeatureFlags.useFiber) {
403
- log.push('NoopErrorBoundary componentDidCatch');
404
- } else {
405
- // In Stack, not calling setState() is treated as a rethrow.
406
- log.push('NoopErrorBoundary componentDidCatch [*]');
407
- }
400
+ log.push('NoopErrorBoundary componentDidCatch');
401
}
402
};
403
@@ -507,14 +500,9 @@ describe('ReactErrorBoundaries', () => {
500
log.push('RetryErrorBoundary componentWillUnmount');
501
}
502
componentDidCatch(error) {
510
- if (ReactDOMFeatureFlags.useFiber) {
511
- log.push('RetryErrorBoundary componentDidCatch [!]');
512
- // In Fiber, calling setState() (and failing) is treated as a rethrow.
513
- this.setState({});
514
- } else {
515
- log.push('RetryErrorBoundary componentDidCatch [*]');
516
- // In Stack, not calling setState() is treated as a rethrow.
517
- }
503
+ log.push('RetryErrorBoundary componentDidCatch [!]');
504
+ // In Fiber, calling setState() (and failing) is treated as a rethrow.
505
+ this.setState({});
506
}
507
};
508
@@ -639,22 +627,13 @@ describe('ReactErrorBoundaries', () => {
627
'BrokenRender constructor',
628
'BrokenRender componentWillMount',
629
'BrokenRender render [!]',
642
- ...(ReactDOMFeatureFlags.useFiber
643
- ? [
644
- // Fiber mounts with null children before capturing error
645
- 'ErrorBoundary componentDidMount',
646
- // Catch and render an error message
647
- 'ErrorBoundary componentDidCatch',
648
- 'ErrorBoundary componentWillUpdate',
649
- 'ErrorBoundary render error',
650
- 'ErrorBoundary componentDidUpdate',
651
- ]
652
- : [
653
- // Catch and render an error message
654
- 'ErrorBoundary componentDidCatch',
655
- 'ErrorBoundary render error',
656
- 'ErrorBoundary componentDidMount',
657
- ]),
630
+ // Fiber mounts with null children before capturing error
631
+ 'ErrorBoundary componentDidMount',
632
+ // Catch and render an error message
633
+ 'ErrorBoundary componentDidCatch',
634
+ 'ErrorBoundary componentWillUpdate',
635
+ 'ErrorBoundary render error',
636
+ 'ErrorBoundary componentDidUpdate',
637
]);
638
639
log.length = 0;
@@ -676,22 +655,13 @@ describe('ReactErrorBoundaries', () => {
655
'ErrorBoundary componentWillMount',
656
'ErrorBoundary render success',
657
'BrokenConstructor constructor [!]',
679
- ...(ReactDOMFeatureFlags.useFiber
680
- ? [
681
- // Fiber mounts with null children before capturing error
682
- 'ErrorBoundary componentDidMount',
683
- // Catch and render an error message
684
- 'ErrorBoundary componentDidCatch',
685
- 'ErrorBoundary componentWillUpdate',
686
- 'ErrorBoundary render error',
687
- 'ErrorBoundary componentDidUpdate',
688
- ]
689
- : [
690
- // Catch and render an error message
691
- 'ErrorBoundary componentDidCatch',
692
- 'ErrorBoundary render error',
693
- 'ErrorBoundary componentDidMount',
694
- ]),
658
+ // Fiber mounts with null children before capturing error
659
+ 'ErrorBoundary componentDidMount',
660
+ // Catch and render an error message
661
+ 'ErrorBoundary componentDidCatch',
662
+ 'ErrorBoundary componentWillUpdate',
663
+ 'ErrorBoundary render error',
664
+ 'ErrorBoundary componentDidUpdate',
665
]);
666
667
log.length = 0;
@@ -714,20 +684,11 @@ describe('ReactErrorBoundaries', () => {
684
'ErrorBoundary render success',
685
'BrokenComponentWillMount constructor',
686
'BrokenComponentWillMount componentWillMount [!]',
717
- ...(ReactDOMFeatureFlags.useFiber
718
- ? [
719
- 'ErrorBoundary componentDidMount',
720
- 'ErrorBoundary componentDidCatch',
721
- 'ErrorBoundary componentWillUpdate',
722
- 'ErrorBoundary render error',
723
- 'ErrorBoundary componentDidUpdate',
724
- ]
725
- : [
726
- // Catch and render an error message
727
- 'ErrorBoundary componentDidCatch',
728
- 'ErrorBoundary render error',
729
- 'ErrorBoundary componentDidMount',
730
- ]),
687
+ 'ErrorBoundary componentDidMount',
688
+ 'ErrorBoundary componentDidCatch',
689
+ 'ErrorBoundary componentWillUpdate',
690
+ 'ErrorBoundary render error',
691
+ 'ErrorBoundary componentDidUpdate',
692
]);
693
694
log.length = 0;
@@ -806,29 +767,15 @@ describe('ReactErrorBoundaries', () => {
767
'BrokenRender constructor',
768
'BrokenRender componentWillMount',
769
'BrokenRender render [!]',
809
- ...(ReactDOMFeatureFlags.useFiber
810
- ? [
811
- 'ErrorBoundary componentDidMount',
812
- 'ErrorBoundary componentDidCatch',
813
- 'ErrorBoundary componentWillUpdate',
814
- 'ErrorBoundary render error',
815
- 'ErrorMessage constructor',
816
- 'ErrorMessage componentWillMount',
817
- 'ErrorMessage render',
818
- 'ErrorMessage componentDidMount',
819
- 'ErrorBoundary componentDidUpdate',
820
- ]
821
- : [
822
- // Handle the error:
823
- 'ErrorBoundary componentDidCatch',
824
- 'ErrorBoundary render error',
825
- // Mount the error message:
826
- 'ErrorMessage constructor',
827
- 'ErrorMessage componentWillMount',
828
- 'ErrorMessage render',
829
- 'ErrorMessage componentDidMount',
830
- 'ErrorBoundary componentDidMount',
831
- ]),
770
+ 'ErrorBoundary componentDidMount',
771
+ 'ErrorBoundary componentDidCatch',
772
+ 'ErrorBoundary componentWillUpdate',
773
+ 'ErrorBoundary render error',
774
+ 'ErrorMessage constructor',
775
+ 'ErrorMessage componentWillMount',
776
+ 'ErrorMessage render',
777
+ 'ErrorMessage componentDidMount',
778
+ 'ErrorBoundary componentDidUpdate',
779
]);
780
781
log.length = 0;
@@ -860,39 +807,22 @@ describe('ReactErrorBoundaries', () => {
807
'BrokenRender constructor',
808
'BrokenRender componentWillMount',
809
'BrokenRender render [!]',
863
- ...(ReactDOMFeatureFlags.useFiber
864
- ? [
865
- // In Fiber, failed error boundaries render null before attempting to recover
866
- 'RetryErrorBoundary componentDidMount',
867
- 'RetryErrorBoundary componentDidCatch [!]',
868
- 'ErrorBoundary componentDidMount',
869
- // Retry
870
- 'RetryErrorBoundary render',
871
- 'BrokenRender constructor',
872
- 'BrokenRender componentWillMount',
873
- 'BrokenRender render [!]',
874
- // This time, the error propagates to the higher boundary
875
- 'RetryErrorBoundary componentWillUnmount',
876
- 'ErrorBoundary componentDidCatch',
877
- // Render the error
878
- 'ErrorBoundary componentWillUpdate',
879
- 'ErrorBoundary render error',
880
- 'ErrorBoundary componentDidUpdate',
881
- ]
882
- : [
883
- // The first error boundary catches the error.
884
- // However, it doesn't adjust its state so next render will also fail.
885
- 'RetryErrorBoundary componentDidCatch [*]',
886
- 'RetryErrorBoundary render',
887
- 'BrokenRender constructor',
888
- 'BrokenRender componentWillMount',
889
- 'BrokenRender render [!]',
890
- // This time, the error propagates to the higher boundary
891
- 'ErrorBoundary componentDidCatch',
892
- // Render the error
893
- 'ErrorBoundary render error',
894
- 'ErrorBoundary componentDidMount',
895
- ]),
810
+ // In Fiber, failed error boundaries render null before attempting to recover
811
+ 'RetryErrorBoundary componentDidMount',
812
+ 'RetryErrorBoundary componentDidCatch [!]',
813
+ 'ErrorBoundary componentDidMount',
814
+ // Retry
815
+ 'RetryErrorBoundary render',
816
+ 'BrokenRender constructor',
817
+ 'BrokenRender componentWillMount',
818
+ 'BrokenRender render [!]',
819
+ // This time, the error propagates to the higher boundary
820
+ 'RetryErrorBoundary componentWillUnmount',
821
+ 'ErrorBoundary componentDidCatch',
822
+ // Render the error
823
+ 'ErrorBoundary componentWillUpdate',
824
+ 'ErrorBoundary render error',
825
+ 'ErrorBoundary componentDidUpdate',
826
]);
827
828
log.length = 0;
@@ -916,20 +846,11 @@ describe('ReactErrorBoundaries', () => {
846
'BrokenComponentWillMountErrorBoundary constructor',
847
'BrokenComponentWillMountErrorBoundary componentWillMount [!]',
848
// The error propagates to the higher boundary
919
- ...(ReactDOMFeatureFlags.useFiber
920
- ? [
921
- 'ErrorBoundary componentDidMount',
922
- 'ErrorBoundary componentDidCatch',
923
- 'ErrorBoundary componentWillUpdate',
924
- 'ErrorBoundary render error',
925
- 'ErrorBoundary componentDidUpdate',
926
- ]
927
- : [
928
- 'ErrorBoundary componentDidCatch',
929
- // Render the error
930
- 'ErrorBoundary render error',
931
- 'ErrorBoundary componentDidMount',
932
- ]),
849
+ 'ErrorBoundary componentDidMount',
850
+ 'ErrorBoundary componentDidCatch',
851
+ 'ErrorBoundary componentWillUpdate',
852
+ 'ErrorBoundary render error',
853
+ 'ErrorBoundary componentDidUpdate',
854
]);
855
856
log.length = 0;
@@ -960,31 +881,19 @@ describe('ReactErrorBoundaries', () => {
881
'BrokenRender render [!]',
882
// The first error boundary catches the error
883
// It adjusts state but throws displaying the message
963
- ...(ReactDOMFeatureFlags.useFiber
964
- ? [
965
- // Finish mounting with null children
966
- 'BrokenRenderErrorBoundary componentDidMount',
967
- // Attempt to handle the error
968
- 'BrokenRenderErrorBoundary componentDidCatch',
969
- 'ErrorBoundary componentDidMount',
970
- 'BrokenRenderErrorBoundary render error [!]',
971
- // Boundary fails with new error, propagate to next boundary
972
- 'BrokenRenderErrorBoundary componentWillUnmount',
973
- // Attempt to handle the error again
974
- 'ErrorBoundary componentDidCatch',
975
- 'ErrorBoundary componentWillUpdate',
976
- 'ErrorBoundary render error',
977
- 'ErrorBoundary componentDidUpdate',
978
- ]
979
- : [
980
- 'BrokenRenderErrorBoundary componentDidCatch',
981
- 'BrokenRenderErrorBoundary render error [!]',
982
- // The error propagates to the higher boundary
983
- 'ErrorBoundary componentDidCatch',
984
- // Render the error
985
- 'ErrorBoundary render error',
986
- 'ErrorBoundary componentDidMount',
987
- ]),
884
+ // Finish mounting with null children
885
+ 'BrokenRenderErrorBoundary componentDidMount',
886
+ // Attempt to handle the error
887
+ 'BrokenRenderErrorBoundary componentDidCatch',
888
+ 'ErrorBoundary componentDidMount',
889
+ 'BrokenRenderErrorBoundary render error [!]',
890
+ // Boundary fails with new error, propagate to next boundary
891
+ 'BrokenRenderErrorBoundary componentWillUnmount',
892
+ // Attempt to handle the error again
893
+ 'ErrorBoundary componentDidCatch',
894
+ 'ErrorBoundary componentWillUpdate',
895
+ 'ErrorBoundary render error',
896
+ 'ErrorBoundary componentDidUpdate',
897
]);
898
899
log.length = 0;
@@ -1015,23 +924,14 @@ describe('ReactErrorBoundaries', () => {
924
'BrokenRender constructor',
925
'BrokenRender componentWillMount',
926
'BrokenRender render [!]',
1018
- ...(ReactDOMFeatureFlags.useFiber
1019
- ? [
1020
- // Finish mounting with null children
1021
- 'ErrorBoundary componentDidMount',
1022
- // Handle the error
1023
- 'ErrorBoundary componentDidCatch',
1024
- // Render the error message
1025
- 'ErrorBoundary componentWillUpdate',
1026
- 'ErrorBoundary render error',
1027
- 'ErrorBoundary componentDidUpdate',
1028
- ]
1029
- : [
1030
- 'ErrorBoundary componentDidCatch',
1031
- // Render the error message
1032
- 'ErrorBoundary render error',
1033
- 'ErrorBoundary componentDidMount',
1034
- ]),
927
+ // Finish mounting with null children
928
+ 'ErrorBoundary componentDidMount',
929
+ // Handle the error
930
+ 'ErrorBoundary componentDidCatch',
931
+ // Render the error message
932
+ 'ErrorBoundary componentWillUpdate',
933
+ 'ErrorBoundary render error',
934
+ 'ErrorBoundary componentDidUpdate',
935
]);
936
937
log.length = 0;
@@ -1064,28 +964,15 @@ describe('ReactErrorBoundaries', () => {
964
'BrokenRender componentWillMount',
965
'BrokenRender render [!]',
966
// Handle error:
1067
- ...(ReactDOMFeatureFlags.useFiber
1068
- ? [
1069
- // Finish mounting with null children
1070
- 'ErrorBoundary componentDidMount',
1071
- // Handle the error
1072
- 'ErrorBoundary componentDidCatch',
1073
- // Render the error message
1074
- 'ErrorBoundary componentWillUpdate',
1075
- 'ErrorBoundary render error',
1076
- 'Error message ref is set to [object HTMLDivElement]',
1077
- 'ErrorBoundary componentDidUpdate',
1078
- ]
1079
- : [
1080
- 'ErrorBoundary componentDidCatch',
1081
- // Stack reconciler resets ref on update, as it doesn't know ref was never set.
1082
- // This is unnecessary, and Fiber doesn't do it:
1083
- 'Child ref is set to null',
1084
- 'ErrorBoundary render error',
1085
- // Ref to error message should get set:
1086
- 'Error message ref is set to [object HTMLDivElement]',
1087
- 'ErrorBoundary componentDidMount',
1088
- ]),
967
+ // Finish mounting with null children
968
+ 'ErrorBoundary componentDidMount',
969
+ // Handle the error
970
+ 'ErrorBoundary componentDidCatch',
971
+ // Render the error message
972
+ 'ErrorBoundary componentWillUpdate',
973
+ 'ErrorBoundary render error',
974
+ 'Error message ref is set to [object HTMLDivElement]',
975
+ 'ErrorBoundary componentDidUpdate',
976
]);
977
978
log.length = 0;
@@ -1149,26 +1036,15 @@ describe('ReactErrorBoundaries', () => {
1036
'Normal2 render',
1037
// BrokenConstructor will abort rendering:
1038
'BrokenConstructor constructor [!]',
1152
- ...(ReactDOMFeatureFlags.useFiber
1153
- ? [
1154
- // Finish updating with null children
1155
- 'Normal componentWillUnmount',
1156
- 'ErrorBoundary componentDidUpdate',
1157
- // Handle the error
1158
- 'ErrorBoundary componentDidCatch',
1159
- // Render the error message
1160
- 'ErrorBoundary componentWillUpdate',
1161
- 'ErrorBoundary render error',
1162
- 'ErrorBoundary componentDidUpdate',
1163
- ]
1164
- : [
1165
- 'ErrorBoundary componentDidCatch',
1166
- // Stack unmounts first, then renders:
1167
- 'Normal componentWillUnmount',
1168
- 'ErrorBoundary render error',
1169
- // Normal2 does not get lifefycle because it was never mounted
1170
- 'ErrorBoundary componentDidUpdate',
1171
- ]),
1039
+ // Finish updating with null children
1040
+ 'Normal componentWillUnmount',
1041
+ 'ErrorBoundary componentDidUpdate',
1042
+ // Handle the error
1043
+ 'ErrorBoundary componentDidCatch',
1044
+ // Render the error message
1045
+ 'ErrorBoundary componentWillUpdate',
1046
+ 'ErrorBoundary render error',
1047
+ 'ErrorBoundary componentDidUpdate',
1048
]);
1049
1050
log.length = 0;
@@ -1209,26 +1085,15 @@ describe('ReactErrorBoundaries', () => {
1085
// BrokenComponentWillMount will abort rendering:
1086
'BrokenComponentWillMount constructor',
1087
'BrokenComponentWillMount componentWillMount [!]',
1212
- ...(ReactDOMFeatureFlags.useFiber
1213
- ? [
1214
- // Finish updating with null children
1215
- 'Normal componentWillUnmount',
1216
- 'ErrorBoundary componentDidUpdate',
1217
- // Handle the error
1218
- 'ErrorBoundary componentDidCatch',
1219
- // Render the error message
1220
- 'ErrorBoundary componentWillUpdate',
1221
- 'ErrorBoundary render error',
1222
- 'ErrorBoundary componentDidUpdate',
1223
- ]
1224
- : [
1225
- 'ErrorBoundary componentDidCatch',
1226
- // Stack unmounts first, then renders:
1227
- 'Normal componentWillUnmount',
1228
- 'ErrorBoundary render error',
1229
- // Normal2 does not get lifefycle because it was never mounted
1230
- 'ErrorBoundary componentDidUpdate',
1231
- ]),
1088
+ // Finish updating with null children
1089
+ 'Normal componentWillUnmount',
1090
+ 'ErrorBoundary componentDidUpdate',
1091
+ // Handle the error
1092
+ 'ErrorBoundary componentDidCatch',
1093
+ // Render the error message
1094
+ 'ErrorBoundary componentWillUpdate',
1095
+ 'ErrorBoundary render error',
1096
+ 'ErrorBoundary componentDidUpdate',
1097
]);
1098
1099
log.length = 0;
@@ -1264,26 +1129,15 @@ describe('ReactErrorBoundaries', () => {
1129
'Normal render',
1130
// BrokenComponentWillReceiveProps will abort rendering:
1131
'BrokenComponentWillReceiveProps componentWillReceiveProps [!]',
1267
- ...(ReactDOMFeatureFlags.useFiber
1268
- ? [
1269
- // Finish updating with null children
1270
- 'Normal componentWillUnmount',
1271
- 'BrokenComponentWillReceiveProps componentWillUnmount',
1272
- 'ErrorBoundary componentDidUpdate',
1273
- // Handle the error
1274
- 'ErrorBoundary componentDidCatch',
1275
- 'ErrorBoundary componentWillUpdate',
1276
- 'ErrorBoundary render error',
1277
- 'ErrorBoundary componentDidUpdate',
1278
- ]
1279
- : [
1280
- 'ErrorBoundary componentDidCatch',
1281
- // Stack unmounts first, then renders:
1282
- 'Normal componentWillUnmount',
1283
- 'BrokenComponentWillReceiveProps componentWillUnmount',
1284
- 'ErrorBoundary render error',
1285
- 'ErrorBoundary componentDidUpdate',
1286
- ]),
1132
+ // Finish updating with null children
1133
+ 'Normal componentWillUnmount',
1134
+ 'BrokenComponentWillReceiveProps componentWillUnmount',
1135
+ 'ErrorBoundary componentDidUpdate',
1136
+ // Handle the error
1137
+ 'ErrorBoundary componentDidCatch',
1138
+ 'ErrorBoundary componentWillUpdate',
1139
+ 'ErrorBoundary render error',
1140
+ 'ErrorBoundary componentDidUpdate',
1141
]);
1142
1143
log.length = 0;
@@ -1320,26 +1174,15 @@ describe('ReactErrorBoundaries', () => {
1174
// BrokenComponentWillUpdate will abort rendering:
1175
'BrokenComponentWillUpdate componentWillReceiveProps',
1176
'BrokenComponentWillUpdate componentWillUpdate [!]',
1323
- ...(ReactDOMFeatureFlags.useFiber
1324
- ? [
1325
- // Finish updating with null children
1326
- 'Normal componentWillUnmount',
1327
- 'BrokenComponentWillUpdate componentWillUnmount',
1328
- 'ErrorBoundary componentDidUpdate',
1329
- // Handle the error
1330
- 'ErrorBoundary componentDidCatch',
1331
- 'ErrorBoundary componentWillUpdate',
1332
- 'ErrorBoundary render error',
1333
- 'ErrorBoundary componentDidUpdate',
1334
- ]
1335
- : [
1336
- 'ErrorBoundary componentDidCatch',
1337
- // Stack unmounts first, then renders:
1338
- 'Normal componentWillUnmount',
1339
- 'BrokenComponentWillUpdate componentWillUnmount',
1340
- 'ErrorBoundary render error',
1341
- 'ErrorBoundary componentDidUpdate',
1342
- ]),
1177
+ // Finish updating with null children
1178
+ 'Normal componentWillUnmount',
1179
+ 'BrokenComponentWillUpdate componentWillUnmount',
1180
+ 'ErrorBoundary componentDidUpdate',
1181
+ // Handle the error
1182
+ 'ErrorBoundary componentDidCatch',
1183
+ 'ErrorBoundary componentWillUpdate',
1184
+ 'ErrorBoundary render error',
1185
+ 'ErrorBoundary componentDidUpdate',
1186
]);
1187
1188
log.length = 0;
@@ -1381,25 +1224,14 @@ describe('ReactErrorBoundaries', () => {
1224
'BrokenRender constructor',
1225
'BrokenRender componentWillMount',
1226
'BrokenRender render [!]',
1384
- ...(ReactDOMFeatureFlags.useFiber
1385
- ? [
1386
- // Finish updating with null children
1387
- 'Normal componentWillUnmount',
1388
- 'ErrorBoundary componentDidUpdate',
1389
- // Handle the error
1390
- 'ErrorBoundary componentDidCatch',
1391
- 'ErrorBoundary componentWillUpdate',
1392
- 'ErrorBoundary render error',
1393
- 'ErrorBoundary componentDidUpdate',
1394
- ]
1395
- : [
1396
- 'ErrorBoundary componentDidCatch',
1397
- // Stack unmounts first, then renders:
1398
- 'Normal componentWillUnmount',
1399
- 'ErrorBoundary render error',
1400
- // Normal2 does not get lifefycle because it was never mounted
1401
- 'ErrorBoundary componentDidUpdate',
1402
- ]),
1227
+ // Finish updating with null children
1228
+ 'Normal componentWillUnmount',
1229
+ 'ErrorBoundary componentDidUpdate',
1230
+ // Handle the error
1231
+ 'ErrorBoundary componentDidCatch',
1232
+ 'ErrorBoundary componentWillUpdate',
1233
+ 'ErrorBoundary render error',
1234
+ 'ErrorBoundary componentDidUpdate',
1235
]);
1236
1237
log.length = 0;
@@ -1451,22 +1283,13 @@ describe('ReactErrorBoundaries', () => {
1283
'BrokenRender constructor',
1284
'BrokenRender componentWillMount',
1285
'BrokenRender render [!]',
1454
- ...(ReactDOMFeatureFlags.useFiber
1455
- ? [
1456
- // Finish updating with null children
1457
- 'Child1 ref is set to null',
1458
- 'ErrorBoundary componentDidUpdate',
1459
- // Handle the error
1460
- 'ErrorBoundary componentDidCatch',
1461
- 'ErrorBoundary componentWillUpdate',
1462
- 'ErrorBoundary render error',
1463
- ]
1464
- : [
1465
- 'ErrorBoundary componentDidCatch',
1466
- // Stack resets ref first, renders later
1467
- 'Child1 ref is set to null',
1468
- 'ErrorBoundary render error',
1469
- ]),
1286
+ // Finish updating with null children
1287
+ 'Child1 ref is set to null',
1288
+ 'ErrorBoundary componentDidUpdate',
1289
+ // Handle the error
1290
+ 'ErrorBoundary componentDidCatch',
1291
+ 'ErrorBoundary componentWillUpdate',
1292
+ 'ErrorBoundary render error',
1293
'Error message ref is set to [object HTMLDivElement]',
1294
// Child2 ref is never set because its mounting aborted
1295
'ErrorBoundary componentDidUpdate',
@@ -1509,35 +1332,22 @@ describe('ReactErrorBoundaries', () => {
1332
'BrokenComponentWillUnmount render',
1333
// Unmounting throws:
1334
'BrokenComponentWillUnmount componentWillUnmount [!]',
1512
- ...(ReactDOMFeatureFlags.useFiber
1513
- ? [
1514
- // Fiber proceeds with lifecycles despite errors
1515
- 'Normal componentWillUnmount',
1516
- // The components have updated in this phase
1517
- 'BrokenComponentWillUnmount componentDidUpdate',
1518
- 'ErrorBoundary componentDidUpdate',
1519
- // Now that commit phase is done, Fiber unmounts the boundary's children
1520
- 'BrokenComponentWillUnmount componentWillUnmount [!]',
1521
- 'ErrorBoundary componentDidCatch',
1522
- // The initial render was aborted, so
1523
- // Fiber retries from the root.
1524
- 'ErrorBoundary componentWillUpdate',
1525
- // Render an error now (stack will do it later)
1526
- 'ErrorBoundary render error',
1527
- // Attempt to unmount previous child:
1528
- // Done
1529
- 'ErrorBoundary componentDidUpdate',
1530
- ]
1531
- : [
1532
- // Stack will handle error immediately
1533
- 'ErrorBoundary componentDidCatch',
1534
- // Attempt to unmount previous children:
1535
- 'BrokenComponentWillUnmount componentWillUnmount [!]',
1536
- 'Normal componentWillUnmount',
1537
- // Render an error now (Fiber will do it earlier)
1538
- 'ErrorBoundary render error',
1539
- 'ErrorBoundary componentDidUpdate',
1540
- ]),
1335
+ // Fiber proceeds with lifecycles despite errors
1336
+ 'Normal componentWillUnmount',
1337
+ // The components have updated in this phase
1338
+ 'BrokenComponentWillUnmount componentDidUpdate',
1339
+ 'ErrorBoundary componentDidUpdate',
1340
+ // Now that commit phase is done, Fiber unmounts the boundary's children
1341
+ 'BrokenComponentWillUnmount componentWillUnmount [!]',
1342
+ 'ErrorBoundary componentDidCatch',
1343
+ // The initial render was aborted, so
1344
+ // Fiber retries from the root.
1345
+ 'ErrorBoundary componentWillUpdate',
1346
+ // Render an error now (stack will do it later)
1347
+ 'ErrorBoundary render error',
1348
+ // Attempt to unmount previous child:
1349
+ // Done
1350
+ 'ErrorBoundary componentDidUpdate',
1351
]);
1352
1353
log.length = 0;
@@ -1580,33 +1390,21 @@ describe('ReactErrorBoundaries', () => {
1390
'BrokenComponentWillUnmount render',
1391
// Unmounting throws:
1392
'BrokenComponentWillUnmount componentWillUnmount [!]',
1583
- ...(ReactDOMFeatureFlags.useFiber
1584
- ? [
1585
- // Fiber proceeds with lifecycles despite errors
1586
- 'BrokenComponentWillUnmount componentDidUpdate',
1587
- 'Normal componentDidUpdate',
1588
- 'ErrorBoundary componentDidUpdate',
1589
- 'Normal componentWillUnmount',
1590
- 'BrokenComponentWillUnmount componentWillUnmount [!]',
1591
- // Now that commit phase is done, Fiber handles errors
1592
- 'ErrorBoundary componentDidCatch',
1593
- // The initial render was aborted, so
1594
- // Fiber retries from the root.
1595
- 'ErrorBoundary componentWillUpdate',
1596
- // Render an error now (stack will do it later)
1597
- 'ErrorBoundary render error',
1598
- // Done
1599
- 'ErrorBoundary componentDidUpdate',
1600
- ]
1601
- : [
1602
- 'ErrorBoundary componentDidCatch',
1603
- // Attempt to unmount previous children:
1604
- 'Normal componentWillUnmount',
1605
- 'BrokenComponentWillUnmount componentWillUnmount [!]',
1606
- // Stack calls lifecycles first, then renders.
1607
- 'ErrorBoundary render error',
1608
- 'ErrorBoundary componentDidUpdate',
1609
- ]),
1393
+ // Fiber proceeds with lifecycles despite errors
1394
+ 'BrokenComponentWillUnmount componentDidUpdate',
1395
+ 'Normal componentDidUpdate',
1396
+ 'ErrorBoundary componentDidUpdate',
1397
+ 'Normal componentWillUnmount',
1398
+ 'BrokenComponentWillUnmount componentWillUnmount [!]',
1399
+ // Now that commit phase is done, Fiber handles errors
1400
+ 'ErrorBoundary componentDidCatch',
1401
+ // The initial render was aborted, so
1402
+ // Fiber retries from the root.
1403
+ 'ErrorBoundary componentWillUpdate',
1404
+ // Render an error now (stack will do it later)
1405
+ 'ErrorBoundary render error',
1406
+ // Done
1407
+ 'ErrorBoundary componentDidUpdate',
1408
]);
1409
1410
log.length = 0;
@@ -1660,31 +1458,19 @@ describe('ReactErrorBoundaries', () => {
1458
'InnerErrorBoundary render success',
1459
// Try unmounting child
1460
'BrokenComponentWillUnmount componentWillUnmount [!]',
1663
- ...(ReactDOMFeatureFlags.useFiber
1664
- ? [
1665
- // Fiber proceeds with lifecycles despite errors
1666
- // Inner and outer boundaries have updated in this phase
1667
- 'InnerErrorBoundary componentDidUpdate',
1668
- 'OuterErrorBoundary componentDidUpdate',
1669
- // Now that commit phase is done, Fiber handles errors
1670
- // Only inner boundary receives the error:
1671
- 'InnerErrorBoundary componentDidCatch',
1672
- 'InnerErrorBoundary componentWillUpdate',
1673
- // Render an error now
1674
- 'InnerErrorBoundary render error',
1675
- // In Fiber, this was a local update to the
1676
- // inner boundary so only its hook fires
1677
- 'InnerErrorBoundary componentDidUpdate',
1678
- ]
1679
- : [
1680
- // Stack will handle error immediately
1681
- 'InnerErrorBoundary componentDidCatch',
1682
- 'InnerErrorBoundary render error',
1683
- // In stack, this was a part of the update to the
1684
- // outer boundary so both lifecycles fire
1685
- 'InnerErrorBoundary componentDidUpdate',
1686
- 'OuterErrorBoundary componentDidUpdate',
1687
- ]),
1461
+ // Fiber proceeds with lifecycles despite errors
1462
+ // Inner and outer boundaries have updated in this phase
1463
+ 'InnerErrorBoundary componentDidUpdate',
1464
+ 'OuterErrorBoundary componentDidUpdate',
1465
+ // Now that commit phase is done, Fiber handles errors
1466
+ // Only inner boundary receives the error:
1467
+ 'InnerErrorBoundary componentDidCatch',
1468
+ 'InnerErrorBoundary componentWillUpdate',
1469
+ // Render an error now
1470
+ 'InnerErrorBoundary render error',
1471
+ // In Fiber, this was a local update to the
1472
+ // inner boundary so only its hook fires
1473
+ 'InnerErrorBoundary componentDidUpdate',
1474
]);
1475
1476
log.length = 0;
@@ -1856,374 +1642,371 @@ describe('ReactErrorBoundaries', () => {
1642
expect(log).toEqual(['ErrorBoundary componentWillUnmount']);
1643
});
1644
1859
- // The tests below implement new features in Fiber.
1860
- if (ReactDOMFeatureFlags.useFiber) {
1861
- it('catches errors originating downstream', () => {
1862
- var fail = false;
1863
- class Stateful extends React.Component {
1864
- state = {shouldThrow: false};
1645
+ it('catches errors originating downstream', () => {
1646
+ var fail = false;
1647
+ class Stateful extends React.Component {
1648
+ state = {shouldThrow: false};
1649
1866
- render() {
1867
- if (fail) {
1868
- log.push('Stateful render [!]');
1869
- throw new Error('Hello');
1870
- }
1871
- return <div>{this.props.children}</div>;
1650
+ render() {
1651
+ if (fail) {
1652
+ log.push('Stateful render [!]');
1653
+ throw new Error('Hello');
1654
}
1655
+ return <div>{this.props.children}</div>;
1656
}
1657
+ }
1658
1875
- var statefulInst;
1876
- var container = document.createElement('div');
1877
- ReactDOM.render(
1878
- <ErrorBoundary>
1879
- <Stateful ref={inst => (statefulInst = inst)} />
1880
- </ErrorBoundary>,
1881
- container,
1882
- );
1883
-
1884
- log.length = 0;
1885
- expect(() => {
1886
- fail = true;
1887
- statefulInst.forceUpdate();
1888
- }).not.toThrow();
1889
-
1890
- expect(log).toEqual([
1891
- 'Stateful render [!]',
1892
- 'ErrorBoundary componentDidCatch',
1893
- 'ErrorBoundary componentWillUpdate',
1894
- 'ErrorBoundary render error',
1895
- 'ErrorBoundary componentDidUpdate',
1896
- ]);
1897
-
1898
- log.length = 0;
1899
- ReactDOM.unmountComponentAtNode(container);
1900
- expect(log).toEqual(['ErrorBoundary componentWillUnmount']);
1901
- });
1902
-
1903
- it('catches errors in componentDidMount', () => {
1904
- var container = document.createElement('div');
1905
- ReactDOM.render(
1906
- <ErrorBoundary>
1907
- <BrokenComponentWillUnmount>
1908
- <Normal />
1909
- </BrokenComponentWillUnmount>
1910
- <BrokenComponentDidMount />
1911
- <Normal logName="LastChild" />
1912
- </ErrorBoundary>,
1913
- container,
1914
- );
1915
- expect(log).toEqual([
1916
- 'ErrorBoundary constructor',
1917
- 'ErrorBoundary componentWillMount',
1918
- 'ErrorBoundary render success',
1919
- 'BrokenComponentWillUnmount constructor',
1920
- 'BrokenComponentWillUnmount componentWillMount',
1921
- 'BrokenComponentWillUnmount render',
1922
- 'Normal constructor',
1923
- 'Normal componentWillMount',
1924
- 'Normal render',
1925
- 'BrokenComponentDidMount constructor',
1926
- 'BrokenComponentDidMount componentWillMount',
1927
- 'BrokenComponentDidMount render',
1928
- 'LastChild constructor',
1929
- 'LastChild componentWillMount',
1930
- 'LastChild render',
1931
- // Start flushing didMount queue
1932
- 'Normal componentDidMount',
1933
- 'BrokenComponentWillUnmount componentDidMount',
1934
- 'BrokenComponentDidMount componentDidMount [!]',
1935
- // Continue despite the error
1936
- 'LastChild componentDidMount',
1937
- 'ErrorBoundary componentDidMount',
1938
- // Now we are ready to handle the error
1939
- // Safely unmount every child
1940
- 'BrokenComponentWillUnmount componentWillUnmount [!]',
1941
- // Continue unmounting safely despite any errors
1942
- 'Normal componentWillUnmount',
1943
- 'BrokenComponentDidMount componentWillUnmount',
1944
- 'LastChild componentWillUnmount',
1945
- // Handle the error
1946
- 'ErrorBoundary componentDidCatch',
1947
- 'ErrorBoundary componentWillUpdate',
1948
- 'ErrorBoundary render error',
1949
- // The update has finished
1950
- 'ErrorBoundary componentDidUpdate',
1951
- ]);
1952
-
1953
- log.length = 0;
1954
- ReactDOM.unmountComponentAtNode(container);
1955
- expect(log).toEqual(['ErrorBoundary componentWillUnmount']);
1956
- });
1957
-
1958
- it('catches errors in componentDidUpdate', () => {
1959
- var container = document.createElement('div');
1960
- ReactDOM.render(
1961
- <ErrorBoundary>
1962
- <BrokenComponentDidUpdate />
1963
- </ErrorBoundary>,
1964
- container,
1965
- );
1966
-
1967
- log.length = 0;
1968
- ReactDOM.render(
1969
- <ErrorBoundary>
1970
- <BrokenComponentDidUpdate />
1971
- </ErrorBoundary>,
1972
- container,
1973
- );
1974
- expect(log).toEqual([
1975
- 'ErrorBoundary componentWillReceiveProps',
1976
- 'ErrorBoundary componentWillUpdate',
1977
- 'ErrorBoundary render success',
1978
- 'BrokenComponentDidUpdate componentWillReceiveProps',
1979
- 'BrokenComponentDidUpdate componentWillUpdate',
1980
- 'BrokenComponentDidUpdate render',
1981
- // All lifecycles run
1982
- 'BrokenComponentDidUpdate componentDidUpdate [!]',
1983
- 'ErrorBoundary componentDidUpdate',
1984
- 'BrokenComponentDidUpdate componentWillUnmount',
1985
- // Then, error is handled
1986
- 'ErrorBoundary componentDidCatch',
1987
- 'ErrorBoundary componentWillUpdate',
1988
- 'ErrorBoundary render error',
1989
- 'ErrorBoundary componentDidUpdate',
1990
- ]);
1991
-
1992
- log.length = 0;
1993
- ReactDOM.unmountComponentAtNode(container);
1994
- expect(log).toEqual(['ErrorBoundary componentWillUnmount']);
1995
- });
1996
-
1997
- it('propagates errors inside boundary during componentDidMount', () => {
1998
- var container = document.createElement('div');
1999
- ReactDOM.render(
2000
- <ErrorBoundary>
2001
- <BrokenComponentDidMountErrorBoundary
2002
- renderError={error => (
2003
- <div>
2004
- We should never catch our own error: {error.message}.
2005
- </div>
2006
- )}
2007
- />
2008
- </ErrorBoundary>,
2009
- container,
2010
- );
2011
- expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
2012
- expect(log).toEqual([
2013
- 'ErrorBoundary constructor',
2014
- 'ErrorBoundary componentWillMount',
2015
- 'ErrorBoundary render success',
2016
- 'BrokenComponentDidMountErrorBoundary constructor',
2017
- 'BrokenComponentDidMountErrorBoundary componentWillMount',
2018
- 'BrokenComponentDidMountErrorBoundary render success',
2019
- 'BrokenComponentDidMountErrorBoundary componentDidMount [!]',
2020
- // Fiber proceeds with the hooks
2021
- 'ErrorBoundary componentDidMount',
2022
- 'BrokenComponentDidMountErrorBoundary componentWillUnmount',
2023
- // The error propagates to the higher boundary
2024
- 'ErrorBoundary componentDidCatch',
2025
- // Fiber retries from the root
2026
- 'ErrorBoundary componentWillUpdate',
2027
- 'ErrorBoundary render error',
2028
- 'ErrorBoundary componentDidUpdate',
2029
- ]);
2030
-
2031
- log.length = 0;
2032
- ReactDOM.unmountComponentAtNode(container);
2033
- expect(log).toEqual(['ErrorBoundary componentWillUnmount']);
2034
- });
2035
-
2036
- it('lets different boundaries catch their own first errors', () => {
2037
- function renderUnmountError(error) {
2038
- return <div>Caught an unmounting error: {error.message}.</div>;
2039
- }
2040
- function renderUpdateError(error) {
2041
- return <div>Caught an updating error: {error.message}.</div>;
2042
- }
2043
-
2044
- var container = document.createElement('div');
2045
- ReactDOM.render(
2046
- <ErrorBoundary logName="OuterErrorBoundary">
2047
- <ErrorBoundary
2048
- logName="InnerUnmountBoundary"
2049
- renderError={renderUnmountError}>
2050
- <BrokenComponentWillUnmount errorText="E1" />
2051
- <BrokenComponentWillUnmount errorText="E2" />
2052
- </ErrorBoundary>
2053
- <ErrorBoundary
2054
- logName="InnerUpdateBoundary"
2055
- renderError={renderUpdateError}>
2056
- <BrokenComponentDidUpdate errorText="E3" />
2057
- <BrokenComponentDidUpdate errorText="E4" />
2058
- </ErrorBoundary>
2059
- </ErrorBoundary>,
2060
- container,
2061
- );
2062
-
2063
- log.length = 0;
2064
- ReactDOM.render(
2065
- <ErrorBoundary logName="OuterErrorBoundary">
2066
- <ErrorBoundary
2067
- logName="InnerUnmountBoundary"
2068
- renderError={renderUnmountError}
2069
- />
2070
- <ErrorBoundary
2071
- logName="InnerUpdateBoundary"
2072
- renderError={renderUpdateError}>
2073
- <BrokenComponentDidUpdate errorText="E3" />
2074
- <BrokenComponentDidUpdate errorText="E4" />
2075
- </ErrorBoundary>
2076
- </ErrorBoundary>,
2077
- container,
2078
- );
2079
-
2080
- expect(container.firstChild.textContent).toBe(
2081
- 'Caught an unmounting error: E1.' + 'Caught an updating error: E3.',
2082
- );
2083
- expect(log).toEqual([
2084
- // Begin update phase
2085
- 'OuterErrorBoundary componentWillReceiveProps',
2086
- 'OuterErrorBoundary componentWillUpdate',
2087
- 'OuterErrorBoundary render success',
2088
- 'InnerUnmountBoundary componentWillReceiveProps',
2089
- 'InnerUnmountBoundary componentWillUpdate',
2090
- 'InnerUnmountBoundary render success',
2091
- 'InnerUpdateBoundary componentWillReceiveProps',
2092
- 'InnerUpdateBoundary componentWillUpdate',
2093
- 'InnerUpdateBoundary render success',
2094
- // First come the updates
2095
- 'BrokenComponentDidUpdate componentWillReceiveProps',
2096
- 'BrokenComponentDidUpdate componentWillUpdate',
2097
- 'BrokenComponentDidUpdate render',
2098
- 'BrokenComponentDidUpdate componentWillReceiveProps',
2099
- 'BrokenComponentDidUpdate componentWillUpdate',
2100
- 'BrokenComponentDidUpdate render',
2101
- // We're in commit phase now, deleting
2102
- 'BrokenComponentWillUnmount componentWillUnmount [!]',
2103
- 'BrokenComponentWillUnmount componentWillUnmount [!]',
2104
- // Continue despite errors, handle them after commit is done
2105
- 'InnerUnmountBoundary componentDidUpdate',
2106
- // We're still in commit phase, now calling update lifecycles
2107
- 'BrokenComponentDidUpdate componentDidUpdate [!]',
2108
- // Again, continue despite errors, we'll handle them later
2109
- 'BrokenComponentDidUpdate componentDidUpdate [!]',
2110
- 'InnerUpdateBoundary componentDidUpdate',
2111
- 'OuterErrorBoundary componentDidUpdate',
2112
- // After the commit phase, attempt to recover from any errors that
2113
- // were captured
2114
- 'BrokenComponentDidUpdate componentWillUnmount',
2115
- 'BrokenComponentDidUpdate componentWillUnmount',
2116
- 'InnerUnmountBoundary componentDidCatch',
2117
- 'InnerUpdateBoundary componentDidCatch',
2118
- 'InnerUnmountBoundary componentWillUpdate',
2119
- 'InnerUnmountBoundary render error',
2120
- 'InnerUpdateBoundary componentWillUpdate',
2121
- 'InnerUpdateBoundary render error',
2122
- 'InnerUnmountBoundary componentDidUpdate',
2123
- 'InnerUpdateBoundary componentDidUpdate',
2124
- ]);
2125
-
2126
- log.length = 0;
2127
- ReactDOM.unmountComponentAtNode(container);
2128
- expect(log).toEqual([
2129
- 'OuterErrorBoundary componentWillUnmount',
2130
- 'InnerUnmountBoundary componentWillUnmount',
2131
- 'InnerUpdateBoundary componentWillUnmount',
2132
- ]);
2133
- });
2134
-
2135
- it('discards a bad root if the root component fails', () => {
2136
- spyOn(console, 'error');
2137
-
2138
- const X = null;
2139
- const Y = undefined;
2140
- let err1;
2141
- let err2;
2142
-
2143
- try {
2144
- let container = document.createElement('div');
2145
- ReactDOM.render(<X />, container);
2146
- } catch (err) {
2147
- err1 = err;
2148
- }
2149
- try {
2150
- let container = document.createElement('div');
2151
- ReactDOM.render(<Y />, container);
2152
- } catch (err) {
2153
- err2 = err;
2154
- }
2155
-
2156
- expect(err1.message).toMatch(/got: null/);
2157
- expect(err2.message).toMatch(/got: undefined/);
2158
- });
2159
-
2160
- it('renders empty output if error boundary does not handle the error', () => {
2161
- var container = document.createElement('div');
2162
- ReactDOM.render(
2163
- <div>
2164
- Sibling
2165
- <NoopErrorBoundary>
2166
- <BrokenRender />
2167
- </NoopErrorBoundary>
2168
- </div>,
2169
- container,
2170
- );
2171
- expect(container.firstChild.textContent).toBe('Sibling');
2172
- expect(log).toEqual([
2173
- 'NoopErrorBoundary constructor',
2174
- 'NoopErrorBoundary componentWillMount',
2175
- 'NoopErrorBoundary render',
2176
- 'BrokenRender constructor',
2177
- 'BrokenRender componentWillMount',
2178
- 'BrokenRender render [!]',
2179
- // In Fiber, noop error boundaries render null
2180
- 'NoopErrorBoundary componentDidMount',
2181
- 'NoopErrorBoundary componentDidCatch',
2182
- // Nothing happens.
2183
- ]);
2184
-
2185
- log.length = 0;
2186
- ReactDOM.unmountComponentAtNode(container);
2187
- expect(log).toEqual(['NoopErrorBoundary componentWillUnmount']);
2188
- });
1659
+ var statefulInst;
1660
+ var container = document.createElement('div');
1661
+ ReactDOM.render(
1662
+ <ErrorBoundary>
1663
+ <Stateful ref={inst => (statefulInst = inst)} />
1664
+ </ErrorBoundary>,
1665
+ container,
1666
+ );
1667
2190
- it('passes first error when two errors happen in commit', () => {
2191
- const errors = [];
2192
- let caughtError;
2193
- class Parent extends React.Component {
2194
- render() {
2195
- return <Child />;
2196
- }
2197
- componentDidMount() {
2198
- errors.push('parent sad');
2199
- throw new Error('parent sad');
2200
- }
1668
+ log.length = 0;
1669
+ expect(() => {
1670
+ fail = true;
1671
+ statefulInst.forceUpdate();
1672
+ }).not.toThrow();
1673
+
1674
+ expect(log).toEqual([
1675
+ 'Stateful render [!]',
1676
+ 'ErrorBoundary componentDidCatch',
1677
+ 'ErrorBoundary componentWillUpdate',
1678
+ 'ErrorBoundary render error',
1679
+ 'ErrorBoundary componentDidUpdate',
1680
+ ]);
1681
+
1682
+ log.length = 0;
1683
+ ReactDOM.unmountComponentAtNode(container);
1684
+ expect(log).toEqual(['ErrorBoundary componentWillUnmount']);
1685
+ });
1686
+
1687
+ it('catches errors in componentDidMount', () => {
1688
+ var container = document.createElement('div');
1689
+ ReactDOM.render(
1690
+ <ErrorBoundary>
1691
+ <BrokenComponentWillUnmount>
1692
+ <Normal />
1693
+ </BrokenComponentWillUnmount>
1694
+ <BrokenComponentDidMount />
1695
+ <Normal logName="LastChild" />
1696
+ </ErrorBoundary>,
1697
+ container,
1698
+ );
1699
+ expect(log).toEqual([
1700
+ 'ErrorBoundary constructor',
1701
+ 'ErrorBoundary componentWillMount',
1702
+ 'ErrorBoundary render success',
1703
+ 'BrokenComponentWillUnmount constructor',
1704
+ 'BrokenComponentWillUnmount componentWillMount',
1705
+ 'BrokenComponentWillUnmount render',
1706
+ 'Normal constructor',
1707
+ 'Normal componentWillMount',
1708
+ 'Normal render',
1709
+ 'BrokenComponentDidMount constructor',
1710
+ 'BrokenComponentDidMount componentWillMount',
1711
+ 'BrokenComponentDidMount render',
1712
+ 'LastChild constructor',
1713
+ 'LastChild componentWillMount',
1714
+ 'LastChild render',
1715
+ // Start flushing didMount queue
1716
+ 'Normal componentDidMount',
1717
+ 'BrokenComponentWillUnmount componentDidMount',
1718
+ 'BrokenComponentDidMount componentDidMount [!]',
1719
+ // Continue despite the error
1720
+ 'LastChild componentDidMount',
1721
+ 'ErrorBoundary componentDidMount',
1722
+ // Now we are ready to handle the error
1723
+ // Safely unmount every child
1724
+ 'BrokenComponentWillUnmount componentWillUnmount [!]',
1725
+ // Continue unmounting safely despite any errors
1726
+ 'Normal componentWillUnmount',
1727
+ 'BrokenComponentDidMount componentWillUnmount',
1728
+ 'LastChild componentWillUnmount',
1729
+ // Handle the error
1730
+ 'ErrorBoundary componentDidCatch',
1731
+ 'ErrorBoundary componentWillUpdate',
1732
+ 'ErrorBoundary render error',
1733
+ // The update has finished
1734
+ 'ErrorBoundary componentDidUpdate',
1735
+ ]);
1736
+
1737
+ log.length = 0;
1738
+ ReactDOM.unmountComponentAtNode(container);
1739
+ expect(log).toEqual(['ErrorBoundary componentWillUnmount']);
1740
+ });
1741
+
1742
+ it('catches errors in componentDidUpdate', () => {
1743
+ var container = document.createElement('div');
1744
+ ReactDOM.render(
1745
+ <ErrorBoundary>
1746
+ <BrokenComponentDidUpdate />
1747
+ </ErrorBoundary>,
1748
+ container,
1749
+ );
1750
+
1751
+ log.length = 0;
1752
+ ReactDOM.render(
1753
+ <ErrorBoundary>
1754
+ <BrokenComponentDidUpdate />
1755
+ </ErrorBoundary>,
1756
+ container,
1757
+ );
1758
+ expect(log).toEqual([
1759
+ 'ErrorBoundary componentWillReceiveProps',
1760
+ 'ErrorBoundary componentWillUpdate',
1761
+ 'ErrorBoundary render success',
1762
+ 'BrokenComponentDidUpdate componentWillReceiveProps',
1763
+ 'BrokenComponentDidUpdate componentWillUpdate',
1764
+ 'BrokenComponentDidUpdate render',
1765
+ // All lifecycles run
1766
+ 'BrokenComponentDidUpdate componentDidUpdate [!]',
1767
+ 'ErrorBoundary componentDidUpdate',
1768
+ 'BrokenComponentDidUpdate componentWillUnmount',
1769
+ // Then, error is handled
1770
+ 'ErrorBoundary componentDidCatch',
1771
+ 'ErrorBoundary componentWillUpdate',
1772
+ 'ErrorBoundary render error',
1773
+ 'ErrorBoundary componentDidUpdate',
1774
+ ]);
1775
+
1776
+ log.length = 0;
1777
+ ReactDOM.unmountComponentAtNode(container);
1778
+ expect(log).toEqual(['ErrorBoundary componentWillUnmount']);
1779
+ });
1780
+
1781
+ it('propagates errors inside boundary during componentDidMount', () => {
1782
+ var container = document.createElement('div');
1783
+ ReactDOM.render(
1784
+ <ErrorBoundary>
1785
+ <BrokenComponentDidMountErrorBoundary
1786
+ renderError={error => (
1787
+ <div>
1788
+ We should never catch our own error: {error.message}.
1789
+ </div>
1790
+ )}
1791
+ />
1792
+ </ErrorBoundary>,
1793
+ container,
1794
+ );
1795
+ expect(container.firstChild.textContent).toBe('Caught an error: Hello.');
1796
+ expect(log).toEqual([
1797
+ 'ErrorBoundary constructor',
1798
+ 'ErrorBoundary componentWillMount',
1799
+ 'ErrorBoundary render success',
1800
+ 'BrokenComponentDidMountErrorBoundary constructor',
1801
+ 'BrokenComponentDidMountErrorBoundary componentWillMount',
1802
+ 'BrokenComponentDidMountErrorBoundary render success',
1803
+ 'BrokenComponentDidMountErrorBoundary componentDidMount [!]',
1804
+ // Fiber proceeds with the hooks
1805
+ 'ErrorBoundary componentDidMount',
1806
+ 'BrokenComponentDidMountErrorBoundary componentWillUnmount',
1807
+ // The error propagates to the higher boundary
1808
+ 'ErrorBoundary componentDidCatch',
1809
+ // Fiber retries from the root
1810
+ 'ErrorBoundary componentWillUpdate',
1811
+ 'ErrorBoundary render error',
1812
+ 'ErrorBoundary componentDidUpdate',
1813
+ ]);
1814
+
1815
+ log.length = 0;
1816
+ ReactDOM.unmountComponentAtNode(container);
1817
+ expect(log).toEqual(['ErrorBoundary componentWillUnmount']);
1818
+ });
1819
+
1820
+ it('lets different boundaries catch their own first errors', () => {
1821
+ function renderUnmountError(error) {
1822
+ return <div>Caught an unmounting error: {error.message}.</div>;
1823
+ }
1824
+ function renderUpdateError(error) {
1825
+ return <div>Caught an updating error: {error.message}.</div>;
1826
+ }
1827
+
1828
+ var container = document.createElement('div');
1829
+ ReactDOM.render(
1830
+ <ErrorBoundary logName="OuterErrorBoundary">
1831
+ <ErrorBoundary
1832
+ logName="InnerUnmountBoundary"
1833
+ renderError={renderUnmountError}>
1834
+ <BrokenComponentWillUnmount errorText="E1" />
1835
+ <BrokenComponentWillUnmount errorText="E2" />
1836
+ </ErrorBoundary>
1837
+ <ErrorBoundary
1838
+ logName="InnerUpdateBoundary"
1839
+ renderError={renderUpdateError}>
1840
+ <BrokenComponentDidUpdate errorText="E3" />
1841
+ <BrokenComponentDidUpdate errorText="E4" />
1842
+ </ErrorBoundary>
1843
+ </ErrorBoundary>,
1844
+ container,
1845
+ );
1846
+
1847
+ log.length = 0;
1848
+ ReactDOM.render(
1849
+ <ErrorBoundary logName="OuterErrorBoundary">
1850
+ <ErrorBoundary
1851
+ logName="InnerUnmountBoundary"
1852
+ renderError={renderUnmountError}
1853
+ />
1854
+ <ErrorBoundary
1855
+ logName="InnerUpdateBoundary"
1856
+ renderError={renderUpdateError}>
1857
+ <BrokenComponentDidUpdate errorText="E3" />
1858
+ <BrokenComponentDidUpdate errorText="E4" />
1859
+ </ErrorBoundary>
1860
+ </ErrorBoundary>,
1861
+ container,
1862
+ );
1863
+
1864
+ expect(container.firstChild.textContent).toBe(
1865
+ 'Caught an unmounting error: E1.' + 'Caught an updating error: E3.',
1866
+ );
1867
+ expect(log).toEqual([
1868
+ // Begin update phase
1869
+ 'OuterErrorBoundary componentWillReceiveProps',
1870
+ 'OuterErrorBoundary componentWillUpdate',
1871
+ 'OuterErrorBoundary render success',
1872
+ 'InnerUnmountBoundary componentWillReceiveProps',
1873
+ 'InnerUnmountBoundary componentWillUpdate',
1874
+ 'InnerUnmountBoundary render success',
1875
+ 'InnerUpdateBoundary componentWillReceiveProps',
1876
+ 'InnerUpdateBoundary componentWillUpdate',
1877
+ 'InnerUpdateBoundary render success',
1878
+ // First come the updates
1879
+ 'BrokenComponentDidUpdate componentWillReceiveProps',
1880
+ 'BrokenComponentDidUpdate componentWillUpdate',
1881
+ 'BrokenComponentDidUpdate render',
1882
+ 'BrokenComponentDidUpdate componentWillReceiveProps',
1883
+ 'BrokenComponentDidUpdate componentWillUpdate',
1884
+ 'BrokenComponentDidUpdate render',
1885
+ // We're in commit phase now, deleting
1886
+ 'BrokenComponentWillUnmount componentWillUnmount [!]',
1887
+ 'BrokenComponentWillUnmount componentWillUnmount [!]',
1888
+ // Continue despite errors, handle them after commit is done
1889
+ 'InnerUnmountBoundary componentDidUpdate',
1890
+ // We're still in commit phase, now calling update lifecycles
1891
+ 'BrokenComponentDidUpdate componentDidUpdate [!]',
1892
+ // Again, continue despite errors, we'll handle them later
1893
+ 'BrokenComponentDidUpdate componentDidUpdate [!]',
1894
+ 'InnerUpdateBoundary componentDidUpdate',
1895
+ 'OuterErrorBoundary componentDidUpdate',
1896
+ // After the commit phase, attempt to recover from any errors that
1897
+ // were captured
1898
+ 'BrokenComponentDidUpdate componentWillUnmount',
1899
+ 'BrokenComponentDidUpdate componentWillUnmount',
1900
+ 'InnerUnmountBoundary componentDidCatch',
1901
+ 'InnerUpdateBoundary componentDidCatch',
1902
+ 'InnerUnmountBoundary componentWillUpdate',
1903
+ 'InnerUnmountBoundary render error',
1904
+ 'InnerUpdateBoundary componentWillUpdate',
1905
+ 'InnerUpdateBoundary render error',
1906
+ 'InnerUnmountBoundary componentDidUpdate',
1907
+ 'InnerUpdateBoundary componentDidUpdate',
1908
+ ]);
1909
+
1910
+ log.length = 0;
1911
+ ReactDOM.unmountComponentAtNode(container);
1912
+ expect(log).toEqual([
1913
+ 'OuterErrorBoundary componentWillUnmount',
1914
+ 'InnerUnmountBoundary componentWillUnmount',
1915
+ 'InnerUpdateBoundary componentWillUnmount',
1916
+ ]);
1917
+ });
1918
+
1919
+ it('discards a bad root if the root component fails', () => {
1920
+ spyOn(console, 'error');
1921
+
1922
+ const X = null;
1923
+ const Y = undefined;
1924
+ let err1;
1925
+ let err2;
1926
+
1927
+ try {
1928
+ let container = document.createElement('div');
1929
+ ReactDOM.render(<X />, container);
1930
+ } catch (err) {
1931
+ err1 = err;
1932
+ }
1933
+ try {
1934
+ let container = document.createElement('div');
1935
+ ReactDOM.render(<Y />, container);
1936
+ } catch (err) {
1937
+ err2 = err;
1938
+ }
1939
+
1940
+ expect(err1.message).toMatch(/got: null/);
1941
+ expect(err2.message).toMatch(/got: undefined/);
1942
+ });
1943
+
1944
+ it('renders empty output if error boundary does not handle the error', () => {
1945
+ var container = document.createElement('div');
1946
+ ReactDOM.render(
1947
+ <div>
1948
+ Sibling
1949
+ <NoopErrorBoundary>
1950
+ <BrokenRender />
1951
+ </NoopErrorBoundary>
1952
+ </div>,
1953
+ container,
1954
+ );
1955
+ expect(container.firstChild.textContent).toBe('Sibling');
1956
+ expect(log).toEqual([
1957
+ 'NoopErrorBoundary constructor',
1958
+ 'NoopErrorBoundary componentWillMount',
1959
+ 'NoopErrorBoundary render',
1960
+ 'BrokenRender constructor',
1961
+ 'BrokenRender componentWillMount',
1962
+ 'BrokenRender render [!]',
1963
+ // In Fiber, noop error boundaries render null
1964
+ 'NoopErrorBoundary componentDidMount',
1965
+ 'NoopErrorBoundary componentDidCatch',
1966
+ // Nothing happens.
1967
+ ]);
1968
+
1969
+ log.length = 0;
1970
+ ReactDOM.unmountComponentAtNode(container);
1971
+ expect(log).toEqual(['NoopErrorBoundary componentWillUnmount']);
1972
+ });
1973
+
1974
+ it('passes first error when two errors happen in commit', () => {
1975
+ const errors = [];
1976
+ let caughtError;
1977
+ class Parent extends React.Component {
1978
+ render() {
1979
+ return <Child />;
1980
}
2202
- class Child extends React.Component {
2203
- render() {
2204
- return <div />;
2205
- }
2206
- componentDidMount() {
2207
- errors.push('child sad');
2208
- throw new Error('child sad');
2209
- }
1981
+ componentDidMount() {
1982
+ errors.push('parent sad');
1983
+ throw new Error('parent sad');
1984
}
2211
-
2212
- var container = document.createElement('div');
2213
- try {
2214
- // Here, we test the behavior where there is no error boundary and we
2215
- // delegate to the host root.
2216
- ReactDOM.render(<Parent />, container);
2217
- } catch (e) {
2218
- if (e.message !== 'parent sad' && e.message !== 'child sad') {
2219
- throw e;
2220
- }
2221
- caughtError = e;
1985
+ }
1986
+ class Child extends React.Component {
1987
+ render() {
1988
+ return <div />;
1989
+ }
1990
+ componentDidMount() {
1991
+ errors.push('child sad');
1992
+ throw new Error('child sad');
1993
}
1994
+ }
1995
2224
- expect(errors).toEqual(['child sad', 'parent sad']);
2225
- // Error should be the first thrown
2226
- expect(caughtError.message).toBe('child sad');
2227
- });
2228
- }
1996
+ var container = document.createElement('div');
1997
+ try {
1998
+ // Here, we test the behavior where there is no error boundary and we
1999
+ // delegate to the host root.
2000
+ ReactDOM.render(<Parent />, container);
2001
+ } catch (e) {
2002
+ if (e.message !== 'parent sad' && e.message !== 'child sad') {
2003
+ throw e;
2004
+ }
2005
+ caughtError = e;
2006
+ }
2007
+
2008
+ expect(errors).toEqual(['child sad', 'parent sad']);
2009
+ // Error should be the first thrown
2010
+ expect(caughtError.message).toBe('child sad');
2011
+ });
2012
});
src/renderers/__tests__/ReactHostOperationHistoryHook-test.js
+1
-4
@@ -9,12 +9,9 @@
9
10
'use strict';
11
12
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
13
-var describeStack = ReactDOMFeatureFlags.useFiber ? describe.skip : describe;
14
-
12
// This is only used by ReactPerf which is currently not supported on Fiber.
13
// Use browser timeline integration instead.
17
-describeStack('ReactHostOperationHistoryHook', () => {
14
+describe.skip('ReactHostOperationHistoryHook', () => {
15
var React;
16
var ReactPerf;
17
var ReactDOM;
src/renderers/__tests__/ReactMultiChild-test.js
+7
-21
@@ -16,13 +16,11 @@ describe('ReactMultiChild', () => {
16
17
var React;
18
var ReactDOM;
19
- var ReactDOMFeatureFlags;
19
20
beforeEach(() => {
21
jest.resetModules();
22
React = require('react');
23
ReactDOM = require('react-dom');
25
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
24
});
25
26
describe('reconciliation', () => {
@@ -280,8 +278,7 @@ describe('ReactMultiChild', () => {
278
'Warning: Using Maps as children is unsupported and will likely yield ' +
279
'unexpected results. Convert it to a sequence/iterable of keyed ' +
280
'ReactElements instead.\n' +
283
- // Fiber gives a slightly better stack with the nearest host components
284
- (ReactDOMFeatureFlags.useFiber ? ' in div (at **)\n' : '') +
281
+ ' in div (at **)\n' +
282
' in Parent (at **)',
283
);
284
});
@@ -368,23 +365,12 @@ describe('ReactMultiChild', () => {
365
'oneA componentDidMount',
366
'twoA componentDidMount',
367
371
- ...(ReactDOMFeatureFlags.useFiber
372
- ? [
373
- 'oneB componentWillMount',
374
- 'oneB render',
375
- 'twoB componentWillMount',
376
- 'twoB render',
377
- 'oneA componentWillUnmount',
378
- 'twoA componentWillUnmount',
379
- ]
380
- : [
381
- 'oneB componentWillMount',
382
- 'oneB render',
383
- 'oneA componentWillUnmount',
384
- 'twoB componentWillMount',
385
- 'twoB render',
386
- 'twoA componentWillUnmount',
387
- ]),
368
+ 'oneB componentWillMount',
369
+ 'oneB render',
370
+ 'twoB componentWillMount',
371
+ 'twoB render',
372
+ 'oneA componentWillUnmount',
373
+ 'twoA componentWillUnmount',
374
375
'oneB componentDidMount',
376
'twoB componentDidMount',
src/renderers/__tests__/ReactMultiChildText-test.js
+12
-46
@@ -11,7 +11,6 @@
11
12
var React = require('react');
13
var ReactDOM = require('react-dom');
14
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
14
var ReactTestUtils = require('react-dom/test-utils');
15
16
// Helpers
@@ -48,43 +47,16 @@ var expectChildren = function(container, children) {
47
expect(textNode.data).toBe('' + children);
48
}
49
} else {
51
- var openingCommentNode;
52
- var closingCommentNode;
50
var mountIndex = 0;
51
52
for (var i = 0; i < children.length; i++) {
53
var child = children[i];
54
55
if (typeof child === 'string') {
59
- if (ReactDOMFeatureFlags.useFiber) {
60
- textNode = outerNode.childNodes[mountIndex];
61
- expect(textNode.nodeType).toBe(3);
62
- expect(textNode.data).toBe('' + child);
63
- mountIndex++;
64
- } else {
65
- openingCommentNode = outerNode.childNodes[mountIndex];
66
-
67
- expect(openingCommentNode.nodeType).toBe(8);
68
- expect(openingCommentNode.nodeValue).toMatch(/ react-text: [0-9]+ /);
69
-
70
- if (child === '') {
71
- textNode = null;
72
- closingCommentNode = openingCommentNode.nextSibling;
73
- mountIndex += 2;
74
- } else {
75
- textNode = openingCommentNode.nextSibling;
76
- closingCommentNode = textNode.nextSibling;
77
- mountIndex += 3;
78
- }
79
-
80
- if (textNode) {
81
- expect(textNode.nodeType).toBe(3);
82
- expect(textNode.data).toBe('' + child);
83
- }
84
-
85
- expect(closingCommentNode.nodeType).toBe(8);
86
- expect(closingCommentNode.nodeValue).toBe(' /react-text ');
87
- }
56
+ textNode = outerNode.childNodes[mountIndex];
57
+ expect(textNode.nodeType).toBe(3);
58
+ expect(textNode.data).toBe('' + child);
59
+ mountIndex++;
60
} else {
61
var elementDOMNode = outerNode.childNodes[mountIndex];
62
expect(elementDOMNode.tagName).toBe('DIV');
@@ -189,20 +161,14 @@ describe('ReactMultiChildText', () => {
161
[true, <div>{1.2}{''}{<div />}{'foo'}</div>, true, 1.2], [<div />, '1.2'],
162
['', 'foo', <div>{true}{<div />}{1.2}{''}</div>, 'foo'], ['', 'foo', <div />, 'foo'],
163
]);
192
- if (ReactDOMFeatureFlags.useFiber) {
193
- expectDev(console.error.calls.count()).toBe(2);
194
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
195
- 'Warning: Each child in an array or iterator should have a unique "key" prop.',
196
- );
197
- expectDev(console.error.calls.argsFor(1)[0]).toContain(
198
- 'Warning: Each child in an array or iterator should have a unique "key" prop.',
199
- );
200
- } else {
201
- expectDev(console.error.calls.count()).toBe(1);
202
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
203
- 'Warning: Each child in an array or iterator should have a unique "key" prop.',
204
- );
205
- }
164
+
165
+ expectDev(console.error.calls.count()).toBe(2);
166
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
167
+ 'Warning: Each child in an array or iterator should have a unique "key" prop.',
168
+ );
169
+ expectDev(console.error.calls.argsFor(1)[0]).toContain(
170
+ 'Warning: Each child in an array or iterator should have a unique "key" prop.',
171
+ );
172
});
173
174
it('should throw if rendering both HTML and children', () => {
src/renderers/__tests__/ReactPerf-test.js
+1
-4
@@ -9,12 +9,9 @@
9
10
'use strict';
11
12
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
13
-var describeStack = ReactDOMFeatureFlags.useFiber ? describe.skip : describe;
14
-
12
// ReactPerf is currently not supported on Fiber.
13
// Use browser timeline integration instead.
17
-describeStack('ReactPerf', () => {
14
+describe.skip('ReactPerf', () => {
15
var React;
16
var ReactDOM;
17
var ReactPerf;
src/renderers/__tests__/ReactStatelessComponent-test.js
+14
-48
@@ -14,8 +14,6 @@ var React;
14
var ReactDOM;
15
var ReactTestUtils;
16
17
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
18
-
17
function StatelessComponent(props) {
18
return <div>{props.name}</div>;
19
}
@@ -118,54 +116,22 @@ describe('ReactStatelessComponent', () => {
116
117
ReactDOM.render(<StatelessComponentWithChildContext name="A" />, container);
118
121
- // Stack and Fiber differ in terms of they show warnings
122
- if (ReactDOMFeatureFlags.useFiber) {
123
- expectDev(console.error.calls.count()).toBe(1);
124
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
125
- 'StatelessComponentWithChildContext(...): childContextTypes cannot ' +
126
- 'be defined on a functional component.',
127
- );
128
- } else {
129
- expectDev(console.error.calls.count()).toBe(2);
130
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
131
- 'StatelessComponentWithChildContext(...): childContextTypes cannot ' +
132
- 'be defined on a functional component.',
133
- );
134
- expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
135
- 'Warning: StatelessComponentWithChildContext.childContextTypes is specified ' +
136
- 'but there is no getChildContext() method on the instance. You can either ' +
137
- 'define getChildContext() on StatelessComponentWithChildContext or remove ' +
138
- 'childContextTypes from it.',
139
- );
140
- }
119
+ expectDev(console.error.calls.count()).toBe(1);
120
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
121
+ 'StatelessComponentWithChildContext(...): childContextTypes cannot ' +
122
+ 'be defined on a functional component.',
123
+ );
124
});
125
143
- if (!ReactDOMFeatureFlags.useFiber) {
144
- // Stack doesn't support fragments
145
- it('should throw when stateless component returns array', () => {
146
- function NotAComponent() {
147
- return [<div />, <div />];
148
- }
149
- expect(function() {
150
- ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
151
- }).toThrowError(
152
- 'NotAComponent(...): A valid React element (or null) must be returned. ' +
153
- 'You may have returned undefined, an array or some other invalid object.',
154
- );
155
- });
156
- }
157
-
158
- if (ReactDOMFeatureFlags.useFiber) {
159
- it('should throw when stateless component returns undefined', () => {
160
- function NotAComponent() {}
161
- expect(function() {
162
- ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
163
- }).toThrowError(
164
- 'NotAComponent(...): Nothing was returned from render. ' +
165
- 'This usually means a return statement is missing. Or, to render nothing, return null.',
166
- );
167
- });
168
- }
126
+ it('should throw when stateless component returns undefined', () => {
127
+ function NotAComponent() {}
128
+ expect(function() {
129
+ ReactTestUtils.renderIntoDocument(<div><NotAComponent /></div>);
130
+ }).toThrowError(
131
+ 'NotAComponent(...): Nothing was returned from render. ' +
132
+ 'This usually means a return statement is missing. Or, to render nothing, return null.',
133
+ );
134
+ });
135
136
it('should throw on string refs in pure functions', () => {
137
function Child() {
src/renderers/__tests__/ReactUpdates-test.js
+25
-35
@@ -12,13 +12,11 @@
12
var React;
13
var ReactDOM;
14
var ReactTestUtils;
15
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
15
16
describe('ReactUpdates', () => {
17
beforeEach(() => {
18
React = require('react');
19
ReactDOM = require('react-dom');
21
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
20
ReactTestUtils = require('react-dom/test-utils');
21
});
22
@@ -519,9 +517,7 @@ describe('ReactUpdates', () => {
517
render() {
518
var portal = null;
519
// If we're using Fiber, we use Portals instead to achieve this.
522
- if (ReactDOMFeatureFlags.useFiber) {
523
- portal = ReactDOM.createPortal(<B ref={n => (b = n)} />, bContainer);
524
- }
520
+ portal = ReactDOM.createPortal(<B ref={n => (b = n)} />, bContainer);
521
return <div>A{this.state.x}{portal}</div>;
522
}
523
}
@@ -535,10 +531,6 @@ describe('ReactUpdates', () => {
531
}
532
533
a = ReactTestUtils.renderIntoDocument(<A />);
538
- if (!ReactDOMFeatureFlags.useFiber) {
539
- ReactDOM.render(<B ref={n => (b = n)} />, bContainer);
540
- }
541
-
534
ReactDOM.unstable_batchedUpdates(function() {
535
a.setState({x: 1});
536
b.setState({x: 1});
@@ -1178,35 +1170,33 @@ describe('ReactUpdates', () => {
1170
}).toThrow('Maximum');
1171
});
1172
1181
- if (ReactDOMFeatureFlags.useFiber) {
1182
- it('does not fall into an infinite error loop', () => {
1183
- function BadRender() {
1184
- throw new Error('error');
1185
- }
1173
+ it('does not fall into an infinite error loop', () => {
1174
+ function BadRender() {
1175
+ throw new Error('error');
1176
+ }
1177
1187
- class ErrorBoundary extends React.Component {
1188
- componentDidCatch() {
1189
- this.props.parent.remount();
1190
- }
1191
- render() {
1192
- return <BadRender />;
1193
- }
1178
+ class ErrorBoundary extends React.Component {
1179
+ componentDidCatch() {
1180
+ this.props.parent.remount();
1181
+ }
1182
+ render() {
1183
+ return <BadRender />;
1184
}
1185
+ }
1186
1196
- class NonTerminating extends React.Component {
1197
- state = {step: 0};
1198
- remount() {
1199
- this.setState(state => ({step: state.step + 1}));
1200
- }
1201
- render() {
1202
- return <ErrorBoundary key={this.state.step} parent={this} />;
1203
- }
1187
+ class NonTerminating extends React.Component {
1188
+ state = {step: 0};
1189
+ remount() {
1190
+ this.setState(state => ({step: state.step + 1}));
1191
+ }
1192
+ render() {
1193
+ return <ErrorBoundary key={this.state.step} parent={this} />;
1194
}
1195
+ }
1196
1206
- const container = document.createElement('div');
1207
- expect(() => {
1208
- ReactDOM.render(<NonTerminating />, container);
1209
- }).toThrow('Maximum');
1210
- });
1211
- }
1197
+ const container = document.createElement('div');
1198
+ expect(() => {
1199
+ ReactDOM.render(<NonTerminating />, container);
1200
+ }).toThrow('Maximum');
1201
+ });
1202
});
src/renderers/__tests__/multiple-copies-of-react-test.js
+7
-19
@@ -10,7 +10,6 @@
10
'use strict';
11
12
let React = require('react');
13
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
13
var ReactTestUtils = require('react-dom/test-utils');
14
15
class TextWithStringRef extends React.Component {
@@ -27,23 +26,12 @@ class TextWithStringRef extends React.Component {
26
27
describe('when different React version is used with string ref', () => {
28
it('throws the "Refs must have owner" warning', () => {
30
- if (ReactDOMFeatureFlags.useFiber) {
31
- expect(() => {
32
- ReactTestUtils.renderIntoDocument(<TextWithStringRef />);
33
- }).toThrow(
34
- 'Element ref was specified as a string (foo) but no owner was set.' +
35
- ' You may have multiple copies of React loaded. (details: ' +
36
- 'https://fb.me/react-refs-must-have-owner).',
37
- );
38
- } else {
39
- expect(() => {
40
- ReactTestUtils.renderIntoDocument(<TextWithStringRef />);
41
- }).toThrow(
42
- 'Only a ReactOwner can have refs. You might be adding a ref to a ' +
43
- "component that was not created inside a component's `render` " +
44
- 'method, or you have multiple copies of React loaded ' +
45
- '(details: https://fb.me/react-refs-must-have-owner)',
46
- );
47
- }
29
+ expect(() => {
30
+ ReactTestUtils.renderIntoDocument(<TextWithStringRef />);
31
+ }).toThrow(
32
+ 'Element ref was specified as a string (foo) but no owner was set.' +
33
+ ' You may have multiple copies of React loaded. (details: ' +
34
+ 'https://fb.me/react-refs-must-have-owner).',
35
+ );
36
});
37
});
src/renderers/__tests__/refs-test.js
+34
-56
@@ -10,7 +10,6 @@
10
'use strict';
11
12
var React = require('react');
13
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
13
var ReactTestUtils = require('react-dom/test-utils');
14
15
/**
@@ -348,40 +347,38 @@ describe('root level refs', () => {
347
expect(ref).toHaveBeenCalledTimes(2);
348
expect(ref.mock.calls[1][0]).toBe(null);
349
351
- if (ReactDOMFeatureFlags.useFiber) {
352
- // fragment
353
- inst = null;
354
- ref = jest.fn(value => (inst = value));
355
- var divInst = null;
356
- var ref2 = jest.fn(value => (divInst = value));
357
- result = ReactDOM.render(
358
- [<Comp ref={ref} key="a" />, 5, <div ref={ref2} key="b">Hello</div>],
359
- container,
360
- );
350
+ // fragment
351
+ inst = null;
352
+ ref = jest.fn(value => (inst = value));
353
+ var divInst = null;
354
+ var ref2 = jest.fn(value => (divInst = value));
355
+ result = ReactDOM.render(
356
+ [<Comp ref={ref} key="a" />, 5, <div ref={ref2} key="b">Hello</div>],
357
+ container,
358
+ );
359
362
- // first call should be `Comp`
363
- expect(ref).toHaveBeenCalledTimes(1);
364
- expect(ref.mock.calls[0][0]).toBeInstanceOf(Comp);
365
- expect(result).toBe(ref.mock.calls[0][0]);
360
+ // first call should be `Comp`
361
+ expect(ref).toHaveBeenCalledTimes(1);
362
+ expect(ref.mock.calls[0][0]).toBeInstanceOf(Comp);
363
+ expect(result).toBe(ref.mock.calls[0][0]);
364
367
- expect(ref2).toHaveBeenCalledTimes(1);
368
- expect(divInst).toBeInstanceOf(HTMLDivElement);
369
- expect(result).not.toBe(divInst);
365
+ expect(ref2).toHaveBeenCalledTimes(1);
366
+ expect(divInst).toBeInstanceOf(HTMLDivElement);
367
+ expect(result).not.toBe(divInst);
368
371
- ReactDOM.unmountComponentAtNode(container);
372
- expect(ref).toHaveBeenCalledTimes(2);
373
- expect(ref.mock.calls[1][0]).toBe(null);
374
- expect(ref2).toHaveBeenCalledTimes(2);
375
- expect(ref2.mock.calls[1][0]).toBe(null);
369
+ ReactDOM.unmountComponentAtNode(container);
370
+ expect(ref).toHaveBeenCalledTimes(2);
371
+ expect(ref.mock.calls[1][0]).toBe(null);
372
+ expect(ref2).toHaveBeenCalledTimes(2);
373
+ expect(ref2.mock.calls[1][0]).toBe(null);
374
377
- // null
378
- result = ReactDOM.render(null, container);
379
- expect(result).toBe(null);
375
+ // null
376
+ result = ReactDOM.render(null, container);
377
+ expect(result).toBe(null);
378
381
- // primitives
382
- result = ReactDOM.render(5, container);
383
- expect(result).toBeInstanceOf(Text);
384
- }
379
+ // primitives
380
+ result = ReactDOM.render(5, container);
381
+ expect(result).toBeInstanceOf(Text);
382
});
383
});
384
@@ -397,28 +394,6 @@ describe('creating element with ref in constructor', () => {
394
}
395
}
396
400
- var devErrorMessage =
401
- 'addComponentAsRefTo(...): Only a ReactOwner can have refs. You might ' +
402
- "be adding a ref to a component that was not created inside a component's " +
403
- '`render` method, or you have multiple copies of React loaded ' +
404
- '(details: https://fb.me/react-refs-must-have-owner).';
405
-
406
- var prodErrorMessage =
407
- 'Minified React error #119; visit ' +
408
- 'http://facebook.github.io/react/docs/error-decoder.html?invariant=119 for the full message ' +
409
- 'or use the non-minified dev environment for full errors and additional helpful warnings.';
410
-
411
- var fiberDevErrorMessage =
412
- 'Element ref was specified as a string (p) but no owner was ' +
413
- 'set. You may have multiple copies of React loaded. ' +
414
- '(details: https://fb.me/react-refs-must-have-owner).';
415
-
416
- var fiberProdErrorMessage =
417
- 'Minified React error #149; visit ' +
418
- 'http://facebook.github.io/react/docs/error-decoder.html?invariant=149&args[]=p ' +
419
- 'for the full message or use the non-minified dev environment for full errors and additional ' +
420
- 'helpful warnings.';
421
-
397
it('throws an error when __DEV__ = true', () => {
398
ReactTestUtils = require('react-dom/test-utils');
399
@@ -429,7 +404,9 @@ describe('creating element with ref in constructor', () => {
404
expect(function() {
405
ReactTestUtils.renderIntoDocument(<RefTest />);
406
}).toThrowError(
432
- ReactDOMFeatureFlags.useFiber ? fiberDevErrorMessage : devErrorMessage,
407
+ 'Element ref was specified as a string (p) but no owner was ' +
408
+ 'set. You may have multiple copies of React loaded. ' +
409
+ '(details: https://fb.me/react-refs-must-have-owner).',
410
);
411
} finally {
412
__DEV__ = originalDev;
@@ -446,9 +423,10 @@ describe('creating element with ref in constructor', () => {
423
expect(function() {
424
ReactTestUtils.renderIntoDocument(<RefTest />);
425
}).toThrowError(
449
- ReactDOMFeatureFlags.useFiber
450
- ? fiberProdErrorMessage
451
- : prodErrorMessage,
426
+ 'Minified React error #149; visit ' +
427
+ 'http://facebook.github.io/react/docs/error-decoder.html?invariant=149&args[]=p ' +
428
+ 'for the full message or use the non-minified dev environment for full errors and additional ' +
429
+ 'helpful warnings.',
430
);
431
} finally {
432
__DEV__ = originalDev;
src/renderers/dom/__tests__/ReactDOMProduction-test.js
+49
-53
@@ -9,8 +9,6 @@
9
'use strict';
10
11
describe('ReactDOMProduction', () => {
12
- var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
13
-
12
var React;
13
var ReactDOM;
14
var ReactDOMServer;
@@ -195,7 +193,7 @@ describe('ReactDOMProduction', () => {
193
});
194
195
it('should throw with an error code in production', () => {
198
- const errorCode = ReactDOMFeatureFlags.useFiber ? 152 : 109;
196
+ const errorCode = 152;
197
expect(function() {
198
class Component extends React.Component {
199
render() {
@@ -235,57 +233,55 @@ describe('ReactDOMProduction', () => {
233
}
234
});
235
238
- if (ReactDOMFeatureFlags.useFiber) {
239
- // This test is originally from ReactDOMFiber-test but we replicate it here
240
- // to avoid production-only regressions because of host context differences
241
- // in dev and prod.
242
- it('should keep track of namespace across portals in production', () => {
243
- var svgEls, htmlEls;
244
- var expectSVG = {ref: el => svgEls.push(el)};
245
- var expectHTML = {ref: el => htmlEls.push(el)};
246
- var usePortal = function(tree) {
247
- return ReactDOM.createPortal(tree, document.createElement('div'));
248
- };
249
- var assertNamespacesMatch = function(tree) {
250
- var container = document.createElement('div');
251
- svgEls = [];
252
- htmlEls = [];
253
- ReactDOM.render(tree, container);
254
- svgEls.forEach(el => {
255
- expect(el.namespaceURI).toBe('http://www.w3.org/2000/svg');
256
- });
257
- htmlEls.forEach(el => {
258
- expect(el.namespaceURI).toBe('http://www.w3.org/1999/xhtml');
259
- });
260
- ReactDOM.unmountComponentAtNode(container);
261
- expect(container.innerHTML).toBe('');
262
- };
236
+ // This test is originally from ReactDOMFiber-test but we replicate it here
237
+ // to avoid production-only regressions because of host context differences
238
+ // in dev and prod.
239
+ it('should keep track of namespace across portals in production', () => {
240
+ var svgEls, htmlEls;
241
+ var expectSVG = {ref: el => svgEls.push(el)};
242
+ var expectHTML = {ref: el => htmlEls.push(el)};
243
+ var usePortal = function(tree) {
244
+ return ReactDOM.createPortal(tree, document.createElement('div'));
245
+ };
246
+ var assertNamespacesMatch = function(tree) {
247
+ var container = document.createElement('div');
248
+ svgEls = [];
249
+ htmlEls = [];
250
+ ReactDOM.render(tree, container);
251
+ svgEls.forEach(el => {
252
+ expect(el.namespaceURI).toBe('http://www.w3.org/2000/svg');
253
+ });
254
+ htmlEls.forEach(el => {
255
+ expect(el.namespaceURI).toBe('http://www.w3.org/1999/xhtml');
256
+ });
257
+ ReactDOM.unmountComponentAtNode(container);
258
+ expect(container.innerHTML).toBe('');
259
+ };
260
264
- assertNamespacesMatch(
265
- <div {...expectHTML}>
266
- <svg {...expectSVG}>
267
- <foreignObject {...expectSVG}>
268
- <p {...expectHTML} />
269
- {usePortal(
261
+ assertNamespacesMatch(
262
+ <div {...expectHTML}>
263
+ <svg {...expectSVG}>
264
+ <foreignObject {...expectSVG}>
265
+ <p {...expectHTML} />
266
+ {usePortal(
267
+ <svg {...expectSVG}>
268
+ <image {...expectSVG} />
269
<svg {...expectSVG}>
270
<image {...expectSVG} />
272
- <svg {...expectSVG}>
273
- <image {...expectSVG} />
274
- <foreignObject {...expectSVG}>
275
- <p {...expectHTML} />
276
- </foreignObject>
277
- {usePortal(<p {...expectHTML} />)}
278
- </svg>
279
- <image {...expectSVG} />
280
- </svg>,
281
- )}
282
- <p {...expectHTML} />
283
- </foreignObject>
284
- <image {...expectSVG} />
285
- </svg>
286
- <p {...expectHTML} />
287
- </div>,
288
- );
289
- });
290
- }
271
+ <foreignObject {...expectSVG}>
272
+ <p {...expectHTML} />
273
+ </foreignObject>
274
+ {usePortal(<p {...expectHTML} />)}
275
+ </svg>
276
+ <image {...expectSVG} />
277
+ </svg>,
278
+ )}
279
+ <p {...expectHTML} />
280
+ </foreignObject>
281
+ <image {...expectSVG} />
282
+ </svg>
283
+ <p {...expectHTML} />
284
+ </div>,
285
+ );
286
+ });
287
});
src/renderers/dom/fiber/__tests__/ReactDOMFiber-test.js
+908
-913
@@ -11,7 +11,6 @@
11
12
var React = require('react');
13
var ReactDOM = require('react-dom');
14
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
14
var ReactTestUtils = require('react-dom/test-utils');
15
var PropTypes = require('prop-types');
16
@@ -74,1076 +73,1072 @@ describe('ReactDOMFiber', () => {
73
expect(called).toEqual(true);
74
});
75
77
- if (ReactDOMFeatureFlags.useFiber) {
78
- it('should render a component returning strings directly from render', () => {
79
- const Text = ({value}) => value;
76
+ it('should render a component returning strings directly from render', () => {
77
+ const Text = ({value}) => value;
78
81
- ReactDOM.render(<Text value="foo" />, container);
82
- expect(container.textContent).toEqual('foo');
83
- });
79
+ ReactDOM.render(<Text value="foo" />, container);
80
+ expect(container.textContent).toEqual('foo');
81
+ });
82
85
- it('should render a component returning numbers directly from render', () => {
86
- const Text = ({value}) => value;
83
+ it('should render a component returning numbers directly from render', () => {
84
+ const Text = ({value}) => value;
85
88
- ReactDOM.render(<Text value={10} />, container);
86
+ ReactDOM.render(<Text value={10} />, container);
87
90
- expect(container.textContent).toEqual('10');
91
- });
88
+ expect(container.textContent).toEqual('10');
89
+ });
90
93
- it('finds the DOM Text node of a string child', () => {
94
- class Text extends React.Component {
95
- render() {
96
- return this.props.value;
97
- }
91
+ it('finds the DOM Text node of a string child', () => {
92
+ class Text extends React.Component {
93
+ render() {
94
+ return this.props.value;
95
}
96
+ }
97
100
- let instance = null;
101
- ReactDOM.render(
102
- <Text value="foo" ref={ref => (instance = ref)} />,
103
- container,
104
- );
98
+ let instance = null;
99
+ ReactDOM.render(
100
+ <Text value="foo" ref={ref => (instance = ref)} />,
101
+ container,
102
+ );
103
106
- const textNode = ReactDOM.findDOMNode(instance);
107
- expect(textNode).toBe(container.firstChild);
108
- expect(textNode.nodeType).toBe(3);
109
- expect(textNode.nodeValue).toBe('foo');
110
- });
104
+ const textNode = ReactDOM.findDOMNode(instance);
105
+ expect(textNode).toBe(container.firstChild);
106
+ expect(textNode.nodeType).toBe(3);
107
+ expect(textNode.nodeValue).toBe('foo');
108
+ });
109
112
- it('finds the first child when a component returns a fragment', () => {
113
- class Fragment extends React.Component {
114
- render() {
115
- return [<div key="a" />, <span key="b" />];
116
- }
110
+ it('finds the first child when a component returns a fragment', () => {
111
+ class Fragment extends React.Component {
112
+ render() {
113
+ return [<div key="a" />, <span key="b" />];
114
}
115
+ }
116
119
- let instance = null;
120
- ReactDOM.render(<Fragment ref={ref => (instance = ref)} />, container);
117
+ let instance = null;
118
+ ReactDOM.render(<Fragment ref={ref => (instance = ref)} />, container);
119
122
- expect(container.childNodes.length).toBe(2);
120
+ expect(container.childNodes.length).toBe(2);
121
124
- const firstNode = ReactDOM.findDOMNode(instance);
125
- expect(firstNode).toBe(container.firstChild);
126
- expect(firstNode.tagName).toBe('DIV');
127
- });
122
+ const firstNode = ReactDOM.findDOMNode(instance);
123
+ expect(firstNode).toBe(container.firstChild);
124
+ expect(firstNode.tagName).toBe('DIV');
125
+ });
126
129
- it('finds the first child even when fragment is nested', () => {
130
- class Wrapper extends React.Component {
131
- render() {
132
- return this.props.children;
133
- }
127
+ it('finds the first child even when fragment is nested', () => {
128
+ class Wrapper extends React.Component {
129
+ render() {
130
+ return this.props.children;
131
}
132
+ }
133
136
- class Fragment extends React.Component {
137
- render() {
138
- return [<Wrapper key="a"><div /></Wrapper>, <span key="b" />];
139
- }
134
+ class Fragment extends React.Component {
135
+ render() {
136
+ return [<Wrapper key="a"><div /></Wrapper>, <span key="b" />];
137
}
138
+ }
139
142
- let instance = null;
143
- ReactDOM.render(<Fragment ref={ref => (instance = ref)} />, container);
140
+ let instance = null;
141
+ ReactDOM.render(<Fragment ref={ref => (instance = ref)} />, container);
142
145
- expect(container.childNodes.length).toBe(2);
143
+ expect(container.childNodes.length).toBe(2);
144
147
- const firstNode = ReactDOM.findDOMNode(instance);
148
- expect(firstNode).toBe(container.firstChild);
149
- expect(firstNode.tagName).toBe('DIV');
150
- });
145
+ const firstNode = ReactDOM.findDOMNode(instance);
146
+ expect(firstNode).toBe(container.firstChild);
147
+ expect(firstNode.tagName).toBe('DIV');
148
+ });
149
152
- it('finds the first child even when first child renders null', () => {
153
- class NullComponent extends React.Component {
154
- render() {
155
- return null;
156
- }
150
+ it('finds the first child even when first child renders null', () => {
151
+ class NullComponent extends React.Component {
152
+ render() {
153
+ return null;
154
}
155
+ }
156
159
- class Fragment extends React.Component {
160
- render() {
161
- return [<NullComponent key="a" />, <div key="b" />, <span key="c" />];
162
- }
157
+ class Fragment extends React.Component {
158
+ render() {
159
+ return [<NullComponent key="a" />, <div key="b" />, <span key="c" />];
160
}
161
+ }
162
165
- let instance = null;
166
- ReactDOM.render(<Fragment ref={ref => (instance = ref)} />, container);
163
+ let instance = null;
164
+ ReactDOM.render(<Fragment ref={ref => (instance = ref)} />, container);
165
168
- expect(container.childNodes.length).toBe(2);
166
+ expect(container.childNodes.length).toBe(2);
167
170
- const firstNode = ReactDOM.findDOMNode(instance);
171
- expect(firstNode).toBe(container.firstChild);
172
- expect(firstNode.tagName).toBe('DIV');
173
- });
174
- }
175
-
176
- if (ReactDOMFeatureFlags.useFiber) {
177
- var svgEls, htmlEls, mathEls;
178
- var expectSVG = {ref: el => svgEls.push(el)};
179
- var expectHTML = {ref: el => htmlEls.push(el)};
180
- var expectMath = {ref: el => mathEls.push(el)};
181
-
182
- var usePortal = function(tree) {
183
- return ReactDOM.createPortal(tree, document.createElement('div'));
184
- };
185
-
186
- var assertNamespacesMatch = function(tree) {
187
- container = document.createElement('div');
188
- svgEls = [];
189
- htmlEls = [];
190
- mathEls = [];
191
-
192
- ReactDOM.render(tree, container);
193
- svgEls.forEach(el => {
194
- expect(el.namespaceURI).toBe('http://www.w3.org/2000/svg');
195
- });
196
- htmlEls.forEach(el => {
197
- expect(el.namespaceURI).toBe('http://www.w3.org/1999/xhtml');
198
- });
199
- mathEls.forEach(el => {
200
- expect(el.namespaceURI).toBe('http://www.w3.org/1998/Math/MathML');
201
- });
202
-
203
- ReactDOM.unmountComponentAtNode(container);
204
- expect(container.innerHTML).toBe('');
205
- };
206
-
207
- it('should render one portal', () => {
208
- var portalContainer = document.createElement('div');
209
-
210
- ReactDOM.render(
211
- <div>
212
- {ReactDOM.createPortal(<div>portal</div>, portalContainer)}
213
- </div>,
214
- container,
215
- );
216
- expect(portalContainer.innerHTML).toBe('<div>portal</div>');
217
- expect(container.innerHTML).toBe('<div></div>');
168
+ const firstNode = ReactDOM.findDOMNode(instance);
169
+ expect(firstNode).toBe(container.firstChild);
170
+ expect(firstNode.tagName).toBe('DIV');
171
+ });
172
219
- ReactDOM.unmountComponentAtNode(container);
220
- expect(portalContainer.innerHTML).toBe('');
221
- expect(container.innerHTML).toBe('');
222
- });
173
+ var svgEls, htmlEls, mathEls;
174
+ var expectSVG = {ref: el => svgEls.push(el)};
175
+ var expectHTML = {ref: el => htmlEls.push(el)};
176
+ var expectMath = {ref: el => mathEls.push(el)};
177
224
- // TODO: remove in React 17
225
- it('should support unstable_createPortal alias', () => {
226
- var portalContainer = document.createElement('div');
178
+ var usePortal = function(tree) {
179
+ return ReactDOM.createPortal(tree, document.createElement('div'));
180
+ };
181
228
- ReactDOM.render(
229
- <div>
230
- {ReactDOM.unstable_createPortal(<div>portal</div>, portalContainer)}
231
- </div>,
232
- container,
233
- );
234
- expect(portalContainer.innerHTML).toBe('<div>portal</div>');
235
- expect(container.innerHTML).toBe('<div></div>');
182
+ var assertNamespacesMatch = function(tree) {
183
+ container = document.createElement('div');
184
+ svgEls = [];
185
+ htmlEls = [];
186
+ mathEls = [];
187
237
- ReactDOM.unmountComponentAtNode(container);
238
- expect(portalContainer.innerHTML).toBe('');
239
- expect(container.innerHTML).toBe('');
188
+ ReactDOM.render(tree, container);
189
+ svgEls.forEach(el => {
190
+ expect(el.namespaceURI).toBe('http://www.w3.org/2000/svg');
191
+ });
192
+ htmlEls.forEach(el => {
193
+ expect(el.namespaceURI).toBe('http://www.w3.org/1999/xhtml');
194
+ });
195
+ mathEls.forEach(el => {
196
+ expect(el.namespaceURI).toBe('http://www.w3.org/1998/Math/MathML');
197
});
198
242
- it('should render many portals', () => {
243
- var portalContainer1 = document.createElement('div');
244
- var portalContainer2 = document.createElement('div');
245
-
246
- var ops = [];
247
- class Child extends React.Component {
248
- componentDidMount() {
249
- ops.push(`${this.props.name} componentDidMount`);
250
- }
251
- componentDidUpdate() {
252
- ops.push(`${this.props.name} componentDidUpdate`);
253
- }
254
- componentWillUnmount() {
255
- ops.push(`${this.props.name} componentWillUnmount`);
256
- }
257
- render() {
258
- return <div>{this.props.name}</div>;
259
- }
260
- }
199
+ ReactDOM.unmountComponentAtNode(container);
200
+ expect(container.innerHTML).toBe('');
201
+ };
202
+
203
+ it('should render one portal', () => {
204
+ var portalContainer = document.createElement('div');
205
+
206
+ ReactDOM.render(
207
+ <div>
208
+ {ReactDOM.createPortal(<div>portal</div>, portalContainer)}
209
+ </div>,
210
+ container,
211
+ );
212
+ expect(portalContainer.innerHTML).toBe('<div>portal</div>');
213
+ expect(container.innerHTML).toBe('<div></div>');
214
+
215
+ ReactDOM.unmountComponentAtNode(container);
216
+ expect(portalContainer.innerHTML).toBe('');
217
+ expect(container.innerHTML).toBe('');
218
+ });
219
262
- class Parent extends React.Component {
263
- componentDidMount() {
264
- ops.push(`Parent:${this.props.step} componentDidMount`);
265
- }
266
- componentDidUpdate() {
267
- ops.push(`Parent:${this.props.step} componentDidUpdate`);
268
- }
269
- componentWillUnmount() {
270
- ops.push(`Parent:${this.props.step} componentWillUnmount`);
271
- }
272
- render() {
273
- const {step} = this.props;
274
- return [
275
- <Child key="a" name={`normal[0]:${step}`} />,
276
- ReactDOM.createPortal(
277
- <Child key="b" name={`portal1[0]:${step}`} />,
278
- portalContainer1,
279
- ),
280
- <Child key="c" name={`normal[1]:${step}`} />,
281
- ReactDOM.createPortal(
282
- [
283
- <Child key="d" name={`portal2[0]:${step}`} />,
284
- <Child key="e" name={`portal2[1]:${step}`} />,
285
- ],
286
- portalContainer2,
287
- ),
288
- ];
289
- }
290
- }
220
+ // TODO: remove in React 17
221
+ it('should support unstable_createPortal alias', () => {
222
+ var portalContainer = document.createElement('div');
223
+
224
+ ReactDOM.render(
225
+ <div>
226
+ {ReactDOM.unstable_createPortal(<div>portal</div>, portalContainer)}
227
+ </div>,
228
+ container,
229
+ );
230
+ expect(portalContainer.innerHTML).toBe('<div>portal</div>');
231
+ expect(container.innerHTML).toBe('<div></div>');
232
+
233
+ ReactDOM.unmountComponentAtNode(container);
234
+ expect(portalContainer.innerHTML).toBe('');
235
+ expect(container.innerHTML).toBe('');
236
+ });
237
292
- ReactDOM.render(<Parent step="a" />, container);
293
- expect(portalContainer1.innerHTML).toBe('<div>portal1[0]:a</div>');
294
- expect(portalContainer2.innerHTML).toBe(
295
- '<div>portal2[0]:a</div><div>portal2[1]:a</div>',
296
- );
297
- expect(container.innerHTML).toBe(
298
- '<div>normal[0]:a</div><div>normal[1]:a</div>',
299
- );
300
- expect(ops).toEqual([
301
- 'normal[0]:a componentDidMount',
302
- 'portal1[0]:a componentDidMount',
303
- 'normal[1]:a componentDidMount',
304
- 'portal2[0]:a componentDidMount',
305
- 'portal2[1]:a componentDidMount',
306
- 'Parent:a componentDidMount',
307
- ]);
308
-
309
- ops.length = 0;
310
- ReactDOM.render(<Parent step="b" />, container);
311
- expect(portalContainer1.innerHTML).toBe('<div>portal1[0]:b</div>');
312
- expect(portalContainer2.innerHTML).toBe(
313
- '<div>portal2[0]:b</div><div>portal2[1]:b</div>',
314
- );
315
- expect(container.innerHTML).toBe(
316
- '<div>normal[0]:b</div><div>normal[1]:b</div>',
317
- );
318
- expect(ops).toEqual([
319
- 'normal[0]:b componentDidUpdate',
320
- 'portal1[0]:b componentDidUpdate',
321
- 'normal[1]:b componentDidUpdate',
322
- 'portal2[0]:b componentDidUpdate',
323
- 'portal2[1]:b componentDidUpdate',
324
- 'Parent:b componentDidUpdate',
325
- ]);
326
-
327
- ops.length = 0;
328
- ReactDOM.unmountComponentAtNode(container);
329
- expect(portalContainer1.innerHTML).toBe('');
330
- expect(portalContainer2.innerHTML).toBe('');
331
- expect(container.innerHTML).toBe('');
332
- expect(ops).toEqual([
333
- 'Parent:b componentWillUnmount',
334
- 'normal[0]:b componentWillUnmount',
335
- 'portal1[0]:b componentWillUnmount',
336
- 'normal[1]:b componentWillUnmount',
337
- 'portal2[0]:b componentWillUnmount',
338
- 'portal2[1]:b componentWillUnmount',
339
- ]);
340
- });
238
+ it('should render many portals', () => {
239
+ var portalContainer1 = document.createElement('div');
240
+ var portalContainer2 = document.createElement('div');
241
342
- it('should render nested portals', () => {
343
- var portalContainer1 = document.createElement('div');
344
- var portalContainer2 = document.createElement('div');
345
- var portalContainer3 = document.createElement('div');
242
+ var ops = [];
243
+ class Child extends React.Component {
244
+ componentDidMount() {
245
+ ops.push(`${this.props.name} componentDidMount`);
246
+ }
247
+ componentDidUpdate() {
248
+ ops.push(`${this.props.name} componentDidUpdate`);
249
+ }
250
+ componentWillUnmount() {
251
+ ops.push(`${this.props.name} componentWillUnmount`);
252
+ }
253
+ render() {
254
+ return <div>{this.props.name}</div>;
255
+ }
256
+ }
257
347
- ReactDOM.render(
348
- [
349
- <div key="a">normal[0]</div>,
258
+ class Parent extends React.Component {
259
+ componentDidMount() {
260
+ ops.push(`Parent:${this.props.step} componentDidMount`);
261
+ }
262
+ componentDidUpdate() {
263
+ ops.push(`Parent:${this.props.step} componentDidUpdate`);
264
+ }
265
+ componentWillUnmount() {
266
+ ops.push(`Parent:${this.props.step} componentWillUnmount`);
267
+ }
268
+ render() {
269
+ const {step} = this.props;
270
+ return [
271
+ <Child key="a" name={`normal[0]:${step}`} />,
272
+ ReactDOM.createPortal(
273
+ <Child key="b" name={`portal1[0]:${step}`} />,
274
+ portalContainer1,
275
+ ),
276
+ <Child key="c" name={`normal[1]:${step}`} />,
277
ReactDOM.createPortal(
278
[
352
- <div key="b">portal1[0]</div>,
353
- ReactDOM.createPortal(
354
- <div key="c">portal2[0]</div>,
355
- portalContainer2,
356
- ),
357
- ReactDOM.createPortal(
358
- <div key="d">portal3[0]</div>,
359
- portalContainer3,
360
- ),
361
- <div key="e">portal1[1]</div>,
279
+ <Child key="d" name={`portal2[0]:${step}`} />,
280
+ <Child key="e" name={`portal2[1]:${step}`} />,
281
],
363
- portalContainer1,
282
+ portalContainer2,
283
),
365
- <div key="f">normal[1]</div>,
366
- ],
367
- container,
368
- );
369
- expect(portalContainer1.innerHTML).toBe(
370
- '<div>portal1[0]</div><div>portal1[1]</div>',
371
- );
372
- expect(portalContainer2.innerHTML).toBe('<div>portal2[0]</div>');
373
- expect(portalContainer3.innerHTML).toBe('<div>portal3[0]</div>');
374
- expect(container.innerHTML).toBe(
375
- '<div>normal[0]</div><div>normal[1]</div>',
376
- );
284
+ ];
285
+ }
286
+ }
287
378
- ReactDOM.unmountComponentAtNode(container);
379
- expect(portalContainer1.innerHTML).toBe('');
380
- expect(portalContainer2.innerHTML).toBe('');
381
- expect(portalContainer3.innerHTML).toBe('');
382
- expect(container.innerHTML).toBe('');
383
- });
288
+ ReactDOM.render(<Parent step="a" />, container);
289
+ expect(portalContainer1.innerHTML).toBe('<div>portal1[0]:a</div>');
290
+ expect(portalContainer2.innerHTML).toBe(
291
+ '<div>portal2[0]:a</div><div>portal2[1]:a</div>',
292
+ );
293
+ expect(container.innerHTML).toBe(
294
+ '<div>normal[0]:a</div><div>normal[1]:a</div>',
295
+ );
296
+ expect(ops).toEqual([
297
+ 'normal[0]:a componentDidMount',
298
+ 'portal1[0]:a componentDidMount',
299
+ 'normal[1]:a componentDidMount',
300
+ 'portal2[0]:a componentDidMount',
301
+ 'portal2[1]:a componentDidMount',
302
+ 'Parent:a componentDidMount',
303
+ ]);
304
+
305
+ ops.length = 0;
306
+ ReactDOM.render(<Parent step="b" />, container);
307
+ expect(portalContainer1.innerHTML).toBe('<div>portal1[0]:b</div>');
308
+ expect(portalContainer2.innerHTML).toBe(
309
+ '<div>portal2[0]:b</div><div>portal2[1]:b</div>',
310
+ );
311
+ expect(container.innerHTML).toBe(
312
+ '<div>normal[0]:b</div><div>normal[1]:b</div>',
313
+ );
314
+ expect(ops).toEqual([
315
+ 'normal[0]:b componentDidUpdate',
316
+ 'portal1[0]:b componentDidUpdate',
317
+ 'normal[1]:b componentDidUpdate',
318
+ 'portal2[0]:b componentDidUpdate',
319
+ 'portal2[1]:b componentDidUpdate',
320
+ 'Parent:b componentDidUpdate',
321
+ ]);
322
+
323
+ ops.length = 0;
324
+ ReactDOM.unmountComponentAtNode(container);
325
+ expect(portalContainer1.innerHTML).toBe('');
326
+ expect(portalContainer2.innerHTML).toBe('');
327
+ expect(container.innerHTML).toBe('');
328
+ expect(ops).toEqual([
329
+ 'Parent:b componentWillUnmount',
330
+ 'normal[0]:b componentWillUnmount',
331
+ 'portal1[0]:b componentWillUnmount',
332
+ 'normal[1]:b componentWillUnmount',
333
+ 'portal2[0]:b componentWillUnmount',
334
+ 'portal2[1]:b componentWillUnmount',
335
+ ]);
336
+ });
337
385
- it('should reconcile portal children', () => {
386
- var portalContainer = document.createElement('div');
338
+ it('should render nested portals', () => {
339
+ var portalContainer1 = document.createElement('div');
340
+ var portalContainer2 = document.createElement('div');
341
+ var portalContainer3 = document.createElement('div');
342
+
343
+ ReactDOM.render(
344
+ [
345
+ <div key="a">normal[0]</div>,
346
+ ReactDOM.createPortal(
347
+ [
348
+ <div key="b">portal1[0]</div>,
349
+ ReactDOM.createPortal(
350
+ <div key="c">portal2[0]</div>,
351
+ portalContainer2,
352
+ ),
353
+ ReactDOM.createPortal(
354
+ <div key="d">portal3[0]</div>,
355
+ portalContainer3,
356
+ ),
357
+ <div key="e">portal1[1]</div>,
358
+ ],
359
+ portalContainer1,
360
+ ),
361
+ <div key="f">normal[1]</div>,
362
+ ],
363
+ container,
364
+ );
365
+ expect(portalContainer1.innerHTML).toBe(
366
+ '<div>portal1[0]</div><div>portal1[1]</div>',
367
+ );
368
+ expect(portalContainer2.innerHTML).toBe('<div>portal2[0]</div>');
369
+ expect(portalContainer3.innerHTML).toBe('<div>portal3[0]</div>');
370
+ expect(container.innerHTML).toBe(
371
+ '<div>normal[0]</div><div>normal[1]</div>',
372
+ );
373
+
374
+ ReactDOM.unmountComponentAtNode(container);
375
+ expect(portalContainer1.innerHTML).toBe('');
376
+ expect(portalContainer2.innerHTML).toBe('');
377
+ expect(portalContainer3.innerHTML).toBe('');
378
+ expect(container.innerHTML).toBe('');
379
+ });
380
388
- ReactDOM.render(
389
- <div>
390
- {ReactDOM.createPortal(<div>portal:1</div>, portalContainer)}
391
- </div>,
392
- container,
393
- );
394
- expect(portalContainer.innerHTML).toBe('<div>portal:1</div>');
395
- expect(container.innerHTML).toBe('<div></div>');
396
-
397
- ReactDOM.render(
398
- <div>
399
- {ReactDOM.createPortal(<div>portal:2</div>, portalContainer)}
400
- </div>,
401
- container,
402
- );
403
- expect(portalContainer.innerHTML).toBe('<div>portal:2</div>');
404
- expect(container.innerHTML).toBe('<div></div>');
405
-
406
- ReactDOM.render(
407
- <div>
408
- {ReactDOM.createPortal(<p>portal:3</p>, portalContainer)}
409
- </div>,
410
- container,
411
- );
412
- expect(portalContainer.innerHTML).toBe('<p>portal:3</p>');
413
- expect(container.innerHTML).toBe('<div></div>');
414
-
415
- ReactDOM.render(
416
- <div>
417
- {ReactDOM.createPortal(['Hi', 'Bye'], portalContainer)}
418
- </div>,
419
- container,
420
- );
421
- expect(portalContainer.innerHTML).toBe('HiBye');
422
- expect(container.innerHTML).toBe('<div></div>');
423
-
424
- ReactDOM.render(
425
- <div>
426
- {ReactDOM.createPortal(['Bye', 'Hi'], portalContainer)}
427
- </div>,
428
- container,
429
- );
430
- expect(portalContainer.innerHTML).toBe('ByeHi');
431
- expect(container.innerHTML).toBe('<div></div>');
432
-
433
- ReactDOM.render(
434
- <div>
435
- {ReactDOM.createPortal(null, portalContainer)}
436
- </div>,
437
- container,
438
- );
439
- expect(portalContainer.innerHTML).toBe('');
440
- expect(container.innerHTML).toBe('<div></div>');
441
- });
381
+ it('should reconcile portal children', () => {
382
+ var portalContainer = document.createElement('div');
383
+
384
+ ReactDOM.render(
385
+ <div>
386
+ {ReactDOM.createPortal(<div>portal:1</div>, portalContainer)}
387
+ </div>,
388
+ container,
389
+ );
390
+ expect(portalContainer.innerHTML).toBe('<div>portal:1</div>');
391
+ expect(container.innerHTML).toBe('<div></div>');
392
+
393
+ ReactDOM.render(
394
+ <div>
395
+ {ReactDOM.createPortal(<div>portal:2</div>, portalContainer)}
396
+ </div>,
397
+ container,
398
+ );
399
+ expect(portalContainer.innerHTML).toBe('<div>portal:2</div>');
400
+ expect(container.innerHTML).toBe('<div></div>');
401
+
402
+ ReactDOM.render(
403
+ <div>
404
+ {ReactDOM.createPortal(<p>portal:3</p>, portalContainer)}
405
+ </div>,
406
+ container,
407
+ );
408
+ expect(portalContainer.innerHTML).toBe('<p>portal:3</p>');
409
+ expect(container.innerHTML).toBe('<div></div>');
410
+
411
+ ReactDOM.render(
412
+ <div>
413
+ {ReactDOM.createPortal(['Hi', 'Bye'], portalContainer)}
414
+ </div>,
415
+ container,
416
+ );
417
+ expect(portalContainer.innerHTML).toBe('HiBye');
418
+ expect(container.innerHTML).toBe('<div></div>');
419
+
420
+ ReactDOM.render(
421
+ <div>
422
+ {ReactDOM.createPortal(['Bye', 'Hi'], portalContainer)}
423
+ </div>,
424
+ container,
425
+ );
426
+ expect(portalContainer.innerHTML).toBe('ByeHi');
427
+ expect(container.innerHTML).toBe('<div></div>');
428
+
429
+ ReactDOM.render(
430
+ <div>
431
+ {ReactDOM.createPortal(null, portalContainer)}
432
+ </div>,
433
+ container,
434
+ );
435
+ expect(portalContainer.innerHTML).toBe('');
436
+ expect(container.innerHTML).toBe('<div></div>');
437
+ });
438
443
- it('should keep track of namespace across portals (simple)', () => {
444
- assertNamespacesMatch(
445
- <svg {...expectSVG}>
446
- <image {...expectSVG} />
447
- {usePortal(<div {...expectHTML} />)}
448
- <image {...expectSVG} />
449
- </svg>,
450
- );
451
- assertNamespacesMatch(
452
- <math {...expectMath}>
453
- <mi {...expectMath} />
454
- {usePortal(<div {...expectHTML} />)}
455
- <mi {...expectMath} />
456
- </math>,
457
- );
458
- assertNamespacesMatch(
459
- <div {...expectHTML}>
460
- <p {...expectHTML} />
461
- {usePortal(
462
- <svg {...expectSVG}>
463
- <image {...expectSVG} />
464
- </svg>,
465
- )}
466
- <p {...expectHTML} />
467
- </div>,
468
- );
469
- });
439
+ it('should keep track of namespace across portals (simple)', () => {
440
+ assertNamespacesMatch(
441
+ <svg {...expectSVG}>
442
+ <image {...expectSVG} />
443
+ {usePortal(<div {...expectHTML} />)}
444
+ <image {...expectSVG} />
445
+ </svg>,
446
+ );
447
+ assertNamespacesMatch(
448
+ <math {...expectMath}>
449
+ <mi {...expectMath} />
450
+ {usePortal(<div {...expectHTML} />)}
451
+ <mi {...expectMath} />
452
+ </math>,
453
+ );
454
+ assertNamespacesMatch(
455
+ <div {...expectHTML}>
456
+ <p {...expectHTML} />
457
+ {usePortal(
458
+ <svg {...expectSVG}>
459
+ <image {...expectSVG} />
460
+ </svg>,
461
+ )}
462
+ <p {...expectHTML} />
463
+ </div>,
464
+ );
465
+ });
466
471
- it('should keep track of namespace across portals (medium)', () => {
472
- assertNamespacesMatch(
473
- <svg {...expectSVG}>
474
- <image {...expectSVG} />
475
- {usePortal(<div {...expectHTML} />)}
476
- <image {...expectSVG} />
477
- {usePortal(<div {...expectHTML} />)}
478
- <image {...expectSVG} />
479
- </svg>,
480
- );
481
- assertNamespacesMatch(
482
- <div {...expectHTML}>
483
- <math {...expectMath}>
484
- <mi {...expectMath} />
485
- {usePortal(
486
- <svg {...expectSVG}>
487
- <image {...expectSVG} />
488
- </svg>,
489
- )}
490
- </math>
491
- <p {...expectHTML} />
492
- </div>,
493
- );
494
- assertNamespacesMatch(
467
+ it('should keep track of namespace across portals (medium)', () => {
468
+ assertNamespacesMatch(
469
+ <svg {...expectSVG}>
470
+ <image {...expectSVG} />
471
+ {usePortal(<div {...expectHTML} />)}
472
+ <image {...expectSVG} />
473
+ {usePortal(<div {...expectHTML} />)}
474
+ <image {...expectSVG} />
475
+ </svg>,
476
+ );
477
+ assertNamespacesMatch(
478
+ <div {...expectHTML}>
479
<math {...expectMath}>
480
<mi {...expectMath} />
481
{usePortal(
482
<svg {...expectSVG}>
483
<image {...expectSVG} />
500
- <foreignObject {...expectSVG}>
501
- <p {...expectHTML} />
502
- <math {...expectMath}>
503
- <mi {...expectMath} />
504
- </math>
505
- <p {...expectHTML} />
506
- </foreignObject>
507
- <image {...expectSVG} />
508
- </svg>,
509
- )}
510
- <mi {...expectMath} />
511
- </math>,
512
- );
513
- assertNamespacesMatch(
514
- <div {...expectHTML}>
515
- {usePortal(
516
- <svg {...expectSVG}>
517
- {usePortal(<div {...expectHTML} />)}
518
- <image {...expectSVG} />
484
</svg>,
485
)}
521
- <p {...expectHTML} />
522
- </div>,
523
- );
524
- assertNamespacesMatch(
525
- <svg {...expectSVG}>
486
+ </math>
487
+ <p {...expectHTML} />
488
+ </div>,
489
+ );
490
+ assertNamespacesMatch(
491
+ <math {...expectMath}>
492
+ <mi {...expectMath} />
493
+ {usePortal(
494
+ <svg {...expectSVG}>
495
+ <image {...expectSVG} />
496
+ <foreignObject {...expectSVG}>
497
+ <p {...expectHTML} />
498
+ <math {...expectMath}>
499
+ <mi {...expectMath} />
500
+ </math>
501
+ <p {...expectHTML} />
502
+ </foreignObject>
503
+ <image {...expectSVG} />
504
+ </svg>,
505
+ )}
506
+ <mi {...expectMath} />
507
+ </math>,
508
+ );
509
+ assertNamespacesMatch(
510
+ <div {...expectHTML}>
511
+ {usePortal(
512
<svg {...expectSVG}>
513
{usePortal(<div {...expectHTML} />)}
514
<image {...expectSVG} />
529
- </svg>
515
+ </svg>,
516
+ )}
517
+ <p {...expectHTML} />
518
+ </div>,
519
+ );
520
+ assertNamespacesMatch(
521
+ <svg {...expectSVG}>
522
+ <svg {...expectSVG}>
523
+ {usePortal(<div {...expectHTML} />)}
524
<image {...expectSVG} />
531
- </svg>,
532
- );
533
- });
525
+ </svg>
526
+ <image {...expectSVG} />
527
+ </svg>,
528
+ );
529
+ });
530
535
- it('should keep track of namespace across portals (complex)', () => {
536
- assertNamespacesMatch(
537
- <div {...expectHTML}>
538
- {usePortal(
539
- <svg {...expectSVG}>
540
- <image {...expectSVG} />
541
- </svg>,
542
- )}
543
- <p {...expectHTML} />
531
+ it('should keep track of namespace across portals (complex)', () => {
532
+ assertNamespacesMatch(
533
+ <div {...expectHTML}>
534
+ {usePortal(
535
<svg {...expectSVG}>
536
<image {...expectSVG} />
546
- </svg>
537
+ </svg>,
538
+ )}
539
+ <p {...expectHTML} />
540
+ <svg {...expectSVG}>
541
+ <image {...expectSVG} />
542
+ </svg>
543
+ <svg {...expectSVG}>
544
<svg {...expectSVG}>
548
- <svg {...expectSVG}>
549
- <image {...expectSVG} />
550
- </svg>
545
<image {...expectSVG} />
546
</svg>
553
- <p {...expectHTML} />
554
- </div>,
555
- );
556
- assertNamespacesMatch(
557
- <div {...expectHTML}>
547
+ <image {...expectSVG} />
548
+ </svg>
549
+ <p {...expectHTML} />
550
+ </div>,
551
+ );
552
+ assertNamespacesMatch(
553
+ <div {...expectHTML}>
554
+ <svg {...expectSVG}>
555
<svg {...expectSVG}>
559
- <svg {...expectSVG}>
560
- <image {...expectSVG} />
561
- {usePortal(
556
+ <image {...expectSVG} />
557
+ {usePortal(
558
+ <svg {...expectSVG}>
559
+ <image {...expectSVG} />
560
<svg {...expectSVG}>
561
<image {...expectSVG} />
564
- <svg {...expectSVG}>
565
- <image {...expectSVG} />
566
- </svg>
567
- <image {...expectSVG} />
568
- </svg>,
569
- )}
570
- <image {...expectSVG} />
571
- <foreignObject {...expectSVG}>
572
- <p {...expectHTML} />
573
- {usePortal(<p {...expectHTML} />)}
574
- <p {...expectHTML} />
575
- </foreignObject>
576
- </svg>
562
+ </svg>
563
+ <image {...expectSVG} />
564
+ </svg>,
565
+ )}
566
<image {...expectSVG} />
578
- </svg>
579
- <p {...expectHTML} />
580
- </div>,
581
- );
582
- assertNamespacesMatch(
583
- <div {...expectHTML}>
584
- <svg {...expectSVG}>
567
<foreignObject {...expectSVG}>
568
<p {...expectHTML} />
587
- {usePortal(
588
- <svg {...expectSVG}>
589
- <image {...expectSVG} />
590
- <svg {...expectSVG}>
591
- <image {...expectSVG} />
592
- <foreignObject {...expectSVG}>
593
- <p {...expectHTML} />
594
- </foreignObject>
595
- {usePortal(<p {...expectHTML} />)}
596
- </svg>
597
- <image {...expectSVG} />
598
- </svg>,
599
- )}
569
+ {usePortal(<p {...expectHTML} />)}
570
<p {...expectHTML} />
571
</foreignObject>
602
- <image {...expectSVG} />
572
</svg>
604
- <p {...expectHTML} />
605
- </div>,
606
- );
607
- });
608
-
609
- it('should unwind namespaces on uncaught errors', () => {
610
- function BrokenRender() {
611
- throw new Error('Hello');
612
- }
613
-
614
- expect(() => {
615
- assertNamespacesMatch(
616
- <svg {...expectSVG}>
617
- <BrokenRender />
618
- </svg>,
619
- );
620
- }).toThrow('Hello');
621
- assertNamespacesMatch(<div {...expectHTML} />);
622
- });
623
-
624
- it('should unwind namespaces on caught errors', () => {
625
- function BrokenRender() {
626
- throw new Error('Hello');
627
- }
628
-
629
- class ErrorBoundary extends React.Component {
630
- state = {error: null};
631
- componentDidCatch(error) {
632
- this.setState({error});
633
- }
634
- render() {
635
- if (this.state.error) {
636
- return <p {...expectHTML} />;
637
- }
638
- return this.props.children;
639
- }
640
- }
641
-
642
- assertNamespacesMatch(
573
+ <image {...expectSVG} />
574
+ </svg>
575
+ <p {...expectHTML} />
576
+ </div>,
577
+ );
578
+ assertNamespacesMatch(
579
+ <div {...expectHTML}>
580
<svg {...expectSVG}>
581
<foreignObject {...expectSVG}>
645
- <ErrorBoundary>
646
- <math {...expectMath}>
647
- <BrokenRender />
648
- </math>
649
- </ErrorBoundary>
582
+ <p {...expectHTML} />
583
+ {usePortal(
584
+ <svg {...expectSVG}>
585
+ <image {...expectSVG} />
586
+ <svg {...expectSVG}>
587
+ <image {...expectSVG} />
588
+ <foreignObject {...expectSVG}>
589
+ <p {...expectHTML} />
590
+ </foreignObject>
591
+ {usePortal(<p {...expectHTML} />)}
592
+ </svg>
593
+ <image {...expectSVG} />
594
+ </svg>,
595
+ )}
596
+ <p {...expectHTML} />
597
</foreignObject>
598
<image {...expectSVG} />
652
- </svg>,
653
- );
654
- assertNamespacesMatch(<div {...expectHTML} />);
655
- });
656
-
657
- it('should unwind namespaces on caught errors in a portal', () => {
658
- function BrokenRender() {
659
- throw new Error('Hello');
660
- }
599
+ </svg>
600
+ <p {...expectHTML} />
601
+ </div>,
602
+ );
603
+ });
604
662
- class ErrorBoundary extends React.Component {
663
- state = {error: null};
664
- componentDidCatch(error) {
665
- this.setState({error});
666
- }
667
- render() {
668
- if (this.state.error) {
669
- return <image {...expectSVG} />;
670
- }
671
- return this.props.children;
672
- }
673
- }
605
+ it('should unwind namespaces on uncaught errors', () => {
606
+ function BrokenRender() {
607
+ throw new Error('Hello');
608
+ }
609
610
+ expect(() => {
611
assertNamespacesMatch(
612
<svg {...expectSVG}>
677
- <ErrorBoundary>
678
- {usePortal(
679
- <div {...expectHTML}>
680
- <math {...expectMath}>
681
- <BrokenRender />)
682
- </math>
683
- </div>,
684
- )}
685
- </ErrorBoundary>
686
- {usePortal(<div {...expectHTML} />)}
613
+ <BrokenRender />
614
</svg>,
615
);
689
- });
690
-
691
- it('should pass portal context when rendering subtree elsewhere', () => {
692
- var portalContainer = document.createElement('div');
616
+ }).toThrow('Hello');
617
+ assertNamespacesMatch(<div {...expectHTML} />);
618
+ });
619
694
- class Component extends React.Component {
695
- static contextTypes = {
696
- foo: PropTypes.string.isRequired,
697
- };
620
+ it('should unwind namespaces on caught errors', () => {
621
+ function BrokenRender() {
622
+ throw new Error('Hello');
623
+ }
624
699
- render() {
700
- return <div>{this.context.foo}</div>;
625
+ class ErrorBoundary extends React.Component {
626
+ state = {error: null};
627
+ componentDidCatch(error) {
628
+ this.setState({error});
629
+ }
630
+ render() {
631
+ if (this.state.error) {
632
+ return <p {...expectHTML} />;
633
}
634
+ return this.props.children;
635
}
636
+ }
637
704
- class Parent extends React.Component {
705
- static childContextTypes = {
706
- foo: PropTypes.string.isRequired,
707
- };
638
+ assertNamespacesMatch(
639
+ <svg {...expectSVG}>
640
+ <foreignObject {...expectSVG}>
641
+ <ErrorBoundary>
642
+ <math {...expectMath}>
643
+ <BrokenRender />
644
+ </math>
645
+ </ErrorBoundary>
646
+ </foreignObject>
647
+ <image {...expectSVG} />
648
+ </svg>,
649
+ );
650
+ assertNamespacesMatch(<div {...expectHTML} />);
651
+ });
652
709
- getChildContext() {
710
- return {
711
- foo: 'bar',
712
- };
713
- }
653
+ it('should unwind namespaces on caught errors in a portal', () => {
654
+ function BrokenRender() {
655
+ throw new Error('Hello');
656
+ }
657
715
- render() {
716
- return ReactDOM.createPortal(<Component />, portalContainer);
658
+ class ErrorBoundary extends React.Component {
659
+ state = {error: null};
660
+ componentDidCatch(error) {
661
+ this.setState({error});
662
+ }
663
+ render() {
664
+ if (this.state.error) {
665
+ return <image {...expectSVG} />;
666
}
667
+ return this.props.children;
668
}
669
+ }
670
720
- ReactDOM.render(<Parent />, container);
721
- expect(container.innerHTML).toBe('');
722
- expect(portalContainer.innerHTML).toBe('<div>bar</div>');
723
- });
671
+ assertNamespacesMatch(
672
+ <svg {...expectSVG}>
673
+ <ErrorBoundary>
674
+ {usePortal(
675
+ <div {...expectHTML}>
676
+ <math {...expectMath}>
677
+ <BrokenRender />)
678
+ </math>
679
+ </div>,
680
+ )}
681
+ </ErrorBoundary>
682
+ {usePortal(<div {...expectHTML} />)}
683
+ </svg>,
684
+ );
685
+ });
686
725
- it('should update portal context if it changes due to setState', () => {
726
- var portalContainer = document.createElement('div');
687
+ it('should pass portal context when rendering subtree elsewhere', () => {
688
+ var portalContainer = document.createElement('div');
689
728
- class Component extends React.Component {
729
- static contextTypes = {
730
- foo: PropTypes.string.isRequired,
731
- getFoo: PropTypes.func.isRequired,
732
- };
690
+ class Component extends React.Component {
691
+ static contextTypes = {
692
+ foo: PropTypes.string.isRequired,
693
+ };
694
734
- render() {
735
- return <div>{this.context.foo + '-' + this.context.getFoo()}</div>;
736
- }
695
+ render() {
696
+ return <div>{this.context.foo}</div>;
697
}
698
+ }
699
739
- class Parent extends React.Component {
740
- static childContextTypes = {
741
- foo: PropTypes.string.isRequired,
742
- getFoo: PropTypes.func.isRequired,
743
- };
700
+ class Parent extends React.Component {
701
+ static childContextTypes = {
702
+ foo: PropTypes.string.isRequired,
703
+ };
704
745
- state = {
746
- bar: 'initial',
705
+ getChildContext() {
706
+ return {
707
+ foo: 'bar',
708
};
709
+ }
710
749
- getChildContext() {
750
- return {
751
- foo: this.state.bar,
752
- getFoo: () => this.state.bar,
753
- };
754
- }
755
-
756
- render() {
757
- return ReactDOM.createPortal(<Component />, portalContainer);
758
- }
711
+ render() {
712
+ return ReactDOM.createPortal(<Component />, portalContainer);
713
}
714
+ }
715
761
- var instance = ReactDOM.render(<Parent />, container);
762
- expect(portalContainer.innerHTML).toBe('<div>initial-initial</div>');
763
- expect(container.innerHTML).toBe('');
764
- instance.setState({bar: 'changed'});
765
- expect(portalContainer.innerHTML).toBe('<div>changed-changed</div>');
766
- expect(container.innerHTML).toBe('');
767
- });
716
+ ReactDOM.render(<Parent />, container);
717
+ expect(container.innerHTML).toBe('');
718
+ expect(portalContainer.innerHTML).toBe('<div>bar</div>');
719
+ });
720
769
- it('should update portal context if it changes due to re-render', () => {
770
- var portalContainer = document.createElement('div');
721
+ it('should update portal context if it changes due to setState', () => {
722
+ var portalContainer = document.createElement('div');
723
772
- class Component extends React.Component {
773
- static contextTypes = {
774
- foo: PropTypes.string.isRequired,
775
- getFoo: PropTypes.func.isRequired,
776
- };
724
+ class Component extends React.Component {
725
+ static contextTypes = {
726
+ foo: PropTypes.string.isRequired,
727
+ getFoo: PropTypes.func.isRequired,
728
+ };
729
778
- render() {
779
- return <div>{this.context.foo + '-' + this.context.getFoo()}</div>;
780
- }
730
+ render() {
731
+ return <div>{this.context.foo + '-' + this.context.getFoo()}</div>;
732
}
733
+ }
734
783
- class Parent extends React.Component {
784
- static childContextTypes = {
785
- foo: PropTypes.string.isRequired,
786
- getFoo: PropTypes.func.isRequired,
787
- };
735
+ class Parent extends React.Component {
736
+ static childContextTypes = {
737
+ foo: PropTypes.string.isRequired,
738
+ getFoo: PropTypes.func.isRequired,
739
+ };
740
789
- getChildContext() {
790
- return {
791
- foo: this.props.bar,
792
- getFoo: () => this.props.bar,
793
- };
794
- }
741
+ state = {
742
+ bar: 'initial',
743
+ };
744
796
- render() {
797
- return ReactDOM.createPortal(<Component />, portalContainer);
798
- }
745
+ getChildContext() {
746
+ return {
747
+ foo: this.state.bar,
748
+ getFoo: () => this.state.bar,
749
+ };
750
}
751
801
- ReactDOM.render(<Parent bar="initial" />, container);
802
- expect(portalContainer.innerHTML).toBe('<div>initial-initial</div>');
803
- expect(container.innerHTML).toBe('');
804
- ReactDOM.render(<Parent bar="changed" />, container);
805
- expect(portalContainer.innerHTML).toBe('<div>changed-changed</div>');
806
- expect(container.innerHTML).toBe('');
807
- });
808
-
809
- it('findDOMNode should find dom element after expanding a fragment', () => {
810
- class MyNode extends React.Component {
811
- render() {
812
- return !this.props.flag
813
- ? [<div key="a" />]
814
- : [<span key="b" />, <div key="a" />];
815
- }
752
+ render() {
753
+ return ReactDOM.createPortal(<Component />, portalContainer);
754
}
755
+ }
756
818
- var myNodeA = ReactDOM.render(<MyNode />, container);
819
- var a = ReactDOM.findDOMNode(myNodeA);
820
- expect(a.tagName).toBe('DIV');
757
+ var instance = ReactDOM.render(<Parent />, container);
758
+ expect(portalContainer.innerHTML).toBe('<div>initial-initial</div>');
759
+ expect(container.innerHTML).toBe('');
760
+ instance.setState({bar: 'changed'});
761
+ expect(portalContainer.innerHTML).toBe('<div>changed-changed</div>');
762
+ expect(container.innerHTML).toBe('');
763
+ });
764
822
- var myNodeB = ReactDOM.render(<MyNode flag={true} />, container);
823
- expect(myNodeA === myNodeB).toBe(true);
765
+ it('should update portal context if it changes due to re-render', () => {
766
+ var portalContainer = document.createElement('div');
767
825
- var b = ReactDOM.findDOMNode(myNodeB);
826
- expect(b.tagName).toBe('SPAN');
827
- });
768
+ class Component extends React.Component {
769
+ static contextTypes = {
770
+ foo: PropTypes.string.isRequired,
771
+ getFoo: PropTypes.func.isRequired,
772
+ };
773
829
- it('should bubble events from the portal to the parent', () => {
830
- var portalContainer = document.createElement('div');
774
+ render() {
775
+ return <div>{this.context.foo + '-' + this.context.getFoo()}</div>;
776
+ }
777
+ }
778
832
- var ops = [];
833
- var portal = null;
779
+ class Parent extends React.Component {
780
+ static childContextTypes = {
781
+ foo: PropTypes.string.isRequired,
782
+ getFoo: PropTypes.func.isRequired,
783
+ };
784
835
- ReactDOM.render(
836
- <div onClick={() => ops.push('parent clicked')}>
837
- {ReactDOM.createPortal(
838
- <div
839
- onClick={() => ops.push('portal clicked')}
840
- ref={n => (portal = n)}>
841
- portal
842
- </div>,
843
- portalContainer,
844
- )}
845
- </div>,
846
- container,
847
- );
785
+ getChildContext() {
786
+ return {
787
+ foo: this.props.bar,
788
+ getFoo: () => this.props.bar,
789
+ };
790
+ }
791
849
- expect(portal.tagName).toBe('DIV');
792
+ render() {
793
+ return ReactDOM.createPortal(<Component />, portalContainer);
794
+ }
795
+ }
796
851
- var fakeNativeEvent = {};
852
- ReactTestUtils.simulateNativeEventOnNode(
853
- 'topClick',
854
- portal,
855
- fakeNativeEvent,
856
- );
797
+ ReactDOM.render(<Parent bar="initial" />, container);
798
+ expect(portalContainer.innerHTML).toBe('<div>initial-initial</div>');
799
+ expect(container.innerHTML).toBe('');
800
+ ReactDOM.render(<Parent bar="changed" />, container);
801
+ expect(portalContainer.innerHTML).toBe('<div>changed-changed</div>');
802
+ expect(container.innerHTML).toBe('');
803
+ });
804
858
- expect(ops).toEqual(['portal clicked', 'parent clicked']);
859
- });
805
+ it('findDOMNode should find dom element after expanding a fragment', () => {
806
+ class MyNode extends React.Component {
807
+ render() {
808
+ return !this.props.flag
809
+ ? [<div key="a" />]
810
+ : [<span key="b" />, <div key="a" />];
811
+ }
812
+ }
813
861
- it('should not onMouseLeave when staying in the portal', () => {
862
- var portalContainer = document.createElement('div');
814
+ var myNodeA = ReactDOM.render(<MyNode />, container);
815
+ var a = ReactDOM.findDOMNode(myNodeA);
816
+ expect(a.tagName).toBe('DIV');
817
864
- var ops = [];
865
- var firstTarget = null;
866
- var secondTarget = null;
867
- var thirdTarget = null;
818
+ var myNodeB = ReactDOM.render(<MyNode flag={true} />, container);
819
+ expect(myNodeA === myNodeB).toBe(true);
820
869
- function simulateMouseMove(from, to) {
870
- if (from) {
871
- ReactTestUtils.simulateNativeEventOnNode('topMouseOut', from, {
872
- target: from,
873
- relatedTarget: to,
874
- });
875
- }
876
- if (to) {
877
- ReactTestUtils.simulateNativeEventOnNode('topMouseOver', to, {
878
- target: to,
879
- relatedTarget: from,
880
- });
881
- }
882
- }
821
+ var b = ReactDOM.findDOMNode(myNodeB);
822
+ expect(b.tagName).toBe('SPAN');
823
+ });
824
884
- ReactDOM.render(
885
- <div>
886
- <div
887
- onMouseEnter={() => ops.push('enter parent')}
888
- onMouseLeave={() => ops.push('leave parent')}>
889
- <div ref={n => (firstTarget = n)} />
890
- {ReactDOM.createPortal(
891
- <div
892
- onMouseEnter={() => ops.push('enter portal')}
893
- onMouseLeave={() => ops.push('leave portal')}
894
- ref={n => (secondTarget = n)}>
895
- portal
896
- </div>,
897
- portalContainer,
898
- )}
899
- </div>
900
- <div ref={n => (thirdTarget = n)} />
901
- </div>,
902
- container,
903
- );
825
+ it('should bubble events from the portal to the parent', () => {
826
+ var portalContainer = document.createElement('div');
827
905
- simulateMouseMove(null, firstTarget);
906
- expect(ops).toEqual(['enter parent']);
828
+ var ops = [];
829
+ var portal = null;
830
908
- ops = [];
831
+ ReactDOM.render(
832
+ <div onClick={() => ops.push('parent clicked')}>
833
+ {ReactDOM.createPortal(
834
+ <div
835
+ onClick={() => ops.push('portal clicked')}
836
+ ref={n => (portal = n)}>
837
+ portal
838
+ </div>,
839
+ portalContainer,
840
+ )}
841
+ </div>,
842
+ container,
843
+ );
844
+
845
+ expect(portal.tagName).toBe('DIV');
846
+
847
+ var fakeNativeEvent = {};
848
+ ReactTestUtils.simulateNativeEventOnNode(
849
+ 'topClick',
850
+ portal,
851
+ fakeNativeEvent,
852
+ );
853
+
854
+ expect(ops).toEqual(['portal clicked', 'parent clicked']);
855
+ });
856
910
- simulateMouseMove(firstTarget, secondTarget);
911
- expect(ops).toEqual([
912
- // Parent did not invoke leave because we're still inside the portal.
913
- 'enter portal',
914
- ]);
857
+ it('should not onMouseLeave when staying in the portal', () => {
858
+ var portalContainer = document.createElement('div');
859
916
- ops = [];
860
+ var ops = [];
861
+ var firstTarget = null;
862
+ var secondTarget = null;
863
+ var thirdTarget = null;
864
918
- simulateMouseMove(secondTarget, thirdTarget);
919
- expect(ops).toEqual([
920
- 'leave portal',
921
- 'leave parent', // Only when we leave the portal does onMouseLeave fire.
922
- ]);
923
- });
865
+ function simulateMouseMove(from, to) {
866
+ if (from) {
867
+ ReactTestUtils.simulateNativeEventOnNode('topMouseOut', from, {
868
+ target: from,
869
+ relatedTarget: to,
870
+ });
871
+ }
872
+ if (to) {
873
+ ReactTestUtils.simulateNativeEventOnNode('topMouseOver', to, {
874
+ target: to,
875
+ relatedTarget: from,
876
+ });
877
+ }
878
+ }
879
925
- it('should throw on bad createPortal argument', () => {
926
- expect(() => {
927
- ReactDOM.createPortal(<div>portal</div>, null);
928
- }).toThrow('Target container is not a DOM element.');
929
- expect(() => {
930
- ReactDOM.createPortal(<div>portal</div>, document.createTextNode('hi'));
931
- }).toThrow('Target container is not a DOM element.');
932
- });
880
+ ReactDOM.render(
881
+ <div>
882
+ <div
883
+ onMouseEnter={() => ops.push('enter parent')}
884
+ onMouseLeave={() => ops.push('leave parent')}>
885
+ <div ref={n => (firstTarget = n)} />
886
+ {ReactDOM.createPortal(
887
+ <div
888
+ onMouseEnter={() => ops.push('enter portal')}
889
+ onMouseLeave={() => ops.push('leave portal')}
890
+ ref={n => (secondTarget = n)}>
891
+ portal
892
+ </div>,
893
+ portalContainer,
894
+ )}
895
+ </div>
896
+ <div ref={n => (thirdTarget = n)} />
897
+ </div>,
898
+ container,
899
+ );
900
+
901
+ simulateMouseMove(null, firstTarget);
902
+ expect(ops).toEqual(['enter parent']);
903
+
904
+ ops = [];
905
+
906
+ simulateMouseMove(firstTarget, secondTarget);
907
+ expect(ops).toEqual([
908
+ // Parent did not invoke leave because we're still inside the portal.
909
+ 'enter portal',
910
+ ]);
911
+
912
+ ops = [];
913
+
914
+ simulateMouseMove(secondTarget, thirdTarget);
915
+ expect(ops).toEqual([
916
+ 'leave portal',
917
+ 'leave parent', // Only when we leave the portal does onMouseLeave fire.
918
+ ]);
919
+ });
920
934
- it('should warn for non-functional event listeners', () => {
935
- spyOn(console, 'error');
936
- class Example extends React.Component {
937
- render() {
938
- return <div onClick="woops" />;
939
- }
921
+ it('should throw on bad createPortal argument', () => {
922
+ expect(() => {
923
+ ReactDOM.createPortal(<div>portal</div>, null);
924
+ }).toThrow('Target container is not a DOM element.');
925
+ expect(() => {
926
+ ReactDOM.createPortal(<div>portal</div>, document.createTextNode('hi'));
927
+ }).toThrow('Target container is not a DOM element.');
928
+ });
929
+
930
+ it('should warn for non-functional event listeners', () => {
931
+ spyOn(console, 'error');
932
+ class Example extends React.Component {
933
+ render() {
934
+ return <div onClick="woops" />;
935
}
941
- ReactDOM.render(<Example />, container);
942
- expectDev(console.error.calls.count()).toBe(1);
943
- expectDev(
944
- normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
945
- ).toContain(
946
- 'Expected `onClick` listener to be a function, instead got a value of `string` type.\n' +
947
- ' in div (at **)\n' +
948
- ' in Example (at **)',
949
- );
950
- });
936
+ }
937
+ ReactDOM.render(<Example />, container);
938
+ expectDev(console.error.calls.count()).toBe(1);
939
+ expectDev(
940
+ normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
941
+ ).toContain(
942
+ 'Expected `onClick` listener to be a function, instead got a value of `string` type.\n' +
943
+ ' in div (at **)\n' +
944
+ ' in Example (at **)',
945
+ );
946
+ });
947
952
- it('should not update event handlers until commit', () => {
953
- let ops = [];
954
- const handlerA = () => ops.push('A');
955
- const handlerB = () => ops.push('B');
948
+ it('should not update event handlers until commit', () => {
949
+ let ops = [];
950
+ const handlerA = () => ops.push('A');
951
+ const handlerB = () => ops.push('B');
952
957
- class Example extends React.Component {
958
- state = {flip: false, count: 0};
959
- flip() {
960
- this.setState({flip: true, count: this.state.count + 1});
961
- }
962
- tick() {
963
- this.setState({count: this.state.count + 1});
964
- }
965
- render() {
966
- const useB = !this.props.forceA && this.state.flip;
967
- return <div onClick={useB ? handlerB : handlerA} />;
968
- }
953
+ class Example extends React.Component {
954
+ state = {flip: false, count: 0};
955
+ flip() {
956
+ this.setState({flip: true, count: this.state.count + 1});
957
}
970
-
971
- class Click extends React.Component {
972
- constructor() {
973
- super();
974
- click(node);
975
- }
976
- render() {
977
- return null;
978
- }
958
+ tick() {
959
+ this.setState({count: this.state.count + 1});
960
}
961
+ render() {
962
+ const useB = !this.props.forceA && this.state.flip;
963
+ return <div onClick={useB ? handlerB : handlerA} />;
964
+ }
965
+ }
966
981
- let inst;
982
- ReactDOM.render([<Example key="a" ref={n => (inst = n)} />], container);
983
- const node = container.firstChild;
984
- expect(node.tagName).toEqual('DIV');
985
-
986
- function click(target) {
987
- var fakeNativeEvent = {};
988
- ReactTestUtils.simulateNativeEventOnNode(
989
- 'topClick',
990
- target,
991
- fakeNativeEvent,
992
- );
967
+ class Click extends React.Component {
968
+ constructor() {
969
+ super();
970
+ click(node);
971
}
972
+ render() {
973
+ return null;
974
+ }
975
+ }
976
995
- click(node);
977
+ let inst;
978
+ ReactDOM.render([<Example key="a" ref={n => (inst = n)} />], container);
979
+ const node = container.firstChild;
980
+ expect(node.tagName).toEqual('DIV');
981
997
- expect(ops).toEqual(['A']);
998
- ops = [];
982
+ function click(target) {
983
+ var fakeNativeEvent = {};
984
+ ReactTestUtils.simulateNativeEventOnNode(
985
+ 'topClick',
986
+ target,
987
+ fakeNativeEvent,
988
+ );
989
+ }
990
1000
- // Render with the other event handler.
1001
- inst.flip();
991
+ click(node);
992
1003
- click(node);
993
+ expect(ops).toEqual(['A']);
994
+ ops = [];
995
1005
- expect(ops).toEqual(['B']);
1006
- ops = [];
996
+ // Render with the other event handler.
997
+ inst.flip();
998
1008
- // Rerender without changing any props.
1009
- inst.tick();
999
+ click(node);
1000
1011
- click(node);
1001
+ expect(ops).toEqual(['B']);
1002
+ ops = [];
1003
1013
- expect(ops).toEqual(['B']);
1014
- ops = [];
1004
+ // Rerender without changing any props.
1005
+ inst.tick();
1006
1016
- // Render a flip back to the A handler. The second component invokes the
1017
- // click handler during render to simulate a click during an aborted
1018
- // render. I use this hack because at current time we don't have a way to
1019
- // test aborted ReactDOM renders.
1020
- ReactDOM.render(
1021
- [<Example key="a" forceA={true} />, <Click key="b" />],
1022
- container,
1023
- );
1007
+ click(node);
1008
1025
- // Because the new click handler has not yet committed, we should still
1026
- // invoke B.
1027
- expect(ops).toEqual(['B']);
1028
- ops = [];
1009
+ expect(ops).toEqual(['B']);
1010
+ ops = [];
1011
1030
- // Any click that happens after commit, should invoke A.
1031
- click(node);
1032
- expect(ops).toEqual(['A']);
1033
- });
1012
+ // Render a flip back to the A handler. The second component invokes the
1013
+ // click handler during render to simulate a click during an aborted
1014
+ // render. I use this hack because at current time we don't have a way to
1015
+ // test aborted ReactDOM renders.
1016
+ ReactDOM.render(
1017
+ [<Example key="a" forceA={true} />, <Click key="b" />],
1018
+ container,
1019
+ );
1020
1035
- it('should not crash encountering low-priority tree', () => {
1036
- ReactDOM.render(
1037
- <div hidden={true}>
1038
- <div />
1039
- </div>,
1040
- container,
1041
- );
1042
- });
1021
+ // Because the new click handler has not yet committed, we should still
1022
+ // invoke B.
1023
+ expect(ops).toEqual(['B']);
1024
+ ops = [];
1025
1044
- it('should not warn when rendering into an empty container', () => {
1045
- spyOn(console, 'error');
1046
- ReactDOM.render(<div>foo</div>, container);
1047
- expect(container.innerHTML).toBe('<div>foo</div>');
1048
- ReactDOM.render(null, container);
1049
- expect(container.innerHTML).toBe('');
1050
- expectDev(console.error.calls.count()).toBe(0);
1051
- ReactDOM.render(<div>bar</div>, container);
1052
- expect(container.innerHTML).toBe('<div>bar</div>');
1053
- expectDev(console.error.calls.count()).toBe(0);
1054
- });
1026
+ // Any click that happens after commit, should invoke A.
1027
+ click(node);
1028
+ expect(ops).toEqual(['A']);
1029
+ });
1030
1056
- it('should warn when replacing a container which was manually updated outside of React', () => {
1057
- spyOn(console, 'error');
1058
- // when not messing with the DOM outside of React
1059
- ReactDOM.render(<div key="1">foo</div>, container);
1060
- ReactDOM.render(<div key="1">bar</div>, container);
1061
- expect(container.innerHTML).toBe('<div>bar</div>');
1062
- // then we mess with the DOM before an update
1063
- // we know this will error - that is expected right now
1064
- // It's an error of type 'NotFoundError' with no message
1065
- expect(() => {
1066
- container.innerHTML = '<div>MEOW.</div>';
1067
- ReactDOM.render(<div key="2">baz</div>, container);
1068
- }).toThrowError();
1069
- expectDev(console.error.calls.count()).toBe(1);
1070
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
1071
- 'render(...): ' +
1072
- 'It looks like the React-rendered content of this container was ' +
1073
- 'removed without using React. This is not supported and will ' +
1074
- 'cause errors. Instead, call ReactDOM.unmountComponentAtNode ' +
1075
- 'to empty a container.',
1076
- );
1077
- });
1031
+ it('should not crash encountering low-priority tree', () => {
1032
+ ReactDOM.render(
1033
+ <div hidden={true}>
1034
+ <div />
1035
+ </div>,
1036
+ container,
1037
+ );
1038
+ });
1039
1079
- it('should warn when doing an update to a container manually updated outside of React', () => {
1080
- spyOn(console, 'error');
1081
- // when not messing with the DOM outside of React
1082
- ReactDOM.render(<div>foo</div>, container);
1083
- ReactDOM.render(<div>bar</div>, container);
1084
- expect(container.innerHTML).toBe('<div>bar</div>');
1085
- // then we mess with the DOM before an update
1086
- container.innerHTML = '<div>MEOW.</div>';
1087
- ReactDOM.render(<div>baz</div>, container);
1088
- // silently fails to update
1089
- expectDev(console.error.calls.count()).toBe(1);
1090
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
1091
- 'render(...): ' +
1092
- 'It looks like the React-rendered content of this container was ' +
1093
- 'removed without using React. This is not supported and will ' +
1094
- 'cause errors. Instead, call ReactDOM.unmountComponentAtNode ' +
1095
- 'to empty a container.',
1096
- );
1097
- });
1040
+ it('should not warn when rendering into an empty container', () => {
1041
+ spyOn(console, 'error');
1042
+ ReactDOM.render(<div>foo</div>, container);
1043
+ expect(container.innerHTML).toBe('<div>foo</div>');
1044
+ ReactDOM.render(null, container);
1045
+ expect(container.innerHTML).toBe('');
1046
+ expectDev(console.error.calls.count()).toBe(0);
1047
+ ReactDOM.render(<div>bar</div>, container);
1048
+ expect(container.innerHTML).toBe('<div>bar</div>');
1049
+ expectDev(console.error.calls.count()).toBe(0);
1050
+ });
1051
1099
- it('should warn when doing an update to a container manually cleared outside of React', () => {
1100
- spyOn(console, 'error');
1101
- // when not messing with the DOM outside of React
1102
- ReactDOM.render(<div>foo</div>, container);
1103
- ReactDOM.render(<div>bar</div>, container);
1104
- expect(container.innerHTML).toBe('<div>bar</div>');
1105
- // then we mess with the DOM before an update
1106
- container.innerHTML = '';
1107
- ReactDOM.render(<div>baz</div>, container);
1108
- // silently fails to update
1109
- expectDev(console.error.calls.count()).toBe(1);
1110
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
1111
- 'render(...): ' +
1112
- 'It looks like the React-rendered content of this container was ' +
1113
- 'removed without using React. This is not supported and will ' +
1114
- 'cause errors. Instead, call ReactDOM.unmountComponentAtNode ' +
1115
- 'to empty a container.',
1116
- );
1117
- });
1052
+ it('should warn when replacing a container which was manually updated outside of React', () => {
1053
+ spyOn(console, 'error');
1054
+ // when not messing with the DOM outside of React
1055
+ ReactDOM.render(<div key="1">foo</div>, container);
1056
+ ReactDOM.render(<div key="1">bar</div>, container);
1057
+ expect(container.innerHTML).toBe('<div>bar</div>');
1058
+ // then we mess with the DOM before an update
1059
+ // we know this will error - that is expected right now
1060
+ // It's an error of type 'NotFoundError' with no message
1061
+ expect(() => {
1062
+ container.innerHTML = '<div>MEOW.</div>';
1063
+ ReactDOM.render(<div key="2">baz</div>, container);
1064
+ }).toThrowError();
1065
+ expectDev(console.error.calls.count()).toBe(1);
1066
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
1067
+ 'render(...): ' +
1068
+ 'It looks like the React-rendered content of this container was ' +
1069
+ 'removed without using React. This is not supported and will ' +
1070
+ 'cause errors. Instead, call ReactDOM.unmountComponentAtNode ' +
1071
+ 'to empty a container.',
1072
+ );
1073
+ });
1074
1119
- it('should render a text component with a text DOM node on the same document as the container', () => {
1120
- // 1. Create a new document through the use of iframe
1121
- // 2. Set up the spy to make asserts when a text component
1122
- // is rendered inside the iframe container
1123
- var textContent = 'Hello world';
1124
- var iframe = document.createElement('iframe');
1125
- document.body.appendChild(iframe);
1126
- var iframeDocument = iframe.contentDocument;
1127
- iframeDocument.write(
1128
- '<!DOCTYPE html><html><head></head><body><div></div></body></html>',
1129
- );
1130
- iframeDocument.close();
1131
- var iframeContainer = iframeDocument.body.firstChild;
1075
+ it('should warn when doing an update to a container manually updated outside of React', () => {
1076
+ spyOn(console, 'error');
1077
+ // when not messing with the DOM outside of React
1078
+ ReactDOM.render(<div>foo</div>, container);
1079
+ ReactDOM.render(<div>bar</div>, container);
1080
+ expect(container.innerHTML).toBe('<div>bar</div>');
1081
+ // then we mess with the DOM before an update
1082
+ container.innerHTML = '<div>MEOW.</div>';
1083
+ ReactDOM.render(<div>baz</div>, container);
1084
+ // silently fails to update
1085
+ expectDev(console.error.calls.count()).toBe(1);
1086
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
1087
+ 'render(...): ' +
1088
+ 'It looks like the React-rendered content of this container was ' +
1089
+ 'removed without using React. This is not supported and will ' +
1090
+ 'cause errors. Instead, call ReactDOM.unmountComponentAtNode ' +
1091
+ 'to empty a container.',
1092
+ );
1093
+ });
1094
1133
- var actualDocument;
1134
- var textNode;
1095
+ it('should warn when doing an update to a container manually cleared outside of React', () => {
1096
+ spyOn(console, 'error');
1097
+ // when not messing with the DOM outside of React
1098
+ ReactDOM.render(<div>foo</div>, container);
1099
+ ReactDOM.render(<div>bar</div>, container);
1100
+ expect(container.innerHTML).toBe('<div>bar</div>');
1101
+ // then we mess with the DOM before an update
1102
+ container.innerHTML = '';
1103
+ ReactDOM.render(<div>baz</div>, container);
1104
+ // silently fails to update
1105
+ expectDev(console.error.calls.count()).toBe(1);
1106
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
1107
+ 'render(...): ' +
1108
+ 'It looks like the React-rendered content of this container was ' +
1109
+ 'removed without using React. This is not supported and will ' +
1110
+ 'cause errors. Instead, call ReactDOM.unmountComponentAtNode ' +
1111
+ 'to empty a container.',
1112
+ );
1113
+ });
1114
1136
- spyOn(iframeContainer, 'appendChild').and.callFake(node => {
1137
- actualDocument = node.ownerDocument;
1138
- textNode = node;
1139
- });
1115
+ it('should render a text component with a text DOM node on the same document as the container', () => {
1116
+ // 1. Create a new document through the use of iframe
1117
+ // 2. Set up the spy to make asserts when a text component
1118
+ // is rendered inside the iframe container
1119
+ var textContent = 'Hello world';
1120
+ var iframe = document.createElement('iframe');
1121
+ document.body.appendChild(iframe);
1122
+ var iframeDocument = iframe.contentDocument;
1123
+ iframeDocument.write(
1124
+ '<!DOCTYPE html><html><head></head><body><div></div></body></html>',
1125
+ );
1126
+ iframeDocument.close();
1127
+ var iframeContainer = iframeDocument.body.firstChild;
1128
+
1129
+ var actualDocument;
1130
+ var textNode;
1131
+
1132
+ spyOn(iframeContainer, 'appendChild').and.callFake(node => {
1133
+ actualDocument = node.ownerDocument;
1134
+ textNode = node;
1135
+ });
1136
1141
- ReactDOM.render(textContent, iframeContainer);
1137
+ ReactDOM.render(textContent, iframeContainer);
1138
1143
- expect(textNode.textContent).toBe(textContent);
1144
- expect(actualDocument).not.toBe(document);
1145
- expect(actualDocument).toBe(iframeDocument);
1146
- expect(iframeContainer.appendChild).toHaveBeenCalledTimes(1);
1147
- });
1148
- }
1139
+ expect(textNode.textContent).toBe(textContent);
1140
+ expect(actualDocument).not.toBe(document);
1141
+ expect(actualDocument).toBe(iframeDocument);
1142
+ expect(iframeContainer.appendChild).toHaveBeenCalledTimes(1);
1143
+ });
1144
});
src/renderers/dom/fiber/__tests__/ReactDOMFiberAsync-test.js
+222
-225
@@ -1,5 +1,4 @@
1
var React = require('react');
2
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
2
var ReactFeatureFlags = require('ReactFeatureFlags');
3
4
var ReactDOM;
@@ -25,270 +24,268 @@ describe('ReactDOMFiberAsync', () => {
24
expect(ops).toEqual(['Hi', 'Bye']);
25
});
26
28
- if (ReactDOMFeatureFlags.useFiber) {
29
- describe('with feature flag disabled', () => {
30
- beforeEach(() => {
31
- jest.resetModules();
32
- ReactFeatureFlags = require('ReactFeatureFlags');
33
- container = document.createElement('div');
34
- ReactFeatureFlags.enableAsyncSubtreeAPI = false;
35
- ReactDOM = require('react-dom');
36
- });
27
+ describe('with feature flag disabled', () => {
28
+ beforeEach(() => {
29
+ jest.resetModules();
30
+ ReactFeatureFlags = require('ReactFeatureFlags');
31
+ container = document.createElement('div');
32
+ ReactFeatureFlags.enableAsyncSubtreeAPI = false;
33
+ ReactDOM = require('react-dom');
34
+ });
35
38
- it('renders synchronously', () => {
39
- ReactDOM.render(
40
- <AsyncComponent><div>Hi</div></AsyncComponent>,
41
- container,
42
- );
43
- expect(container.textContent).toEqual('Hi');
44
-
45
- ReactDOM.render(
46
- <AsyncComponent><div>Bye</div></AsyncComponent>,
47
- container,
48
- );
49
- expect(container.textContent).toEqual('Bye');
50
- });
36
+ it('renders synchronously', () => {
37
+ ReactDOM.render(
38
+ <AsyncComponent><div>Hi</div></AsyncComponent>,
39
+ container,
40
+ );
41
+ expect(container.textContent).toEqual('Hi');
42
+
43
+ ReactDOM.render(
44
+ <AsyncComponent><div>Bye</div></AsyncComponent>,
45
+ container,
46
+ );
47
+ expect(container.textContent).toEqual('Bye');
48
});
49
+ });
50
53
- describe('with feature flag enabled', () => {
54
- beforeEach(() => {
55
- jest.resetModules();
56
- ReactFeatureFlags = require('ReactFeatureFlags');
57
- container = document.createElement('div');
58
- ReactFeatureFlags.enableAsyncSubtreeAPI = true;
59
- ReactDOM = require('react-dom');
60
- });
51
+ describe('with feature flag enabled', () => {
52
+ beforeEach(() => {
53
+ jest.resetModules();
54
+ ReactFeatureFlags = require('ReactFeatureFlags');
55
+ container = document.createElement('div');
56
+ ReactFeatureFlags.enableAsyncSubtreeAPI = true;
57
+ ReactDOM = require('react-dom');
58
+ });
59
62
- it('AsyncComponent at the root makes the entire tree async', () => {
63
- ReactDOM.render(
64
- <AsyncComponent><div>Hi</div></AsyncComponent>,
65
- container,
66
- );
67
- expect(container.textContent).toEqual('');
68
- jest.runAllTimers();
69
- expect(container.textContent).toEqual('Hi');
70
-
71
- ReactDOM.render(
72
- <AsyncComponent><div>Bye</div></AsyncComponent>,
73
- container,
74
- );
75
- expect(container.textContent).toEqual('Hi');
76
- jest.runAllTimers();
77
- expect(container.textContent).toEqual('Bye');
78
- });
60
+ it('AsyncComponent at the root makes the entire tree async', () => {
61
+ ReactDOM.render(
62
+ <AsyncComponent><div>Hi</div></AsyncComponent>,
63
+ container,
64
+ );
65
+ expect(container.textContent).toEqual('');
66
+ jest.runAllTimers();
67
+ expect(container.textContent).toEqual('Hi');
68
+
69
+ ReactDOM.render(
70
+ <AsyncComponent><div>Bye</div></AsyncComponent>,
71
+ container,
72
+ );
73
+ expect(container.textContent).toEqual('Hi');
74
+ jest.runAllTimers();
75
+ expect(container.textContent).toEqual('Bye');
76
+ });
77
80
- it('updates inside an async tree are async by default', () => {
81
- let instance;
82
- class Component extends React.Component {
83
- state = {step: 0};
84
- render() {
85
- instance = this;
86
- return <div>{this.state.step}</div>;
87
- }
78
+ it('updates inside an async tree are async by default', () => {
79
+ let instance;
80
+ class Component extends React.Component {
81
+ state = {step: 0};
82
+ render() {
83
+ instance = this;
84
+ return <div>{this.state.step}</div>;
85
}
86
+ }
87
+
88
+ ReactDOM.render(
89
+ <AsyncComponent><Component /></AsyncComponent>,
90
+ container,
91
+ );
92
+ expect(container.textContent).toEqual('');
93
+ jest.runAllTimers();
94
+ expect(container.textContent).toEqual('0');
95
+
96
+ instance.setState({step: 1});
97
+ expect(container.textContent).toEqual('0');
98
+ jest.runAllTimers();
99
+ expect(container.textContent).toEqual('1');
100
+ });
101
90
- ReactDOM.render(
91
- <AsyncComponent><Component /></AsyncComponent>,
92
- container,
93
- );
94
- expect(container.textContent).toEqual('');
95
- jest.runAllTimers();
96
- expect(container.textContent).toEqual('0');
97
-
98
- instance.setState({step: 1});
99
- expect(container.textContent).toEqual('0');
100
- jest.runAllTimers();
101
- expect(container.textContent).toEqual('1');
102
- });
103
-
104
- it('AsyncComponent creates an async subtree', () => {
105
- let instance;
106
- class Component extends React.unstable_AsyncComponent {
107
- state = {step: 0};
108
- render() {
109
- instance = this;
110
- return <div>{this.state.step}</div>;
111
- }
102
+ it('AsyncComponent creates an async subtree', () => {
103
+ let instance;
104
+ class Component extends React.unstable_AsyncComponent {
105
+ state = {step: 0};
106
+ render() {
107
+ instance = this;
108
+ return <div>{this.state.step}</div>;
109
}
110
+ }
111
114
- ReactDOM.render(<div><Component /></div>, container);
115
- jest.runAllTimers();
112
+ ReactDOM.render(<div><Component /></div>, container);
113
+ jest.runAllTimers();
114
117
- instance.setState({step: 1});
118
- expect(container.textContent).toEqual('0');
119
- jest.runAllTimers();
120
- expect(container.textContent).toEqual('1');
121
- });
115
+ instance.setState({step: 1});
116
+ expect(container.textContent).toEqual('0');
117
+ jest.runAllTimers();
118
+ expect(container.textContent).toEqual('1');
119
+ });
120
123
- it('updates inside an async subtree are async by default', () => {
124
- class Component extends React.unstable_AsyncComponent {
125
- render() {
126
- return <Child />;
127
- }
121
+ it('updates inside an async subtree are async by default', () => {
122
+ class Component extends React.unstable_AsyncComponent {
123
+ render() {
124
+ return <Child />;
125
}
129
-
130
- let instance;
131
- class Child extends React.Component {
132
- state = {step: 0};
133
- render() {
134
- instance = this;
135
- return <div>{this.state.step}</div>;
136
- }
126
+ }
127
+
128
+ let instance;
129
+ class Child extends React.Component {
130
+ state = {step: 0};
131
+ render() {
132
+ instance = this;
133
+ return <div>{this.state.step}</div>;
134
}
135
+ }
136
139
- ReactDOM.render(<div><Component /></div>, container);
140
- jest.runAllTimers();
137
+ ReactDOM.render(<div><Component /></div>, container);
138
+ jest.runAllTimers();
139
142
- instance.setState({step: 1});
143
- expect(container.textContent).toEqual('0');
144
- jest.runAllTimers();
145
- expect(container.textContent).toEqual('1');
146
- });
140
+ instance.setState({step: 1});
141
+ expect(container.textContent).toEqual('0');
142
+ jest.runAllTimers();
143
+ expect(container.textContent).toEqual('1');
144
+ });
145
148
- it('flushSync batches sync updates and flushes them at the end of the batch', () => {
149
- let ops = [];
150
- let instance;
151
-
152
- class Component extends React.Component {
153
- state = {text: ''};
154
- push(val) {
155
- this.setState(state => ({text: state.text + val}));
156
- }
157
- componentDidUpdate() {
158
- ops.push(this.state.text);
159
- }
160
- render() {
161
- instance = this;
162
- return <span>{this.state.text}</span>;
163
- }
146
+ it('flushSync batches sync updates and flushes them at the end of the batch', () => {
147
+ let ops = [];
148
+ let instance;
149
+
150
+ class Component extends React.Component {
151
+ state = {text: ''};
152
+ push(val) {
153
+ this.setState(state => ({text: state.text + val}));
154
+ }
155
+ componentDidUpdate() {
156
+ ops.push(this.state.text);
157
+ }
158
+ render() {
159
+ instance = this;
160
+ return <span>{this.state.text}</span>;
161
}
162
+ }
163
166
- ReactDOM.render(<Component />, container);
164
+ ReactDOM.render(<Component />, container);
165
168
- instance.push('A');
169
- expect(ops).toEqual(['A']);
170
- expect(container.textContent).toEqual('A');
166
+ instance.push('A');
167
+ expect(ops).toEqual(['A']);
168
+ expect(container.textContent).toEqual('A');
169
172
- ReactDOM.flushSync(() => {
173
- instance.push('B');
174
- instance.push('C');
175
- // Not flushed yet
176
- expect(container.textContent).toEqual('A');
177
- expect(ops).toEqual(['A']);
178
- });
179
- expect(container.textContent).toEqual('ABC');
180
- expect(ops).toEqual(['A', 'ABC']);
181
- instance.push('D');
182
- expect(container.textContent).toEqual('ABCD');
183
- expect(ops).toEqual(['A', 'ABC', 'ABCD']);
170
+ ReactDOM.flushSync(() => {
171
+ instance.push('B');
172
+ instance.push('C');
173
+ // Not flushed yet
174
+ expect(container.textContent).toEqual('A');
175
+ expect(ops).toEqual(['A']);
176
});
177
+ expect(container.textContent).toEqual('ABC');
178
+ expect(ops).toEqual(['A', 'ABC']);
179
+ instance.push('D');
180
+ expect(container.textContent).toEqual('ABCD');
181
+ expect(ops).toEqual(['A', 'ABC', 'ABCD']);
182
+ });
183
+
184
+ it('flushSync flushes updates even if nested inside another flushSync', () => {
185
+ let ops = [];
186
+ let instance;
187
186
- it('flushSync flushes updates even if nested inside another flushSync', () => {
187
- let ops = [];
188
- let instance;
189
-
190
- class Component extends React.Component {
191
- state = {text: ''};
192
- push(val) {
193
- this.setState(state => ({text: state.text + val}));
194
- }
195
- componentDidUpdate() {
196
- ops.push(this.state.text);
197
- }
198
- render() {
199
- instance = this;
200
- return <span>{this.state.text}</span>;
201
- }
188
+ class Component extends React.Component {
189
+ state = {text: ''};
190
+ push(val) {
191
+ this.setState(state => ({text: state.text + val}));
192
}
193
+ componentDidUpdate() {
194
+ ops.push(this.state.text);
195
+ }
196
+ render() {
197
+ instance = this;
198
+ return <span>{this.state.text}</span>;
199
+ }
200
+ }
201
204
- ReactDOM.render(<Component />, container);
202
+ ReactDOM.render(<Component />, container);
203
206
- instance.push('A');
207
- expect(ops).toEqual(['A']);
204
+ instance.push('A');
205
+ expect(ops).toEqual(['A']);
206
+ expect(container.textContent).toEqual('A');
207
+
208
+ ReactDOM.flushSync(() => {
209
+ instance.push('B');
210
+ instance.push('C');
211
+ // Not flushed yet
212
expect(container.textContent).toEqual('A');
213
+ expect(ops).toEqual(['A']);
214
215
ReactDOM.flushSync(() => {
211
- instance.push('B');
212
- instance.push('C');
213
- // Not flushed yet
214
- expect(container.textContent).toEqual('A');
215
- expect(ops).toEqual(['A']);
216
-
217
- ReactDOM.flushSync(() => {
218
- instance.push('D');
219
- });
220
- // The nested flushSync caused everything to flush.
221
- expect(container.textContent).toEqual('ABCD');
222
- expect(ops).toEqual(['A', 'ABCD']);
216
+ instance.push('D');
217
});
218
+ // The nested flushSync caused everything to flush.
219
expect(container.textContent).toEqual('ABCD');
220
expect(ops).toEqual(['A', 'ABCD']);
221
});
222
+ expect(container.textContent).toEqual('ABCD');
223
+ expect(ops).toEqual(['A', 'ABCD']);
224
+ });
225
228
- it('flushSync throws if already performing work', () => {
229
- class Component extends React.Component {
230
- componentDidUpdate() {
231
- ReactDOM.flushSync(() => {});
232
- }
233
- render() {
234
- return null;
235
- }
226
+ it('flushSync throws if already performing work', () => {
227
+ class Component extends React.Component {
228
+ componentDidUpdate() {
229
+ ReactDOM.flushSync(() => {});
230
}
231
+ render() {
232
+ return null;
233
+ }
234
+ }
235
+
236
+ // Initial mount
237
+ ReactDOM.render(<Component />, container);
238
+ // Update
239
+ expect(() => ReactDOM.render(<Component />, container)).toThrow(
240
+ 'flushSync was called from inside a lifecycle method',
241
+ );
242
+ });
243
238
- // Initial mount
239
- ReactDOM.render(<Component />, container);
240
- // Update
241
- expect(() => ReactDOM.render(<Component />, container)).toThrow(
242
- 'flushSync was called from inside a lifecycle method',
243
- );
244
- });
244
+ it('flushSync flushes updates before end of the tick', () => {
245
+ let ops = [];
246
+ let instance;
247
246
- it('flushSync flushes updates before end of the tick', () => {
247
- let ops = [];
248
- let instance;
249
-
250
- class Component extends React.unstable_AsyncComponent {
251
- state = {text: ''};
252
- push(val) {
253
- this.setState(state => ({text: state.text + val}));
254
- }
255
- componentDidUpdate() {
256
- ops.push(this.state.text);
257
- }
258
- render() {
259
- instance = this;
260
- return <span>{this.state.text}</span>;
261
- }
248
+ class Component extends React.unstable_AsyncComponent {
249
+ state = {text: ''};
250
+ push(val) {
251
+ this.setState(state => ({text: state.text + val}));
252
}
253
+ componentDidUpdate() {
254
+ ops.push(this.state.text);
255
+ }
256
+ render() {
257
+ instance = this;
258
+ return <span>{this.state.text}</span>;
259
+ }
260
+ }
261
264
- ReactDOM.render(<Component />, container);
265
- jest.runAllTimers();
262
+ ReactDOM.render(<Component />, container);
263
+ jest.runAllTimers();
264
267
- // Updates are async by default
268
- instance.push('A');
269
- expect(ops).toEqual([]);
270
- expect(container.textContent).toEqual('');
265
+ // Updates are async by default
266
+ instance.push('A');
267
+ expect(ops).toEqual([]);
268
+ expect(container.textContent).toEqual('');
269
272
- ReactDOM.flushSync(() => {
273
- instance.push('B');
274
- instance.push('C');
275
- // Not flushed yet
276
- expect(container.textContent).toEqual('');
277
- expect(ops).toEqual([]);
278
- });
279
- // Only the active updates have flushed
280
- expect(container.textContent).toEqual('BC');
281
- expect(ops).toEqual(['BC']);
282
-
283
- instance.push('D');
284
- expect(container.textContent).toEqual('BC');
285
- expect(ops).toEqual(['BC']);
286
-
287
- // Flush the async updates
288
- jest.runAllTimers();
289
- expect(container.textContent).toEqual('BCAD');
290
- expect(ops).toEqual(['BC', 'BCAD']);
270
+ ReactDOM.flushSync(() => {
271
+ instance.push('B');
272
+ instance.push('C');
273
+ // Not flushed yet
274
+ expect(container.textContent).toEqual('');
275
+ expect(ops).toEqual([]);
276
});
277
+ // Only the active updates have flushed
278
+ expect(container.textContent).toEqual('BC');
279
+ expect(ops).toEqual(['BC']);
280
+
281
+ instance.push('D');
282
+ expect(container.textContent).toEqual('BC');
283
+ expect(ops).toEqual(['BC']);
284
+
285
+ // Flush the async updates
286
+ jest.runAllTimers();
287
+ expect(container.textContent).toEqual('BCAD');
288
+ expect(ops).toEqual(['BC', 'BCAD']);
289
});
293
- }
290
+ });
291
});
src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
+74
-139
@@ -15,7 +15,6 @@ describe('ReactDOMComponent', () => {
15
var ReactDOM;
16
var ReactDOMServer;
17
var inputValueTracking;
18
- var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
18
19
function normalizeCodeLocInfo(str) {
20
return str && str.replace(/\(at .+?:\d+\)/g, '(at **)');
@@ -25,7 +24,6 @@ describe('ReactDOMComponent', () => {
24
jest.resetModules();
25
React = require('react');
26
ReactDOM = require('react-dom');
28
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
27
ReactDOMServer = require('react-dom/server');
28
ReactTestUtils = require('react-dom/test-utils');
29
// TODO: can we express this test with only public API?
@@ -940,9 +938,7 @@ describe('ReactDOMComponent', () => {
938
'<hasOwnProperty /> is using uppercase HTML',
939
);
940
expectDev(console.error.calls.argsFor(3)[0]).toContain(
943
- ReactDOMFeatureFlags.useFiber
944
- ? 'The tag <hasOwnProperty> is unrecognized in this browser'
945
- : 'The tag <hasownproperty> is unrecognized in this browser',
941
+ 'The tag <hasOwnProperty> is unrecognized in this browser',
942
);
943
});
944
@@ -1323,36 +1319,6 @@ describe('ReactDOMComponent', () => {
1319
});
1320
1321
describe('unmountComponent', () => {
1326
- // Fiber does not have a clean-up phase for host components; relies on GC
1327
- if (!ReactDOMFeatureFlags.useFiber) {
1328
- it('should clean up input value tracking', () => {
1329
- var container = document.createElement('div');
1330
- var node = ReactDOM.render(
1331
- <input type="text" defaultValue="foo" />,
1332
- container,
1333
- );
1334
- var tracker = inputValueTracking._getTrackerFromNode(node);
1335
-
1336
- spyOn(tracker, 'stopTracking');
1337
-
1338
- ReactDOM.unmountComponentAtNode(container);
1339
-
1340
- expect(tracker.stopTracking.calls.count()).toBe(1);
1341
- });
1342
-
1343
- it('should clean up input textarea tracking', () => {
1344
- var container = document.createElement('div');
1345
- var node = ReactDOM.render(<textarea defaultValue="foo" />, container);
1346
- var tracker = inputValueTracking._getTrackerFromNode(node);
1347
-
1348
- spyOn(tracker, 'stopTracking');
1349
-
1350
- ReactDOM.unmountComponentAtNode(container);
1351
-
1352
- expect(tracker.stopTracking.calls.count()).toBe(1);
1353
- });
1354
- }
1355
-
1322
it('unmounts children before unsetting DOM node info', () => {
1323
class Inner extends React.Component {
1324
render() {
@@ -1402,15 +1368,12 @@ describe('ReactDOMComponent', () => {
1368
spyOn(console, 'error');
1369
ReactTestUtils.renderIntoDocument(<div><tr /><tr /></div>);
1370
1405
- var addendum = ReactDOMFeatureFlags.useFiber
1406
- ? '\n in tr (at **)' + '\n in div (at **)'
1407
- : ' See div > tr.';
1408
-
1371
expectDev(console.error.calls.count()).toBe(1);
1372
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
1373
'Warning: validateDOMNesting(...): <tr> cannot appear as a child of ' +
1374
'<div>.' +
1413
- addendum,
1375
+ '\n in tr (at **)' +
1376
+ '\n in div (at **)',
1377
);
1378
});
1379
@@ -1419,16 +1382,13 @@ describe('ReactDOMComponent', () => {
1382
var p = document.createElement('p');
1383
ReactDOM.render(<span><p /></span>, p);
1384
1422
- var addendum = ReactDOMFeatureFlags.useFiber
1423
- ? // There is no outer `p` here because root container is not part of the stack.
1424
- '\n in p (at **)' + '\n in span (at **)'
1425
- : ' See p > ... > p.';
1426
-
1385
expectDev(console.error.calls.count()).toBe(1);
1386
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
1387
'Warning: validateDOMNesting(...): <p> cannot appear as a descendant ' +
1388
'of <p>.' +
1431
- addendum,
1389
+ // There is no outer `p` here because root container is not part of the stack.
1390
+ '\n in p (at **)' +
1391
+ '\n in span (at **)',
1392
);
1393
});
1394
@@ -1450,39 +1410,31 @@ describe('ReactDOMComponent', () => {
1410
ReactTestUtils.renderIntoDocument(<Foo />);
1411
expectDev(console.error.calls.count()).toBe(3);
1412
1453
- var addendum1 = ReactDOMFeatureFlags.useFiber
1454
- ? '\n in tr (at **)' +
1455
- '\n in Row (at **)' +
1456
- '\n in table (at **)' +
1457
- '\n in Foo (at **)'
1458
- : ' See Foo > table > Row > tr.';
1413
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(0)[0])).toBe(
1414
'Warning: validateDOMNesting(...): <tr> cannot appear as a child of ' +
1415
'<table>. Add a <tbody> to your code to match the DOM tree generated ' +
1416
'by the browser.' +
1463
- addendum1,
1417
+ '\n in tr (at **)' +
1418
+ '\n in Row (at **)' +
1419
+ '\n in table (at **)' +
1420
+ '\n in Foo (at **)',
1421
);
1422
1466
- var addendum2 = ReactDOMFeatureFlags.useFiber
1467
- ? '\n in tr (at **)' +
1468
- '\n in Row (at **)' +
1469
- '\n in table (at **)' +
1470
- '\n in Foo (at **)'
1471
- : ' See Row > tr > #text.';
1423
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(1)[0])).toBe(
1424
'Warning: validateDOMNesting(...): Text nodes cannot appear as a ' +
1425
'child of <tr>.' +
1475
- addendum2,
1426
+ '\n in tr (at **)' +
1427
+ '\n in Row (at **)' +
1428
+ '\n in table (at **)' +
1429
+ '\n in Foo (at **)',
1430
);
1431
1478
- var addendum3 = ReactDOMFeatureFlags.useFiber
1479
- ? '\n in table (at **)' + '\n in Foo (at **)'
1480
- : ' See Foo > table > #text.';
1432
expectDev(normalizeCodeLocInfo(console.error.calls.argsFor(2)[0])).toBe(
1433
'Warning: validateDOMNesting(...): Whitespace text nodes cannot ' +
1434
"appear as a child of <table>. Make sure you don't have any extra " +
1435
'whitespace between tags on each line of your source code.' +
1485
- addendum3,
1436
+ '\n in table (at **)' +
1437
+ '\n in Foo (at **)',
1438
);
1439
});
1440
@@ -1518,13 +1470,11 @@ describe('ReactDOMComponent', () => {
1470
expectDev(
1471
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
1472
).toContain(
1521
- ReactDOMFeatureFlags.useFiber
1522
- ? '\n in tr (at **)' +
1523
- '\n in Row (at **)' +
1524
- '\n in FancyRow (at **)' +
1525
- '\n in table (at **)' +
1526
- '\n in Viz1 (at **)'
1527
- : 'See Viz1 > table > FancyRow > Row > tr.',
1473
+ '\n in tr (at **)' +
1474
+ '\n in Row (at **)' +
1475
+ '\n in FancyRow (at **)' +
1476
+ '\n in table (at **)' +
1477
+ '\n in Viz1 (at **)',
1478
);
1479
1480
function Viz2() {
@@ -1538,15 +1488,13 @@ describe('ReactDOMComponent', () => {
1488
expectDev(
1489
normalizeCodeLocInfo(console.error.calls.argsFor(1)[0]),
1490
).toContain(
1541
- ReactDOMFeatureFlags.useFiber
1542
- ? '\n in tr (at **)' +
1543
- '\n in Row (at **)' +
1544
- '\n in FancyRow (at **)' +
1545
- '\n in table (at **)' +
1546
- '\n in Table (at **)' +
1547
- '\n in FancyTable (at **)' +
1548
- '\n in Viz2 (at **)'
1549
- : 'See Viz2 > FancyTable > Table > table > FancyRow > Row > tr.',
1491
+ '\n in tr (at **)' +
1492
+ '\n in Row (at **)' +
1493
+ '\n in FancyRow (at **)' +
1494
+ '\n in table (at **)' +
1495
+ '\n in Table (at **)' +
1496
+ '\n in FancyTable (at **)' +
1497
+ '\n in Viz2 (at **)',
1498
);
1499
1500
ReactTestUtils.renderIntoDocument(<FancyTable><FancyRow /></FancyTable>);
@@ -1554,14 +1502,12 @@ describe('ReactDOMComponent', () => {
1502
expectDev(
1503
normalizeCodeLocInfo(console.error.calls.argsFor(2)[0]),
1504
).toContain(
1557
- ReactDOMFeatureFlags.useFiber
1558
- ? '\n in tr (at **)' +
1559
- '\n in Row (at **)' +
1560
- '\n in FancyRow (at **)' +
1561
- '\n in table (at **)' +
1562
- '\n in Table (at **)' +
1563
- '\n in FancyTable (at **)'
1564
- : 'See FancyTable > Table > table > FancyRow > Row > tr.',
1505
+ '\n in tr (at **)' +
1506
+ '\n in Row (at **)' +
1507
+ '\n in FancyRow (at **)' +
1508
+ '\n in table (at **)' +
1509
+ '\n in Table (at **)' +
1510
+ '\n in FancyTable (at **)',
1511
);
1512
1513
ReactTestUtils.renderIntoDocument(<table><FancyRow /></table>);
@@ -1569,12 +1515,10 @@ describe('ReactDOMComponent', () => {
1515
expectDev(
1516
normalizeCodeLocInfo(console.error.calls.argsFor(3)[0]),
1517
).toContain(
1572
- ReactDOMFeatureFlags.useFiber
1573
- ? '\n in tr (at **)' +
1574
- '\n in Row (at **)' +
1575
- '\n in FancyRow (at **)' +
1576
- '\n in table (at **)'
1577
- : 'See table > FancyRow > Row > tr.',
1518
+ '\n in tr (at **)' +
1519
+ '\n in Row (at **)' +
1520
+ '\n in FancyRow (at **)' +
1521
+ '\n in table (at **)',
1522
);
1523
1524
ReactTestUtils.renderIntoDocument(<FancyTable><tr /></FancyTable>);
@@ -1582,12 +1526,10 @@ describe('ReactDOMComponent', () => {
1526
expectDev(
1527
normalizeCodeLocInfo(console.error.calls.argsFor(4)[0]),
1528
).toContain(
1585
- ReactDOMFeatureFlags.useFiber
1586
- ? '\n in tr (at **)' +
1587
- '\n in table (at **)' +
1588
- '\n in Table (at **)' +
1589
- '\n in FancyTable (at **)'
1590
- : 'See FancyTable > Table > table > tr.',
1529
+ '\n in tr (at **)' +
1530
+ '\n in table (at **)' +
1531
+ '\n in Table (at **)' +
1532
+ '\n in FancyTable (at **)',
1533
);
1534
1535
class Link extends React.Component {
@@ -1601,13 +1543,11 @@ describe('ReactDOMComponent', () => {
1543
expectDev(
1544
normalizeCodeLocInfo(console.error.calls.argsFor(5)[0]),
1545
).toContain(
1604
- ReactDOMFeatureFlags.useFiber
1605
- ? '\n in a (at **)' +
1606
- '\n in Link (at **)' +
1607
- '\n in div (at **)' +
1608
- '\n in a (at **)' +
1609
- '\n in Link (at **)'
1610
- : 'See Link > a > ... > Link > a.',
1546
+ '\n in a (at **)' +
1547
+ '\n in Link (at **)' +
1548
+ '\n in div (at **)' +
1549
+ '\n in a (at **)' +
1550
+ '\n in Link (at **)',
1551
);
1552
});
1553
@@ -2294,42 +2234,37 @@ describe('ReactDOMComponent', () => {
2234
});
2235
});
2236
2297
- if (ReactDOMFeatureFlags.useFiber) {
2298
- // This is currently broken (and has been broken for a while).
2299
- // We had a fix based on reading namespace, but it was too convoluted.
2300
- // TODO: a proper fix that would happen at the diffing stage.
2301
- describe('Hyphenated SVG elements', function() {
2302
- it('the font-face element is not a custom element', function() {
2303
- spyOn(console, 'error');
2304
- var el = ReactTestUtils.renderIntoDocument(
2305
- <svg><font-face x-height={false} /></svg>,
2306
- );
2237
+ describe('Hyphenated SVG elements', function() {
2238
+ it('the font-face element is not a custom element', function() {
2239
+ spyOn(console, 'error');
2240
+ var el = ReactTestUtils.renderIntoDocument(
2241
+ <svg><font-face x-height={false} /></svg>,
2242
+ );
2243
2308
- expect(el.querySelector('font-face').hasAttribute('x-height')).toBe(
2309
- false,
2310
- );
2244
+ expect(el.querySelector('font-face').hasAttribute('x-height')).toBe(
2245
+ false,
2246
+ );
2247
2312
- expectDev(console.error.calls.count()).toBe(1);
2313
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
2314
- 'Warning: Invalid DOM property `x-height`. Did you mean `xHeight`',
2315
- );
2316
- });
2248
+ expectDev(console.error.calls.count()).toBe(1);
2249
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
2250
+ 'Warning: Invalid DOM property `x-height`. Did you mean `xHeight`',
2251
+ );
2252
+ });
2253
2318
- it('the font-face element does not allow unknown boolean values', function() {
2319
- spyOn(console, 'error');
2320
- var el = ReactTestUtils.renderIntoDocument(
2321
- <svg><font-face whatever={false} /></svg>,
2322
- );
2254
+ it('the font-face element does not allow unknown boolean values', function() {
2255
+ spyOn(console, 'error');
2256
+ var el = ReactTestUtils.renderIntoDocument(
2257
+ <svg><font-face whatever={false} /></svg>,
2258
+ );
2259
2324
- expect(el.querySelector('font-face').hasAttribute('whatever')).toBe(
2325
- false,
2326
- );
2260
+ expect(el.querySelector('font-face').hasAttribute('whatever')).toBe(
2261
+ false,
2262
+ );
2263
2328
- expectDev(console.error.calls.count()).toBe(1);
2329
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
2330
- 'Warning: Received `false` for non-boolean attribute `whatever`.',
2331
- );
2332
- });
2264
+ expectDev(console.error.calls.count()).toBe(1);
2265
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
2266
+ 'Warning: Received `false` for non-boolean attribute `whatever`.',
2267
+ );
2268
});
2334
- }
2269
+ });
2270
});
src/renderers/dom/shared/__tests__/ReactDOMComponentTree-test.js
+1
-7
@@ -9,8 +9,6 @@
9
10
'use strict';
11
12
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
13
-
12
describe('ReactDOMComponentTree', () => {
13
var React;
14
var ReactDOM;
@@ -21,11 +19,7 @@ describe('ReactDOMComponentTree', () => {
19
var container = document.createElement('div');
20
// Force server-rendering path:
21
container.innerHTML = ReactDOMServer.renderToString(elt);
24
- if (ReactDOMFeatureFlags.useFiber) {
25
- return ReactDOM.hydrate(elt, container);
26
- } else {
27
- return ReactDOM.render(elt, container);
28
- }
22
+ return ReactDOM.hydrate(elt, container);
23
}
24
25
function getTypeOf(instance) {
src/renderers/dom/shared/__tests__/ReactDOMServerIntegration-test.js
+208
-379
@@ -9,8 +9,6 @@
9
10
'use strict';
11
12
-let ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
13
-
12
let ExecutionEnvironment;
13
let PropTypes;
14
let React;
@@ -21,7 +19,6 @@ let ReactTestUtils;
19
const stream = require('stream');
20
21
const TEXT_NODE_TYPE = 3;
24
-const COMMENT_NODE_TYPE = 8;
22
23
// Helper functions for rendering tests
24
// ====================================
@@ -29,7 +26,7 @@ const COMMENT_NODE_TYPE = 8;
26
// promisified version of ReactDOM.render()
27
function asyncReactDOMRender(reactElement, domElement, forceHydrate) {
28
return new Promise(resolve => {
32
- if (forceHydrate && ReactDOMFeatureFlags.useFiber) {
29
+ if (forceHydrate) {
30
ReactDOM.hydrate(reactElement, domElement);
31
} else {
32
ReactDOM.render(reactElement, domElement);
@@ -213,9 +210,7 @@ const clientRenderOnBadMarkup = async (element, errorCount = 0) => {
210
// as that will not work in the server string scenario.
211
function itRenders(desc, testFn) {
212
it(`renders ${desc} with server string render`, () => testFn(serverRender));
216
- if (ReactDOMFeatureFlags.useFiber) {
217
- it(`renders ${desc} with server stream render`, () => testFn(streamRender));
218
- }
213
+ it(`renders ${desc} with server stream render`, () => testFn(streamRender));
214
itClientRenders(desc, testFn);
215
}
216
@@ -324,7 +319,6 @@ function resetModules() {
319
PropTypes = require('prop-types');
320
React = require('react');
321
ReactDOM = require('react-dom');
327
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
322
ReactTestUtils = require('react-dom/test-utils');
323
324
// Now we reset the modules again to load the server renderer.
@@ -358,97 +352,95 @@ describe('ReactDOMServerIntegration', () => {
352
expect(e.firstChild.tagName).toBe('BR');
353
});
354
361
- if (ReactDOMFeatureFlags.useFiber) {
362
- itRenders('a string', async render => {
363
- let e = await render('Hello');
364
- expect(e.nodeType).toBe(3);
365
- expect(e.nodeValue).toMatch('Hello');
366
- });
355
+ itRenders('a string', async render => {
356
+ let e = await render('Hello');
357
+ expect(e.nodeType).toBe(3);
358
+ expect(e.nodeValue).toMatch('Hello');
359
+ });
360
368
- itRenders('a number', async render => {
369
- let e = await render(42);
370
- expect(e.nodeType).toBe(3);
371
- expect(e.nodeValue).toMatch('42');
372
- });
361
+ itRenders('a number', async render => {
362
+ let e = await render(42);
363
+ expect(e.nodeType).toBe(3);
364
+ expect(e.nodeValue).toMatch('42');
365
+ });
366
374
- itRenders('an array with one child', async render => {
375
- let e = await render([<div key={1}>text1</div>]);
376
- let parent = e.parentNode;
377
- expect(parent.childNodes[0].tagName).toBe('DIV');
378
- });
367
+ itRenders('an array with one child', async render => {
368
+ let e = await render([<div key={1}>text1</div>]);
369
+ let parent = e.parentNode;
370
+ expect(parent.childNodes[0].tagName).toBe('DIV');
371
+ });
372
380
- itRenders('an array with several children', async render => {
381
- let Header = props => {
382
- return <p>header</p>;
383
- };
384
- let Footer = props => {
385
- return [<h2 key={1}>footer</h2>, <h3 key={2}>about</h3>];
386
- };
387
- let e = await render([
388
- <div key={1}>text1</div>,
389
- <span key={2}>text2</span>,
390
- <Header key={3} />,
391
- <Footer key={4} />,
392
- ]);
393
- let parent = e.parentNode;
394
- expect(parent.childNodes[0].tagName).toBe('DIV');
395
- expect(parent.childNodes[1].tagName).toBe('SPAN');
396
- expect(parent.childNodes[2].tagName).toBe('P');
397
- expect(parent.childNodes[3].tagName).toBe('H2');
398
- expect(parent.childNodes[4].tagName).toBe('H3');
399
- });
400
-
401
- itRenders('a nested array', async render => {
402
- let e = await render([
403
- [<div key={1}>text1</div>],
404
- <span key={1}>text2</span>,
405
- [[[null, <p key={1} />], false]],
406
- ]);
407
- let parent = e.parentNode;
408
- expect(parent.childNodes[0].tagName).toBe('DIV');
409
- expect(parent.childNodes[1].tagName).toBe('SPAN');
410
- expect(parent.childNodes[2].tagName).toBe('P');
411
- });
412
-
413
- itRenders('an iterable', async render => {
414
- const threeDivIterable = {
415
- '@@iterator': function() {
416
- var i = 0;
417
- return {
418
- next: function() {
419
- if (i++ < 3) {
420
- return {value: <div key={i} />, done: false};
421
- } else {
422
- return {value: undefined, done: true};
423
- }
424
- },
425
- };
426
- },
427
- };
428
- let e = await render(threeDivIterable);
429
- let parent = e.parentNode;
430
- expect(parent.childNodes.length).toBe(3);
431
- expect(parent.childNodes[0].tagName).toBe('DIV');
432
- expect(parent.childNodes[1].tagName).toBe('DIV');
433
- expect(parent.childNodes[2].tagName).toBe('DIV');
434
- });
373
+ itRenders('an array with several children', async render => {
374
+ let Header = props => {
375
+ return <p>header</p>;
376
+ };
377
+ let Footer = props => {
378
+ return [<h2 key={1}>footer</h2>, <h3 key={2}>about</h3>];
379
+ };
380
+ let e = await render([
381
+ <div key={1}>text1</div>,
382
+ <span key={2}>text2</span>,
383
+ <Header key={3} />,
384
+ <Footer key={4} />,
385
+ ]);
386
+ let parent = e.parentNode;
387
+ expect(parent.childNodes[0].tagName).toBe('DIV');
388
+ expect(parent.childNodes[1].tagName).toBe('SPAN');
389
+ expect(parent.childNodes[2].tagName).toBe('P');
390
+ expect(parent.childNodes[3].tagName).toBe('H2');
391
+ expect(parent.childNodes[4].tagName).toBe('H3');
392
+ });
393
436
- itRenders('emptyish values', async render => {
437
- let e = await render(0);
438
- expect(e.nodeType).toBe(TEXT_NODE_TYPE);
439
- expect(e.nodeValue).toMatch('0');
394
+ itRenders('a nested array', async render => {
395
+ let e = await render([
396
+ [<div key={1}>text1</div>],
397
+ <span key={1}>text2</span>,
398
+ [[[null, <p key={1} />], false]],
399
+ ]);
400
+ let parent = e.parentNode;
401
+ expect(parent.childNodes[0].tagName).toBe('DIV');
402
+ expect(parent.childNodes[1].tagName).toBe('SPAN');
403
+ expect(parent.childNodes[2].tagName).toBe('P');
404
+ });
405
441
- // Empty string is special because client renders a node
442
- // but server returns empty HTML. So we compare parent text.
443
- expect((await render(<div>{''}</div>)).textContent).toBe('');
406
+ itRenders('an iterable', async render => {
407
+ const threeDivIterable = {
408
+ '@@iterator': function() {
409
+ var i = 0;
410
+ return {
411
+ next: function() {
412
+ if (i++ < 3) {
413
+ return {value: <div key={i} />, done: false};
414
+ } else {
415
+ return {value: undefined, done: true};
416
+ }
417
+ },
418
+ };
419
+ },
420
+ };
421
+ let e = await render(threeDivIterable);
422
+ let parent = e.parentNode;
423
+ expect(parent.childNodes.length).toBe(3);
424
+ expect(parent.childNodes[0].tagName).toBe('DIV');
425
+ expect(parent.childNodes[1].tagName).toBe('DIV');
426
+ expect(parent.childNodes[2].tagName).toBe('DIV');
427
+ });
428
445
- expect(await render([])).toBe(null);
446
- expect(await render(false)).toBe(null);
447
- expect(await render(true)).toBe(null);
448
- expect(await render(undefined)).toBe(null);
449
- expect(await render([[[false]], undefined])).toBe(null);
450
- });
451
- }
429
+ itRenders('emptyish values', async render => {
430
+ let e = await render(0);
431
+ expect(e.nodeType).toBe(TEXT_NODE_TYPE);
432
+ expect(e.nodeValue).toMatch('0');
433
+
434
+ // Empty string is special because client renders a node
435
+ // but server returns empty HTML. So we compare parent text.
436
+ expect((await render(<div>{''}</div>)).textContent).toBe('');
437
+
438
+ expect(await render([])).toBe(null);
439
+ expect(await render(false)).toBe(null);
440
+ expect(await render(true)).toBe(null);
441
+ expect(await render(undefined)).toBe(null);
442
+ expect(await render([[[false]], undefined])).toBe(null);
443
+ });
444
});
445
446
describe('property to attribute mapping', function() {
@@ -999,23 +991,7 @@ describe('ReactDOMServerIntegration', () => {
991
}
992
993
function expectTextNode(node, text) {
1002
- if (ReactDOMFeatureFlags.useFiber) {
1003
- // with Fiber, a React text node is just a DOM text node.
1004
- expectNode(node, TEXT_NODE_TYPE, text);
1005
- } else {
1006
- // with Stack, a React text node is a DOM text node surrounded by
1007
- // react-text comment nodes.
1008
- expectNode(node, COMMENT_NODE_TYPE, / react-text: [0-9]+ /);
1009
- if (text.length > 0) {
1010
- node = node.nextSibling;
1011
- expectNode(node, TEXT_NODE_TYPE, text);
1012
- }
1013
- expectNode(node.nextSibling, COMMENT_NODE_TYPE, / \/react-text /);
1014
- }
1015
- }
1016
-
1017
- function expectEmptyNode(node) {
1018
- expectNode(node, COMMENT_NODE_TYPE, / react-empty: [0-9]+ /);
994
+ expectNode(node, TEXT_NODE_TYPE, text);
995
}
996
997
describe('text children', function() {
@@ -1040,74 +1016,45 @@ describe('ReactDOMServerIntegration', () => {
1016
1017
itRenders('a div with multiple empty text children', async render => {
1018
const e = await render(<div>{''}{''}{''}</div>);
1043
- if (ReactDOMFeatureFlags.useFiber) {
1044
- // with Fiber, there are just three separate text node children,
1045
- // each of which is blank.
1046
- if (render === serverRender || render === streamRender) {
1047
- // For plain server markup result we should have no text nodes if
1048
- // they're all empty.
1049
- expect(e.childNodes.length).toBe(0);
1050
- expect(e.textContent).toBe('');
1051
- } else {
1052
- expect(e.childNodes.length).toBe(3);
1053
- expectTextNode(e.childNodes[0], '');
1054
- expectTextNode(e.childNodes[1], '');
1055
- expectTextNode(e.childNodes[2], '');
1056
- }
1019
+ if (render === serverRender || render === streamRender) {
1020
+ // For plain server markup result we should have no text nodes if
1021
+ // they're all empty.
1022
+ expect(e.childNodes.length).toBe(0);
1023
+ expect(e.textContent).toBe('');
1024
} else {
1058
- // with Stack, there are six react-text comment nodes.
1059
- expect(e.childNodes.length).toBe(6);
1025
+ expect(e.childNodes.length).toBe(3);
1026
expectTextNode(e.childNodes[0], '');
1027
+ expectTextNode(e.childNodes[1], '');
1028
expectTextNode(e.childNodes[2], '');
1062
- expectTextNode(e.childNodes[4], '');
1029
}
1030
});
1031
1032
itRenders('a div with multiple whitespace children', async render => {
1033
const e = await render(<div>{' '}{' '}{' '}</div>);
1068
- if (ReactDOMFeatureFlags.useFiber) {
1069
- // with Fiber, there are normally just three text nodes
1070
- if (
1071
- render === serverRender ||
1072
- render === clientRenderOnServerString ||
1073
- render === streamRender
1074
- ) {
1075
- // For plain server markup result we have comments between.
1076
- // If we're able to hydrate, they remain.
1077
- expect(e.childNodes.length).toBe(5);
1078
- expectTextNode(e.childNodes[0], ' ');
1079
- expectTextNode(e.childNodes[2], ' ');
1080
- expectTextNode(e.childNodes[4], ' ');
1081
- } else {
1082
- expect(e.childNodes.length).toBe(3);
1083
- expectTextNode(e.childNodes[0], ' ');
1084
- expectTextNode(e.childNodes[1], ' ');
1085
- expectTextNode(e.childNodes[2], ' ');
1086
- }
1034
+ if (
1035
+ render === serverRender ||
1036
+ render === clientRenderOnServerString ||
1037
+ render === streamRender
1038
+ ) {
1039
+ // For plain server markup result we have comments between.
1040
+ // If we're able to hydrate, they remain.
1041
+ expect(e.childNodes.length).toBe(5);
1042
+ expectTextNode(e.childNodes[0], ' ');
1043
+ expectTextNode(e.childNodes[2], ' ');
1044
+ expectTextNode(e.childNodes[4], ' ');
1045
} else {
1088
- // with Stack, each of the text nodes is surrounded by react-text
1089
- // comment nodes, making 9 nodes in total.
1090
- expect(e.childNodes.length).toBe(9);
1046
+ expect(e.childNodes.length).toBe(3);
1047
expectTextNode(e.childNodes[0], ' ');
1092
- expectTextNode(e.childNodes[3], ' ');
1093
- expectTextNode(e.childNodes[6], ' ');
1048
+ expectTextNode(e.childNodes[1], ' ');
1049
+ expectTextNode(e.childNodes[2], ' ');
1050
}
1051
});
1052
1053
itRenders('a div with text sibling to a node', async render => {
1054
const e = await render(<div>Text<span>More Text</span></div>);
1055
let spanNode;
1100
- if (ReactDOMFeatureFlags.useFiber) {
1101
- // with Fiber, there are only two children, the "Text" text node and
1102
- // the span element.
1103
- expect(e.childNodes.length).toBe(2);
1104
- spanNode = e.childNodes[1];
1105
- } else {
1106
- // with Stack, there are four children, a "Text" text node surrounded
1107
- // by react-text comment nodes, and the span element.
1108
- expect(e.childNodes.length).toBe(4);
1109
- spanNode = e.childNodes[3];
1110
- }
1056
+ expect(e.childNodes.length).toBe(2);
1057
+ spanNode = e.childNodes[1];
1058
expectTextNode(e.childNodes[0], 'Text');
1059
expect(spanNode.tagName).toBe('SPAN');
1060
expect(spanNode.childNodes.length).toBe(1);
@@ -1130,72 +1077,44 @@ describe('ReactDOMServerIntegration', () => {
1077
1078
itRenders('a leading blank child with a text sibling', async render => {
1079
const e = await render(<div>{''}foo</div>);
1133
- if (ReactDOMFeatureFlags.useFiber) {
1134
- // with Fiber, there are just two text nodes.
1135
- if (render === serverRender || render === streamRender) {
1136
- expect(e.childNodes.length).toBe(1);
1137
- expectTextNode(e.childNodes[0], 'foo');
1138
- } else {
1139
- expect(e.childNodes.length).toBe(2);
1140
- expectTextNode(e.childNodes[0], '');
1141
- expectTextNode(e.childNodes[1], 'foo');
1142
- }
1080
+ if (render === serverRender || render === streamRender) {
1081
+ expect(e.childNodes.length).toBe(1);
1082
+ expectTextNode(e.childNodes[0], 'foo');
1083
} else {
1144
- // with Stack, there are five nodes: two react-text comment nodes
1145
- // without any text between them, and the text node foo surrounded
1146
- // by react-text comment nodes.
1147
- expect(e.childNodes.length).toBe(5);
1084
+ expect(e.childNodes.length).toBe(2);
1085
expectTextNode(e.childNodes[0], '');
1149
- expectTextNode(e.childNodes[2], 'foo');
1086
+ expectTextNode(e.childNodes[1], 'foo');
1087
}
1088
});
1089
1090
itRenders('a trailing blank child with a text sibling', async render => {
1091
const e = await render(<div>foo{''}</div>);
1155
- if (ReactDOMFeatureFlags.useFiber) {
1156
- // with Fiber, there are just two text nodes.
1157
- if (render === serverRender || render === streamRender) {
1158
- expect(e.childNodes.length).toBe(1);
1159
- expectTextNode(e.childNodes[0], 'foo');
1160
- } else {
1161
- expect(e.childNodes.length).toBe(2);
1162
- expectTextNode(e.childNodes[0], 'foo');
1163
- expectTextNode(e.childNodes[1], '');
1164
- }
1092
+ // with Fiber, there are just two text nodes.
1093
+ if (render === serverRender || render === streamRender) {
1094
+ expect(e.childNodes.length).toBe(1);
1095
+ expectTextNode(e.childNodes[0], 'foo');
1096
} else {
1166
- // with Stack, there are five nodes: the text node foo surrounded
1167
- // by react-text comment nodes, and two react-text comment nodes
1168
- // without any text between them.
1169
- expect(e.childNodes.length).toBe(5);
1097
+ expect(e.childNodes.length).toBe(2);
1098
expectTextNode(e.childNodes[0], 'foo');
1171
- expectTextNode(e.childNodes[3], '');
1099
+ expectTextNode(e.childNodes[1], '');
1100
}
1101
});
1102
1103
itRenders('an element with two text children', async render => {
1104
const e = await render(<div>{'foo'}{'bar'}</div>);
1177
- if (ReactDOMFeatureFlags.useFiber) {
1178
- // with Fiber, there are just two text nodes.
1179
- if (
1180
- render === serverRender ||
1181
- render === clientRenderOnServerString ||
1182
- render === streamRender
1183
- ) {
1184
- // In the server render output there's a comment between them.
1185
- expect(e.childNodes.length).toBe(3);
1186
- expectTextNode(e.childNodes[0], 'foo');
1187
- expectTextNode(e.childNodes[2], 'bar');
1188
- } else {
1189
- expect(e.childNodes.length).toBe(2);
1190
- expectTextNode(e.childNodes[0], 'foo');
1191
- expectTextNode(e.childNodes[1], 'bar');
1192
- }
1105
+ if (
1106
+ render === serverRender ||
1107
+ render === clientRenderOnServerString ||
1108
+ render === streamRender
1109
+ ) {
1110
+ // In the server render output there's a comment between them.
1111
+ expect(e.childNodes.length).toBe(3);
1112
+ expectTextNode(e.childNodes[0], 'foo');
1113
+ expectTextNode(e.childNodes[2], 'bar');
1114
} else {
1194
- // with Stack, there are six nodes: two text nodes, each surrounded
1195
- // by react-text comment nodes.
1196
- expect(e.childNodes.length).toBe(6);
1115
+ expect(e.childNodes.length).toBe(2);
1116
expectTextNode(e.childNodes[0], 'foo');
1198
- expectTextNode(e.childNodes[3], 'bar');
1117
+ expectTextNode(e.childNodes[1], 'bar');
1118
}
1119
});
1120
});
@@ -1214,28 +1133,20 @@ describe('ReactDOMServerIntegration', () => {
1133
1134
itRenders('an element with number and text children', async render => {
1135
const e = await render(<div>{'foo'}{40}</div>);
1217
- if (ReactDOMFeatureFlags.useFiber) {
1218
- // with Fiber, there are just two text nodes.
1219
- if (
1220
- render === serverRender ||
1221
- render === clientRenderOnServerString ||
1222
- render === streamRender
1223
- ) {
1224
- // In the server markup there's a comment between.
1225
- expect(e.childNodes.length).toBe(3);
1226
- expectTextNode(e.childNodes[0], 'foo');
1227
- expectTextNode(e.childNodes[2], '40');
1228
- } else {
1229
- expect(e.childNodes.length).toBe(2);
1230
- expectTextNode(e.childNodes[0], 'foo');
1231
- expectTextNode(e.childNodes[1], '40');
1232
- }
1136
+ // with Fiber, there are just two text nodes.
1137
+ if (
1138
+ render === serverRender ||
1139
+ render === clientRenderOnServerString ||
1140
+ render === streamRender
1141
+ ) {
1142
+ // In the server markup there's a comment between.
1143
+ expect(e.childNodes.length).toBe(3);
1144
+ expectTextNode(e.childNodes[0], 'foo');
1145
+ expectTextNode(e.childNodes[2], '40');
1146
} else {
1234
- // with Stack, there are six nodes: two text nodes, each surrounded
1235
- // by react-text comment nodes.
1236
- expect(e.childNodes.length).toBe(6);
1147
+ expect(e.childNodes.length).toBe(2);
1148
expectTextNode(e.childNodes[0], 'foo');
1238
- expectTextNode(e.childNodes[3], '40');
1149
+ expectTextNode(e.childNodes[1], '40');
1150
}
1151
});
1152
});
@@ -1259,54 +1170,25 @@ describe('ReactDOMServerIntegration', () => {
1170
itRenders('a null component children as empty', async render => {
1171
const NullComponent = () => null;
1172
const e = await render(<div><NullComponent /></div>);
1262
- if (ReactDOMFeatureFlags.useFiber) {
1263
- // with Fiber, an empty component results in no markup.
1264
- expect(e.childNodes.length).toBe(0);
1265
- } else {
1266
- // with Stack, an empty component results in one react-empty comment
1267
- // node.
1268
- expect(e.childNodes.length).toBe(1);
1269
- expectEmptyNode(e.firstChild);
1270
- }
1173
+ expect(e.childNodes.length).toBe(0);
1174
});
1175
1176
itRenders('null children as blank', async render => {
1177
const e = await render(<div>{null}foo</div>);
1275
- if (ReactDOMFeatureFlags.useFiber) {
1276
- // with Fiber, there is just one text node.
1277
- expect(e.childNodes.length).toBe(1);
1278
- expectTextNode(e.childNodes[0], 'foo');
1279
- } else {
1280
- // with Stack, there's a text node surronded by react-text comment nodes.
1281
- expect(e.childNodes.length).toBe(3);
1282
- expectTextNode(e.childNodes[0], 'foo');
1283
- }
1178
+ expect(e.childNodes.length).toBe(1);
1179
+ expectTextNode(e.childNodes[0], 'foo');
1180
});
1181
1182
itRenders('false children as blank', async render => {
1183
const e = await render(<div>{false}foo</div>);
1288
- if (ReactDOMFeatureFlags.useFiber) {
1289
- // with Fiber, there is just one text node.
1290
- expect(e.childNodes.length).toBe(1);
1291
- expectTextNode(e.childNodes[0], 'foo');
1292
- } else {
1293
- // with Stack, there's a text node surronded by react-text comment nodes.
1294
- expect(e.childNodes.length).toBe(3);
1295
- expectTextNode(e.childNodes[0], 'foo');
1296
- }
1184
+ expect(e.childNodes.length).toBe(1);
1185
+ expectTextNode(e.childNodes[0], 'foo');
1186
});
1187
1188
itRenders('null and false children together as blank', async render => {
1189
const e = await render(<div>{false}{null}foo{null}{false}</div>);
1301
- if (ReactDOMFeatureFlags.useFiber) {
1302
- // with Fiber, there is just one text node.
1303
- expect(e.childNodes.length).toBe(1);
1304
- expectTextNode(e.childNodes[0], 'foo');
1305
- } else {
1306
- // with Stack, there's a text node surronded by react-text comment nodes.
1307
- expect(e.childNodes.length).toBe(3);
1308
- expectTextNode(e.childNodes[0], 'foo');
1309
- }
1190
+ expect(e.childNodes.length).toBe(1);
1191
+ expectTextNode(e.childNodes[0], 'foo');
1192
});
1193
1194
itRenders('only null and false children as blank', async render => {
@@ -1522,21 +1404,10 @@ describe('ReactDOMServerIntegration', () => {
1404
);
1405
expect(e.id).toBe('parent');
1406
let child1, child2, textNode;
1525
- if (ReactDOMFeatureFlags.useFiber) {
1526
- // with Fiber, there are three children: the child1 element, a
1527
- // single space text node, and the child2 element.
1528
- expect(e.childNodes.length).toBe(3);
1529
- child1 = e.childNodes[0];
1530
- textNode = e.childNodes[1];
1531
- child2 = e.childNodes[2];
1532
- } else {
1533
- // with Stack, there are five children: the child1 element, a single
1534
- // space surrounded by react-text comments, and the child2 element.
1535
- expect(e.childNodes.length).toBe(5);
1536
- child1 = e.childNodes[0];
1537
- textNode = e.childNodes[1];
1538
- child2 = e.childNodes[4];
1539
- }
1407
+ expect(e.childNodes.length).toBe(3);
1408
+ child1 = e.childNodes[0];
1409
+ textNode = e.childNodes[1];
1410
+ child2 = e.childNodes[2];
1411
expect(child1.id).toBe('child1');
1412
expect(child1.childNodes.length).toBe(0);
1413
expectTextNode(textNode, ' ');
@@ -1551,22 +1422,10 @@ describe('ReactDOMServerIntegration', () => {
1422
// prettier-ignore
1423
const e = await render(<div id="parent"> <div id="child" /> </div>); // eslint-disable-line no-multi-spaces
1424
let textNode1, child, textNode2;
1554
- if (ReactDOMFeatureFlags.useFiber) {
1555
- // with Fiber, there are three children: a one-space text node, the
1556
- // child element, and a two-space text node.
1557
- expect(e.childNodes.length).toBe(3);
1558
- textNode1 = e.childNodes[0];
1559
- child = e.childNodes[1];
1560
- textNode2 = e.childNodes[2];
1561
- } else {
1562
- // with Stack, there are 7 children: a one-space text node surrounded
1563
- // by react-text comments, the child element, and a two-space text node
1564
- // surrounded by react-text comments.
1565
- expect(e.childNodes.length).toBe(7);
1566
- textNode1 = e.childNodes[0];
1567
- child = e.childNodes[3];
1568
- textNode2 = e.childNodes[4];
1569
- }
1425
+ expect(e.childNodes.length).toBe(3);
1426
+ textNode1 = e.childNodes[0];
1427
+ child = e.childNodes[1];
1428
+ textNode2 = e.childNodes[2];
1429
expect(e.id).toBe('parent');
1430
expectTextNode(textNode1, ' ');
1431
expect(child.id).toBe('child');
@@ -1575,33 +1434,31 @@ describe('ReactDOMServerIntegration', () => {
1434
},
1435
);
1436
1578
- if (ReactDOMFeatureFlags.useFiber) {
1579
- itRenders('a composite with multiple children', async render => {
1580
- const Component = props => props.children;
1581
- const e = await render(
1582
- <Component>{['a', 'b', [undefined], [[false, 'c']]]}</Component>,
1583
- );
1437
+ itRenders('a composite with multiple children', async render => {
1438
+ const Component = props => props.children;
1439
+ const e = await render(
1440
+ <Component>{['a', 'b', [undefined], [[false, 'c']]]}</Component>,
1441
+ );
1442
1585
- let parent = e.parentNode;
1586
- if (
1587
- render === serverRender ||
1588
- render === clientRenderOnServerString ||
1589
- render === streamRender
1590
- ) {
1591
- // For plain server markup result we have comments between.
1592
- // If we're able to hydrate, they remain.
1593
- expect(parent.childNodes.length).toBe(5);
1594
- expectTextNode(parent.childNodes[0], 'a');
1595
- expectTextNode(parent.childNodes[2], 'b');
1596
- expectTextNode(parent.childNodes[4], 'c');
1597
- } else {
1598
- expect(parent.childNodes.length).toBe(3);
1599
- expectTextNode(parent.childNodes[0], 'a');
1600
- expectTextNode(parent.childNodes[1], 'b');
1601
- expectTextNode(parent.childNodes[2], 'c');
1602
- }
1603
- });
1604
- }
1443
+ let parent = e.parentNode;
1444
+ if (
1445
+ render === serverRender ||
1446
+ render === clientRenderOnServerString ||
1447
+ render === streamRender
1448
+ ) {
1449
+ // For plain server markup result we have comments between.
1450
+ // If we're able to hydrate, they remain.
1451
+ expect(parent.childNodes.length).toBe(5);
1452
+ expectTextNode(parent.childNodes[0], 'a');
1453
+ expectTextNode(parent.childNodes[2], 'b');
1454
+ expectTextNode(parent.childNodes[4], 'c');
1455
+ } else {
1456
+ expect(parent.childNodes.length).toBe(3);
1457
+ expectTextNode(parent.childNodes[0], 'a');
1458
+ expectTextNode(parent.childNodes[1], 'b');
1459
+ expectTextNode(parent.childNodes[2], 'c');
1460
+ }
1461
+ });
1462
});
1463
1464
describe('escaping >, <, and &', function() {
@@ -1615,27 +1472,18 @@ describe('ReactDOMServerIntegration', () => {
1472
const e = await render(
1473
<div>{'<span>Text1"</span>'}{'<span>Text2"</span>'}</div>,
1474
);
1618
- if (ReactDOMFeatureFlags.useFiber) {
1619
- // with Fiber, there are just two text nodes.
1620
- if (
1621
- render === serverRender ||
1622
- render === clientRenderOnServerString ||
1623
- render === streamRender
1624
- ) {
1625
- expect(e.childNodes.length).toBe(3);
1626
- expectTextNode(e.childNodes[0], '<span>Text1"</span>');
1627
- expectTextNode(e.childNodes[2], '<span>Text2"</span>');
1628
- } else {
1629
- expect(e.childNodes.length).toBe(2);
1630
- expectTextNode(e.childNodes[0], '<span>Text1"</span>');
1631
- expectTextNode(e.childNodes[1], '<span>Text2"</span>');
1632
- }
1475
+ if (
1476
+ render === serverRender ||
1477
+ render === clientRenderOnServerString ||
1478
+ render === streamRender
1479
+ ) {
1480
+ expect(e.childNodes.length).toBe(3);
1481
+ expectTextNode(e.childNodes[0], '<span>Text1"</span>');
1482
+ expectTextNode(e.childNodes[2], '<span>Text2"</span>');
1483
} else {
1634
- // with Stack there are six nodes: two text nodes each surrounded by
1635
- // two react-text comment nodes.
1636
- expect(e.childNodes.length).toBe(6);
1484
+ expect(e.childNodes.length).toBe(2);
1485
expectTextNode(e.childNodes[0], '<span>Text1"</span>');
1638
- expectTextNode(e.childNodes[3], '<span>Text2"</span>');
1486
+ expectTextNode(e.childNodes[1], '<span>Text2"</span>');
1487
}
1488
});
1489
});
@@ -1647,12 +1495,9 @@ describe('ReactDOMServerIntegration', () => {
1495
const UndefinedComponent = () => undefined;
1496
await render(<UndefinedComponent />, 1);
1497
},
1650
- ReactDOMFeatureFlags.useFiber
1651
- ? 'UndefinedComponent(...): Nothing was returned from render. ' +
1652
- 'This usually means a return statement is missing. Or, to ' +
1653
- 'render nothing, return null.'
1654
- : 'A valid React element (or null) must be returned. ' +
1655
- 'You may have returned undefined, an array or some other invalid object.',
1498
+ 'UndefinedComponent(...): Nothing was returned from render. ' +
1499
+ 'This usually means a return statement is missing. Or, to ' +
1500
+ 'render nothing, return null.',
1501
);
1502
1503
itThrowsWhenRendering(
@@ -1665,12 +1510,9 @@ describe('ReactDOMServerIntegration', () => {
1510
}
1511
await render(<UndefinedComponent />, 1);
1512
},
1668
- ReactDOMFeatureFlags.useFiber
1669
- ? 'UndefinedComponent(...): Nothing was returned from render. ' +
1670
- 'This usually means a return statement is missing. Or, to ' +
1671
- 'render nothing, return null.'
1672
- : 'A valid React element (or null) must be returned. ' +
1673
- 'You may have returned undefined, an array or some other invalid object.',
1513
+ 'UndefinedComponent(...): Nothing was returned from render. ' +
1514
+ 'This usually means a return statement is missing. Or, to ' +
1515
+ 'render nothing, return null.',
1516
);
1517
1518
itThrowsWhenRendering(
@@ -1679,12 +1521,9 @@ describe('ReactDOMServerIntegration', () => {
1521
const ObjectComponent = () => ({x: 123});
1522
await render(<ObjectComponent />, 1);
1523
},
1682
- ReactDOMFeatureFlags.useFiber
1683
- ? 'Objects are not valid as a React child (found: object with keys ' +
1684
- '{x}). If you meant to render a collection of children, use ' +
1685
- 'an array instead.'
1686
- : 'A valid React element (or null) must be returned. ' +
1687
- 'You may have returned undefined, an array or some other invalid object.',
1524
+ 'Objects are not valid as a React child (found: object with keys ' +
1525
+ '{x}). If you meant to render a collection of children, use ' +
1526
+ 'an array instead.',
1527
);
1528
1529
itThrowsWhenRendering(
@@ -1697,12 +1536,9 @@ describe('ReactDOMServerIntegration', () => {
1536
}
1537
await render(<ObjectComponent />, 1);
1538
},
1700
- ReactDOMFeatureFlags.useFiber
1701
- ? 'Objects are not valid as a React child (found: object with keys ' +
1702
- '{x}). If you meant to render a collection of children, use ' +
1703
- 'an array instead.'
1704
- : 'A valid React element (or null) must be returned. ' +
1705
- 'You may have returned undefined, an array or some other invalid object.',
1539
+ 'Objects are not valid as a React child (found: object with keys ' +
1540
+ '{x}). If you meant to render a collection of children, use ' +
1541
+ 'an array instead.',
1542
);
1543
1544
itThrowsWhenRendering(
@@ -1710,11 +1546,9 @@ describe('ReactDOMServerIntegration', () => {
1546
async render => {
1547
await render({x: 123});
1548
},
1713
- ReactDOMFeatureFlags.useFiber
1714
- ? 'Objects are not valid as a React child (found: object with keys ' +
1715
- '{x}). If you meant to render a collection of children, use ' +
1716
- 'an array instead.'
1717
- : 'Invalid component element.',
1549
+ 'Objects are not valid as a React child (found: object with keys ' +
1550
+ '{x}). If you meant to render a collection of children, use ' +
1551
+ 'an array instead.',
1552
);
1553
});
1554
});
@@ -2734,12 +2568,7 @@ describe('ReactDOMServerIntegration', () => {
2568
));
2569
2570
it('can distinguish an empty component from an empty text component', () =>
2737
- (ReactDOMFeatureFlags.useFiber
2738
- ? expectMarkupMatch
2739
- : expectMarkupMismatch)(
2740
- <div><EmptyComponent /></div>,
2741
- <div>{''}</div>,
2742
- ));
2571
+ expectMarkupMatch(<div><EmptyComponent /></div>, <div>{''}</div>));
2572
});
2573
2574
// Markup Mismatches: misc
src/renderers/dom/shared/__tests__/ReactDOMTextComponent-test.js
+2
-12
@@ -12,7 +12,6 @@
12
var React;
13
var ReactDOM;
14
var ReactDOMServer;
15
-var ReactDOMFeatureFlags;
15
16
// In standard React, TextComponent keeps track of different Text templates
17
// using comments. However, in React Fiber, those comments are not outputted due
@@ -28,7 +27,6 @@ describe('ReactDOMTextComponent', () => {
27
React = require('react');
28
ReactDOM = require('react-dom');
29
ReactDOMServer = require('react-dom/server');
31
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
30
});
31
32
it('updates a mounted text component in place', () => {
@@ -117,11 +115,7 @@ describe('ReactDOMTextComponent', () => {
115
var reactEl = <div>{'foo'}{'bar'}{'baz'}</div>;
116
el.innerHTML = ReactDOMServer.renderToString(reactEl);
117
120
- if (ReactDOMFeatureFlags.useFiber) {
121
- ReactDOM.hydrate(reactEl, el);
122
- } else {
123
- ReactDOM.render(reactEl, el);
124
- }
118
+ ReactDOM.hydrate(reactEl, el);
119
expect(el.textContent).toBe('foobarbaz');
120
121
ReactDOM.unmountComponentAtNode(el);
@@ -129,11 +123,7 @@ describe('ReactDOMTextComponent', () => {
123
reactEl = <div>{''}{''}{''}</div>;
124
el.innerHTML = ReactDOMServer.renderToString(reactEl);
125
132
- if (ReactDOMFeatureFlags.useFiber) {
133
- ReactDOM.hydrate(reactEl, el);
134
- } else {
135
- ReactDOM.render(reactEl, el);
136
- }
126
+ ReactDOM.hydrate(reactEl, el);
127
expect(el.textContent).toBe('');
128
});
129
src/renderers/dom/shared/__tests__/ReactMount-test.js
+60
-99
@@ -9,7 +9,6 @@
9
10
'use strict';
11
12
-const ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
12
const {COMMENT_NODE} = require('HTMLNodeType');
13
14
const invariant = require('invariant');
@@ -66,24 +65,22 @@ describe('ReactMount', () => {
65
});
66
});
67
69
- if (ReactDOMFeatureFlags.useFiber) {
70
- it('warns when given a factory', () => {
71
- spyOn(console, 'error');
72
- class Component extends React.Component {
73
- render() {
74
- return <div />;
75
- }
68
+ it('warns when given a factory', () => {
69
+ spyOn(console, 'error');
70
+ class Component extends React.Component {
71
+ render() {
72
+ return <div />;
73
}
74
+ }
75
78
- ReactTestUtils.renderIntoDocument(Component);
79
- expectDev(console.error.calls.count()).toBe(1);
80
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
81
- 'Functions are not valid as a React child. ' +
82
- 'This may happen if you return a Component instead of <Component /> from render. ' +
83
- 'Or maybe you meant to call this function rather than return it.',
84
- );
85
- });
86
- }
76
+ ReactTestUtils.renderIntoDocument(Component);
77
+ expectDev(console.error.calls.count()).toBe(1);
78
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
79
+ 'Functions are not valid as a React child. ' +
80
+ 'This may happen if you return a Component instead of <Component /> from render. ' +
81
+ 'Or maybe you meant to call this function rather than return it.',
82
+ );
83
+ });
84
85
it('should render different components in same root', () => {
86
var container = document.createElement('container');
@@ -144,21 +141,11 @@ describe('ReactMount', () => {
141
container.innerHTML = ReactDOMServer.renderToString(<div />) + ' ';
142
143
spyOn(console, 'error');
147
- if (ReactDOMFeatureFlags.useFiber) {
148
- ReactDOM.hydrate(<div />, container);
149
- } else {
150
- ReactDOM.render(<div />, container);
151
- }
144
+ ReactDOM.hydrate(<div />, container);
145
expectDev(console.error.calls.count()).toBe(1);
153
- if (ReactDOMFeatureFlags.useFiber) {
154
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
155
- 'Did not expect server HTML to contain the text node " " in <container>.',
156
- );
157
- } else {
158
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
159
- 'Target node has markup rendered by React, but there are unrelated nodes as well.',
160
- );
161
- }
146
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
147
+ 'Did not expect server HTML to contain the text node " " in <container>.',
148
+ );
149
});
150
151
it('should warn if mounting into right padded rendered markup', () => {
@@ -166,21 +153,11 @@ describe('ReactMount', () => {
153
container.innerHTML = ' ' + ReactDOMServer.renderToString(<div />);
154
155
spyOn(console, 'error');
169
- if (ReactDOMFeatureFlags.useFiber) {
170
- ReactDOM.hydrate(<div />, container);
171
- } else {
172
- ReactDOM.render(<div />, container);
173
- }
156
+ ReactDOM.hydrate(<div />, container);
157
expectDev(console.error.calls.count()).toBe(1);
175
- if (ReactDOMFeatureFlags.useFiber) {
176
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
177
- 'Did not expect server HTML to contain the text node " " in <container>.',
178
- );
179
- } else {
180
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
181
- 'Target node has markup rendered by React, but there are unrelated nodes as well.',
182
- );
183
- }
158
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
159
+ 'Did not expect server HTML to contain the text node " " in <container>.',
160
+ );
161
});
162
163
it('should not warn if mounting into non-empty node', () => {
@@ -213,29 +190,15 @@ describe('ReactMount', () => {
190
div.innerHTML = markup;
191
192
spyOn(console, 'error');
216
- if (ReactDOMFeatureFlags.useFiber) {
217
- ReactDOM.hydrate(
218
- <div>This markup contains an nbsp entity: client text</div>,
219
- div,
220
- );
221
- } else {
222
- ReactDOM.render(
223
- <div>This markup contains an nbsp entity: client text</div>,
224
- div,
225
- );
226
- }
193
+ ReactDOM.hydrate(
194
+ <div>This markup contains an nbsp entity: client text</div>,
195
+ div,
196
+ );
197
expectDev(console.error.calls.count()).toBe(1);
228
- if (ReactDOMFeatureFlags.useFiber) {
229
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
230
- 'Server: "This markup contains an nbsp entity: server text" ' +
231
- 'Client: "This markup contains an nbsp entity: client text"',
232
- );
233
- } else {
234
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
235
- ' (client) nbsp entity: client text</div>\n' +
236
- ' (server) nbsp entity: server text</div>',
237
- );
238
- }
198
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
199
+ 'Server: "This markup contains an nbsp entity: server text" ' +
200
+ 'Client: "This markup contains an nbsp entity: client text"',
201
+ );
202
});
203
204
if (WebComponents !== undefined) {
@@ -388,41 +351,39 @@ describe('ReactMount', () => {
351
expect(container2.textContent).toEqual('a!');
352
});
353
391
- if (ReactDOMFeatureFlags.useFiber) {
392
- describe('mount point is a comment node', () => {
393
- let containerDiv;
394
- let mountPoint;
354
+ describe('mount point is a comment node', () => {
355
+ let containerDiv;
356
+ let mountPoint;
357
396
- beforeEach(() => {
397
- containerDiv = document.createElement('div');
398
- containerDiv.innerHTML = 'A<!-- react-mount-point-unstable -->B';
399
- mountPoint = containerDiv.childNodes[1];
400
- invariant(mountPoint.nodeType === COMMENT_NODE, 'Expected comment');
401
- });
358
+ beforeEach(() => {
359
+ containerDiv = document.createElement('div');
360
+ containerDiv.innerHTML = 'A<!-- react-mount-point-unstable -->B';
361
+ mountPoint = containerDiv.childNodes[1];
362
+ invariant(mountPoint.nodeType === COMMENT_NODE, 'Expected comment');
363
+ });
364
403
- it('renders at a comment node', () => {
404
- function Char(props) {
405
- return props.children;
406
- }
407
- function list(chars) {
408
- return chars.split('').map(c => <Char key={c}>{c}</Char>);
409
- }
410
-
411
- ReactDOM.render(list('aeiou'), mountPoint);
412
- expect(containerDiv.innerHTML).toBe(
413
- 'Aaeiou<!-- react-mount-point-unstable -->B',
414
- );
365
+ it('renders at a comment node', () => {
366
+ function Char(props) {
367
+ return props.children;
368
+ }
369
+ function list(chars) {
370
+ return chars.split('').map(c => <Char key={c}>{c}</Char>);
371
+ }
372
416
- ReactDOM.render(list('yea'), mountPoint);
417
- expect(containerDiv.innerHTML).toBe(
418
- 'Ayea<!-- react-mount-point-unstable -->B',
419
- );
373
+ ReactDOM.render(list('aeiou'), mountPoint);
374
+ expect(containerDiv.innerHTML).toBe(
375
+ 'Aaeiou<!-- react-mount-point-unstable -->B',
376
+ );
377
421
- ReactDOM.render(list(''), mountPoint);
422
- expect(containerDiv.innerHTML).toBe(
423
- 'A<!-- react-mount-point-unstable -->B',
424
- );
425
- });
378
+ ReactDOM.render(list('yea'), mountPoint);
379
+ expect(containerDiv.innerHTML).toBe(
380
+ 'Ayea<!-- react-mount-point-unstable -->B',
381
+ );
382
+
383
+ ReactDOM.render(list(''), mountPoint);
384
+ expect(containerDiv.innerHTML).toBe(
385
+ 'A<!-- react-mount-point-unstable -->B',
386
+ );
387
});
427
- }
388
+ });
389
});
src/renderers/dom/shared/__tests__/ReactRenderDocument-test.js
+228
-291
@@ -15,15 +15,6 @@ var ReactDOMServer;
15
16
var getTestDocument;
17
18
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
19
-
20
-var UNMOUNT_INVARIANT_MESSAGE =
21
- '<html> tried to unmount. ' +
22
- 'Because of cross-browser quirks it is impossible to unmount some ' +
23
- 'top-level components (eg <html>, <head>, and <body>) reliably and ' +
24
- 'efficiently. To fix this, have a single top-level component that ' +
25
- 'never unmounts render these elements.';
26
-
18
describe('rendering React components at document', () => {
19
beforeEach(() => {
20
jest.resetModules();
@@ -36,16 +27,12 @@ describe('rendering React components at document', () => {
27
28
describe('with old implicit hydration API', () => {
29
function expectDeprecationWarningWithFiber() {
39
- if (ReactDOMFeatureFlags.useFiber) {
40
- expectDev(console.warn.calls.count()).toBe(1);
41
- expectDev(console.warn.calls.argsFor(0)[0]).toContain(
42
- 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
43
- 'will stop working in React v17. Replace the ReactDOM.render() call ' +
44
- 'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
45
- );
46
- } else {
47
- expectDev(console.warn.calls.count()).toBe(0);
48
- }
30
+ expectDev(console.warn.calls.count()).toBe(1);
31
+ expectDev(console.warn.calls.argsFor(0)[0]).toContain(
32
+ 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
33
+ 'will stop working in React v17. Replace the ReactDOM.render() call ' +
34
+ 'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
35
+ );
36
}
37
38
it('should be able to adopt server markup', () => {
@@ -101,17 +88,9 @@ describe('rendering React components at document', () => {
88
ReactDOM.render(<Root />, testDocument);
89
expect(testDocument.body.innerHTML).toBe('Hello world');
90
104
- if (ReactDOMFeatureFlags.useFiber) {
105
- // In Fiber this actually works. It might not be a good idea though.
106
- ReactDOM.unmountComponentAtNode(testDocument);
107
- expect(testDocument.firstChild).toBe(null);
108
- } else {
109
- expect(function() {
110
- ReactDOM.unmountComponentAtNode(testDocument);
111
- }).toThrowError(UNMOUNT_INVARIANT_MESSAGE);
112
-
113
- expect(testDocument.body.innerHTML).toBe('Hello world');
114
- }
91
+ // In Fiber this actually works. It might not be a good idea though.
92
+ ReactDOM.unmountComponentAtNode(testDocument);
93
+ expect(testDocument.firstChild).toBe(null);
94
95
expectDeprecationWarningWithFiber();
96
});
@@ -152,23 +131,12 @@ describe('rendering React components at document', () => {
131
var testDocument = getTestDocument(markup);
132
133
ReactDOM.render(<Component />, testDocument);
155
-
134
expect(testDocument.body.innerHTML).toBe('Hello world');
135
158
- // Reactive update
159
- if (ReactDOMFeatureFlags.useFiber) {
160
- // This works but is probably a bad idea.
161
- ReactDOM.render(<Component2 />, testDocument);
162
-
163
- expect(testDocument.body.innerHTML).toBe('Goodbye world');
164
- } else {
165
- expect(function() {
166
- ReactDOM.render(<Component2 />, testDocument);
167
- }).toThrowError(UNMOUNT_INVARIANT_MESSAGE);
168
-
169
- expect(testDocument.body.innerHTML).toBe('Hello world');
170
- }
136
+ // This works but is probably a bad idea.
137
+ ReactDOM.render(<Component2 />, testDocument);
138
139
+ expect(testDocument.body.innerHTML).toBe('Goodbye world');
140
expectDeprecationWarningWithFiber();
141
});
142
@@ -231,38 +199,20 @@ describe('rendering React components at document', () => {
199
);
200
var testDocument = getTestDocument(markup);
201
234
- if (ReactDOMFeatureFlags.useFiber) {
235
- spyOn(console, 'warn');
236
- spyOn(console, 'error');
237
- ReactDOM.render(<Component text="Hello world" />, testDocument);
238
- expect(testDocument.body.innerHTML).toBe('Hello world');
239
- expectDev(console.warn.calls.count()).toBe(1);
240
- expectDev(console.warn.calls.argsFor(0)[0]).toContain(
241
- 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
242
- 'will stop working in React v17. Replace the ReactDOM.render() call ' +
243
- 'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
244
- );
245
- expectDev(console.error.calls.count()).toBe(1);
246
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
247
- 'Warning: Text content did not match.',
248
- );
249
- } else {
250
- expect(function() {
251
- // Notice the text is different!
252
- ReactDOM.render(<Component text="Hello world" />, testDocument);
253
- }).toThrowError(
254
- "You're trying to render a component to the document using " +
255
- 'server rendering but the checksum was invalid. This usually ' +
256
- 'means you rendered a different component type or props on ' +
257
- 'the client from the one on the server, or your render() methods ' +
258
- 'are impure. React cannot handle this case due to cross-browser ' +
259
- 'quirks by rendering at the document root. You should look for ' +
260
- 'environment dependent code in your components and ensure ' +
261
- 'the props are the same client and server side:\n' +
262
- ' (client) dy data-reactid="4">Hello world</body></\n' +
263
- ' (server) dy data-reactid="4">Goodbye world</body>',
264
- );
265
- }
202
+ spyOn(console, 'warn');
203
+ spyOn(console, 'error');
204
+ ReactDOM.render(<Component text="Hello world" />, testDocument);
205
+ expect(testDocument.body.innerHTML).toBe('Hello world');
206
+ expectDev(console.warn.calls.count()).toBe(1);
207
+ expectDev(console.warn.calls.argsFor(0)[0]).toContain(
208
+ 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
209
+ 'will stop working in React v17. Replace the ReactDOM.render() call ' +
210
+ 'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
211
+ );
212
+ expectDev(console.error.calls.count()).toBe(1);
213
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
214
+ 'Warning: Text content did not match.',
215
+ );
216
});
217
218
it('should throw on full document render w/ no markup', () => {
@@ -283,19 +233,8 @@ describe('rendering React components at document', () => {
233
}
234
}
235
286
- if (ReactDOMFeatureFlags.useFiber) {
287
- ReactDOM.render(<Component text="Hello world" />, testDocument);
288
- expect(testDocument.body.innerHTML).toBe('Hello world');
289
- } else {
290
- expect(function() {
291
- ReactDOM.render(<Component />, testDocument);
292
- }).toThrowError(
293
- "You're trying to render a component to the document but you didn't " +
294
- "use server rendering. We can't do this without using server " +
295
- 'rendering due to cross-browser quirks. See ' +
296
- 'ReactDOMServer.renderToString() for server rendering.',
297
- );
298
- }
236
+ ReactDOM.render(<Component text="Hello world" />, testDocument);
237
+ expect(testDocument.body.innerHTML).toBe('Hello world');
238
// We don't expect a warning about new hydration API here because
239
// we aren't sure if the user meant to hydrate or replace the document.
240
// We would see a warning if the document had React-rendered HTML in it.
@@ -323,221 +262,219 @@ describe('rendering React components at document', () => {
262
});
263
});
264
326
- if (ReactDOMFeatureFlags.useFiber) {
327
- describe('with new explicit hydration API', () => {
328
- it('should be able to adopt server markup', () => {
329
- class Root extends React.Component {
330
- render() {
331
- return (
332
- <html>
333
- <head>
334
- <title>Hello World</title>
335
- </head>
336
- <body>
337
- {'Hello ' + this.props.hello}
338
- </body>
339
- </html>
340
- );
341
- }
265
+ describe('with new explicit hydration API', () => {
266
+ it('should be able to adopt server markup', () => {
267
+ class Root extends React.Component {
268
+ render() {
269
+ return (
270
+ <html>
271
+ <head>
272
+ <title>Hello World</title>
273
+ </head>
274
+ <body>
275
+ {'Hello ' + this.props.hello}
276
+ </body>
277
+ </html>
278
+ );
279
}
280
+ }
281
+
282
+ var markup = ReactDOMServer.renderToString(<Root hello="world" />);
283
+ var testDocument = getTestDocument(markup);
284
+ var body = testDocument.body;
285
+
286
+ ReactDOM.hydrate(<Root hello="world" />, testDocument);
287
+ expect(testDocument.body.innerHTML).toBe('Hello world');
288
+
289
+ ReactDOM.hydrate(<Root hello="moon" />, testDocument);
290
+ expect(testDocument.body.innerHTML).toBe('Hello moon');
291
+
292
+ expect(body === testDocument.body).toBe(true);
293
+ });
294
344
- var markup = ReactDOMServer.renderToString(<Root hello="world" />);
345
- var testDocument = getTestDocument(markup);
346
- var body = testDocument.body;
347
-
348
- ReactDOM.hydrate(<Root hello="world" />, testDocument);
349
- expect(testDocument.body.innerHTML).toBe('Hello world');
350
-
351
- ReactDOM.hydrate(<Root hello="moon" />, testDocument);
352
- expect(testDocument.body.innerHTML).toBe('Hello moon');
353
-
354
- expect(body === testDocument.body).toBe(true);
355
- });
356
-
357
- it('should not be able to unmount component from document node', () => {
358
- class Root extends React.Component {
359
- render() {
360
- return (
361
- <html>
362
- <head>
363
- <title>Hello World</title>
364
- </head>
365
- <body>
366
- Hello world
367
- </body>
368
- </html>
369
- );
370
- }
295
+ it('should not be able to unmount component from document node', () => {
296
+ class Root extends React.Component {
297
+ render() {
298
+ return (
299
+ <html>
300
+ <head>
301
+ <title>Hello World</title>
302
+ </head>
303
+ <body>
304
+ Hello world
305
+ </body>
306
+ </html>
307
+ );
308
}
309
+ }
310
+
311
+ var markup = ReactDOMServer.renderToString(<Root />);
312
+ var testDocument = getTestDocument(markup);
313
+ ReactDOM.hydrate(<Root />, testDocument);
314
+ expect(testDocument.body.innerHTML).toBe('Hello world');
315
+
316
+ // In Fiber this actually works. It might not be a good idea though.
317
+ ReactDOM.unmountComponentAtNode(testDocument);
318
+ expect(testDocument.firstChild).toBe(null);
319
+ });
320
373
- var markup = ReactDOMServer.renderToString(<Root />);
374
- var testDocument = getTestDocument(markup);
375
- ReactDOM.hydrate(<Root />, testDocument);
376
- expect(testDocument.body.innerHTML).toBe('Hello world');
377
-
378
- // In Fiber this actually works. It might not be a good idea though.
379
- ReactDOM.unmountComponentAtNode(testDocument);
380
- expect(testDocument.firstChild).toBe(null);
381
- });
382
-
383
- it('should not be able to switch root constructors', () => {
384
- class Component extends React.Component {
385
- render() {
386
- return (
387
- <html>
388
- <head>
389
- <title>Hello World</title>
390
- </head>
391
- <body>
392
- Hello world
393
- </body>
394
- </html>
395
- );
396
- }
321
+ it('should not be able to switch root constructors', () => {
322
+ class Component extends React.Component {
323
+ render() {
324
+ return (
325
+ <html>
326
+ <head>
327
+ <title>Hello World</title>
328
+ </head>
329
+ <body>
330
+ Hello world
331
+ </body>
332
+ </html>
333
+ );
334
}
335
+ }
336
399
- class Component2 extends React.Component {
400
- render() {
401
- return (
402
- <html>
403
- <head>
404
- <title>Hello World</title>
405
- </head>
406
- <body>
407
- Goodbye world
408
- </body>
409
- </html>
410
- );
411
- }
337
+ class Component2 extends React.Component {
338
+ render() {
339
+ return (
340
+ <html>
341
+ <head>
342
+ <title>Hello World</title>
343
+ </head>
344
+ <body>
345
+ Goodbye world
346
+ </body>
347
+ </html>
348
+ );
349
}
350
+ }
351
+
352
+ var markup = ReactDOMServer.renderToString(<Component />);
353
+ var testDocument = getTestDocument(markup);
354
+
355
+ ReactDOM.hydrate(<Component />, testDocument);
356
414
- var markup = ReactDOMServer.renderToString(<Component />);
415
- var testDocument = getTestDocument(markup);
416
-
417
- ReactDOM.hydrate(<Component />, testDocument);
418
-
419
- expect(testDocument.body.innerHTML).toBe('Hello world');
420
-
421
- // This works but is probably a bad idea.
422
- ReactDOM.hydrate(<Component2 />, testDocument);
423
-
424
- expect(testDocument.body.innerHTML).toBe('Goodbye world');
425
- });
426
-
427
- it('should be able to mount into document', () => {
428
- class Component extends React.Component {
429
- render() {
430
- return (
431
- <html>
432
- <head>
433
- <title>Hello World</title>
434
- </head>
435
- <body>
436
- {this.props.text}
437
- </body>
438
- </html>
439
- );
440
- }
357
+ expect(testDocument.body.innerHTML).toBe('Hello world');
358
+
359
+ // This works but is probably a bad idea.
360
+ ReactDOM.hydrate(<Component2 />, testDocument);
361
+
362
+ expect(testDocument.body.innerHTML).toBe('Goodbye world');
363
+ });
364
+
365
+ it('should be able to mount into document', () => {
366
+ class Component extends React.Component {
367
+ render() {
368
+ return (
369
+ <html>
370
+ <head>
371
+ <title>Hello World</title>
372
+ </head>
373
+ <body>
374
+ {this.props.text}
375
+ </body>
376
+ </html>
377
+ );
378
}
379
+ }
380
+
381
+ var markup = ReactDOMServer.renderToString(
382
+ <Component text="Hello world" />,
383
+ );
384
+ var testDocument = getTestDocument(markup);
385
443
- var markup = ReactDOMServer.renderToString(
444
- <Component text="Hello world" />,
445
- );
446
- var testDocument = getTestDocument(markup);
447
-
448
- ReactDOM.hydrate(<Component text="Hello world" />, testDocument);
449
-
450
- expect(testDocument.body.innerHTML).toBe('Hello world');
451
- });
452
-
453
- it('renders over an existing text child without throwing', () => {
454
- spyOn(console, 'error');
455
- const container = document.createElement('div');
456
- container.textContent = 'potato';
457
- ReactDOM.hydrate(<div>parsnip</div>, container);
458
- expect(container.textContent).toBe('parsnip');
459
- expectDev(console.error.calls.count()).toBe(1);
460
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
461
- 'Did not expect server HTML to contain the text node "potato" in <div>.',
462
- );
463
- });
464
-
465
- it('should give helpful errors on state desync', () => {
466
- class Component extends React.Component {
467
- render() {
468
- return (
469
- <html>
470
- <head>
471
- <title>Hello World</title>
472
- </head>
473
- <body>
474
- {this.props.text}
475
- </body>
476
- </html>
477
- );
478
- }
386
+ ReactDOM.hydrate(<Component text="Hello world" />, testDocument);
387
+
388
+ expect(testDocument.body.innerHTML).toBe('Hello world');
389
+ });
390
+
391
+ it('renders over an existing text child without throwing', () => {
392
+ spyOn(console, 'error');
393
+ const container = document.createElement('div');
394
+ container.textContent = 'potato';
395
+ ReactDOM.hydrate(<div>parsnip</div>, container);
396
+ expect(container.textContent).toBe('parsnip');
397
+ expectDev(console.error.calls.count()).toBe(1);
398
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
399
+ 'Did not expect server HTML to contain the text node "potato" in <div>.',
400
+ );
401
+ });
402
+
403
+ it('should give helpful errors on state desync', () => {
404
+ class Component extends React.Component {
405
+ render() {
406
+ return (
407
+ <html>
408
+ <head>
409
+ <title>Hello World</title>
410
+ </head>
411
+ <body>
412
+ {this.props.text}
413
+ </body>
414
+ </html>
415
+ );
416
}
417
+ }
418
+
419
+ var markup = ReactDOMServer.renderToString(
420
+ <Component text="Goodbye world" />,
421
+ );
422
+ var testDocument = getTestDocument(markup);
423
+
424
+ spyOn(console, 'error');
425
+ ReactDOM.hydrate(<Component text="Hello world" />, testDocument);
426
+ expect(testDocument.body.innerHTML).toBe('Hello world');
427
+ expectDev(console.error.calls.count()).toBe(1);
428
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
429
+ 'Warning: Text content did not match.',
430
+ );
431
+ });
432
+
433
+ it('should render w/ no markup to full document', () => {
434
+ spyOn(console, 'error');
435
+ var testDocument = getTestDocument();
436
481
- var markup = ReactDOMServer.renderToString(
482
- <Component text="Goodbye world" />,
483
- );
484
- var testDocument = getTestDocument(markup);
485
-
486
- spyOn(console, 'error');
487
- ReactDOM.hydrate(<Component text="Hello world" />, testDocument);
488
- expect(testDocument.body.innerHTML).toBe('Hello world');
489
- expectDev(console.error.calls.count()).toBe(1);
490
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
491
- 'Warning: Text content did not match.',
492
- );
493
- });
494
-
495
- it('should render w/ no markup to full document', () => {
496
- spyOn(console, 'error');
497
- var testDocument = getTestDocument();
498
-
499
- class Component extends React.Component {
500
- render() {
501
- return (
502
- <html>
503
- <head>
504
- <title>Hello World</title>
505
- </head>
506
- <body>
507
- {this.props.text}
508
- </body>
509
- </html>
510
- );
511
- }
437
+ class Component extends React.Component {
438
+ render() {
439
+ return (
440
+ <html>
441
+ <head>
442
+ <title>Hello World</title>
443
+ </head>
444
+ <body>
445
+ {this.props.text}
446
+ </body>
447
+ </html>
448
+ );
449
}
450
+ }
451
514
- ReactDOM.hydrate(<Component text="Hello world" />, testDocument);
515
- expect(testDocument.body.innerHTML).toBe('Hello world');
516
- expectDev(console.error.calls.count()).toBe(1);
517
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
518
- // getTestDocument() has an extra <meta> that we didn't render.
519
- 'Did not expect server HTML to contain a <meta> in <head>.',
520
- );
521
- });
522
-
523
- it('supports findDOMNode on full-page components', () => {
524
- var tree = (
525
- <html>
526
- <head>
527
- <title>Hello World</title>
528
- </head>
529
- <body>
530
- Hello world
531
- </body>
532
- </html>
533
- );
534
-
535
- var markup = ReactDOMServer.renderToString(tree);
536
- var testDocument = getTestDocument(markup);
537
- var component = ReactDOM.hydrate(tree, testDocument);
538
- expect(testDocument.body.innerHTML).toBe('Hello world');
539
- expect(ReactDOM.findDOMNode(component).tagName).toBe('HTML');
540
- });
452
+ ReactDOM.hydrate(<Component text="Hello world" />, testDocument);
453
+ expect(testDocument.body.innerHTML).toBe('Hello world');
454
+ expectDev(console.error.calls.count()).toBe(1);
455
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
456
+ // getTestDocument() has an extra <meta> that we didn't render.
457
+ 'Did not expect server HTML to contain a <meta> in <head>.',
458
+ );
459
});
542
- }
460
+
461
+ it('supports findDOMNode on full-page components', () => {
462
+ var tree = (
463
+ <html>
464
+ <head>
465
+ <title>Hello World</title>
466
+ </head>
467
+ <body>
468
+ Hello world
469
+ </body>
470
+ </html>
471
+ );
472
+
473
+ var markup = ReactDOMServer.renderToString(tree);
474
+ var testDocument = getTestDocument(markup);
475
+ var component = ReactDOM.hydrate(tree, testDocument);
476
+ expect(testDocument.body.innerHTML).toBe('Hello world');
477
+ expect(ReactDOM.findDOMNode(component).tagName).toBe('HTML');
478
+ });
479
+ });
480
});
src/renderers/dom/shared/__tests__/ReactServerRendering-test.js
+91
-139
@@ -16,9 +16,6 @@ var ReactDOMServer;
16
var ReactTestUtils;
17
var PropTypes;
18
19
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
20
-
21
-var ID_ATTRIBUTE_NAME;
19
var ROOT_ATTRIBUTE_NAME;
20
21
describe('ReactDOMServer', () => {
@@ -34,7 +31,6 @@ describe('ReactDOMServer', () => {
31
ReactDOMServer = require('react-dom/server');
32
33
var DOMProperty = require('DOMProperty');
37
- ID_ATTRIBUTE_NAME = DOMProperty.ID_ATTRIBUTE_NAME;
34
ROOT_ATTRIBUTE_NAME = DOMProperty.ROOT_ATTRIBUTE_NAME;
35
});
36
@@ -72,11 +68,7 @@ describe('ReactDOMServer', () => {
68
}
69
70
var response = ReactDOMServer.renderToString(<NullComponent />);
75
- if (ReactDOMFeatureFlags.useFiber) {
76
- expect(response).toBe('');
77
- } else {
78
- expect(response).toBe('<!-- react-empty: 1 -->');
79
- }
71
+ expect(response).toBe('');
72
});
73
74
// TODO: Test that listeners are not registered onto any document/container.
@@ -103,10 +95,7 @@ describe('ReactDOMServer', () => {
95
'>' +
96
'<span' +
97
'>' +
106
- (ReactDOMFeatureFlags.useFiber
107
- ? 'My name is <!-- -->child'
108
- : '<!-- react-text: [0-9]+ -->My name is <!-- /react-text -->' +
109
- '<!-- react-text: [0-9]+ -->child<!-- /react-text -->') +
98
+ 'My name is <!-- -->child' +
99
'</span>' +
100
'</div>',
101
),
@@ -165,14 +154,8 @@ describe('ReactDOMServer', () => {
154
'<span ' +
155
ROOT_ATTRIBUTE_NAME +
156
'=""' +
168
- (ReactDOMFeatureFlags.useFiber
169
- ? ''
170
- : ' ' + ID_ATTRIBUTE_NAME + '="[^"]*"') +
157
'>' +
172
- (ReactDOMFeatureFlags.useFiber
173
- ? 'Component name: <!-- -->TestComponent'
174
- : '<!-- react-text: [0-9]+ -->Component name: <!-- /react-text -->' +
175
- '<!-- react-text: [0-9]+ -->TestComponent<!-- /react-text -->') +
158
+ 'Component name: <!-- -->TestComponent' +
159
'</span>',
160
),
161
);
@@ -247,24 +230,14 @@ describe('ReactDOMServer', () => {
230
231
var instance = ReactDOM.render(<TestComponent name="x" />, element);
232
expect(mountCount).toEqual(3);
250
- if (ReactDOMFeatureFlags.useFiber) {
251
- expectDev(console.warn.calls.count()).toBe(1);
252
- expectDev(console.warn.calls.argsFor(0)[0]).toContain(
253
- 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
254
- 'will stop working in React v17. Replace the ReactDOM.render() call ' +
255
- 'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
256
- );
257
- } else {
258
- expectDev(console.warn.calls.count()).toBe(0);
259
- }
233
+ expectDev(console.warn.calls.count()).toBe(1);
234
+ expectDev(console.warn.calls.argsFor(0)[0]).toContain(
235
+ 'render(): Calling ReactDOM.render() to hydrate server-rendered markup ' +
236
+ 'will stop working in React v17. Replace the ReactDOM.render() call ' +
237
+ 'with ReactDOM.hydrate() if you want React to attach to the server HTML.',
238
+ );
239
console.warn.calls.reset();
261
-
262
- var expectedMarkup = lastMarkup;
263
- if (ReactDOMFeatureFlags.useFiber) {
264
- var reactComments = /<!-- \/?react-text(: \d+)? -->/g;
265
- expectedMarkup = expectedMarkup.replace(reactComments, '');
266
- }
267
- expect(element.innerHTML).toBe(expectedMarkup);
240
+ expect(element.innerHTML).toBe(lastMarkup);
241
242
// Ensure the events system works after mount into server markup
243
expect(numClicks).toEqual(0);
@@ -280,18 +253,9 @@ describe('ReactDOMServer', () => {
253
instance = ReactDOM.render(<TestComponent name="y" />, element);
254
expect(mountCount).toEqual(4);
255
expectDev(console.error.calls.count()).toBe(1);
283
- if (ReactDOMFeatureFlags.useFiber) {
284
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
285
- 'Text content did not match. Server: "x" Client: "y"',
286
- );
287
- } else {
288
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
289
- '(client) -- react-text: 3 -->y<!-- /react-text --',
290
- );
291
- expectDev(console.error.calls.argsFor(0)[0]).toContain(
292
- '(server) -- react-text: 3 -->x<!-- /react-text --',
293
- );
294
- }
256
+ expectDev(console.error.calls.argsFor(0)[0]).toContain(
257
+ 'Text content did not match. Server: "x" Client: "y"',
258
+ );
259
console.error.calls.reset();
260
expect(element.innerHTML.length > 0).toBe(true);
261
expect(element.innerHTML).not.toEqual(lastMarkup);
@@ -304,104 +268,94 @@ describe('ReactDOMServer', () => {
268
expectDev(console.error.calls.count()).toBe(0);
269
});
270
307
- if (ReactDOMFeatureFlags.useFiber) {
308
- it('should have the correct mounting behavior (new hydrate API)', () => {
309
- spyOn(console, 'error');
310
- // This test is testing client-side behavior.
311
- ExecutionEnvironment.canUseDOM = true;
271
+ it('should have the correct mounting behavior (new hydrate API)', () => {
272
+ spyOn(console, 'error');
273
+ // This test is testing client-side behavior.
274
+ ExecutionEnvironment.canUseDOM = true;
275
313
- var mountCount = 0;
314
- var numClicks = 0;
276
+ var mountCount = 0;
277
+ var numClicks = 0;
278
316
- class TestComponent extends React.Component {
317
- componentDidMount() {
318
- mountCount++;
319
- }
279
+ class TestComponent extends React.Component {
280
+ componentDidMount() {
281
+ mountCount++;
282
+ }
283
321
- click = () => {
322
- numClicks++;
323
- };
284
+ click = () => {
285
+ numClicks++;
286
+ };
287
325
- render() {
326
- return (
327
- <span ref="span" onClick={this.click}>
328
- Name: {this.props.name}
329
- </span>
330
- );
331
- }
288
+ render() {
289
+ return (
290
+ <span ref="span" onClick={this.click}>
291
+ Name: {this.props.name}
292
+ </span>
293
+ );
294
}
295
+ }
296
334
- var element = document.createElement('div');
335
- ReactDOM.render(<TestComponent />, element);
336
-
337
- var lastMarkup = element.innerHTML;
338
-
339
- // Exercise the update path. Markup should not change,
340
- // but some lifecycle methods should be run again.
341
- ReactDOM.render(<TestComponent name="x" />, element);
342
- expect(mountCount).toEqual(1);
343
-
344
- // Unmount and remount. We should get another mount event and
345
- // we should get different markup, as the IDs are unique each time.
346
- ReactDOM.unmountComponentAtNode(element);
347
- expect(element.innerHTML).toEqual('');
348
- ReactDOM.render(<TestComponent name="x" />, element);
349
- expect(mountCount).toEqual(2);
350
- expect(element.innerHTML).not.toEqual(lastMarkup);
351
-
352
- // Now kill the node and render it on top of server-rendered markup, as if
353
- // we used server rendering. We should mount again, but the markup should
354
- // be unchanged. We will append a sentinel at the end of innerHTML to be
355
- // sure that innerHTML was not changed.
356
- ReactDOM.unmountComponentAtNode(element);
357
- expect(element.innerHTML).toEqual('');
358
-
359
- ExecutionEnvironment.canUseDOM = false;
360
- lastMarkup = ReactDOMServer.renderToString(<TestComponent name="x" />);
361
- ExecutionEnvironment.canUseDOM = true;
362
- element.innerHTML = lastMarkup;
363
-
364
- var instance = ReactDOM.hydrate(<TestComponent name="x" />, element);
365
- expect(mountCount).toEqual(3);
366
-
367
- var expectedMarkup = lastMarkup;
368
- if (ReactDOMFeatureFlags.useFiber) {
369
- var reactComments = /<!-- \/?react-text(: \d+)? -->/g;
370
- expectedMarkup = expectedMarkup.replace(reactComments, '');
371
- }
372
- expect(element.innerHTML).toBe(expectedMarkup);
373
-
374
- // Ensure the events system works after mount into server markup
375
- expect(numClicks).toEqual(0);
376
- ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance.refs.span));
377
- expect(numClicks).toEqual(1);
378
-
379
- ReactDOM.unmountComponentAtNode(element);
380
- expect(element.innerHTML).toEqual('');
381
-
382
- // Now simulate a situation where the app is not idempotent. React should
383
- // warn but do the right thing.
384
- element.innerHTML = lastMarkup;
385
- instance = ReactDOM.hydrate(<TestComponent name="y" />, element);
386
- expect(mountCount).toEqual(4);
387
- expectDev(console.error.calls.count()).toBe(1);
388
- expect(element.innerHTML.length > 0).toBe(true);
389
- expect(element.innerHTML).not.toEqual(lastMarkup);
390
-
391
- // Ensure the events system works after markup mismatch.
392
- expect(numClicks).toEqual(1);
393
- ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance.refs.span));
394
- expect(numClicks).toEqual(2);
395
- });
396
- }
297
+ var element = document.createElement('div');
298
+ ReactDOM.render(<TestComponent />, element);
299
+
300
+ var lastMarkup = element.innerHTML;
301
+
302
+ // Exercise the update path. Markup should not change,
303
+ // but some lifecycle methods should be run again.
304
+ ReactDOM.render(<TestComponent name="x" />, element);
305
+ expect(mountCount).toEqual(1);
306
+
307
+ // Unmount and remount. We should get another mount event and
308
+ // we should get different markup, as the IDs are unique each time.
309
+ ReactDOM.unmountComponentAtNode(element);
310
+ expect(element.innerHTML).toEqual('');
311
+ ReactDOM.render(<TestComponent name="x" />, element);
312
+ expect(mountCount).toEqual(2);
313
+ expect(element.innerHTML).not.toEqual(lastMarkup);
314
+
315
+ // Now kill the node and render it on top of server-rendered markup, as if
316
+ // we used server rendering. We should mount again, but the markup should
317
+ // be unchanged. We will append a sentinel at the end of innerHTML to be
318
+ // sure that innerHTML was not changed.
319
+ ReactDOM.unmountComponentAtNode(element);
320
+ expect(element.innerHTML).toEqual('');
321
+
322
+ ExecutionEnvironment.canUseDOM = false;
323
+ lastMarkup = ReactDOMServer.renderToString(<TestComponent name="x" />);
324
+ ExecutionEnvironment.canUseDOM = true;
325
+ element.innerHTML = lastMarkup;
326
+
327
+ var instance = ReactDOM.hydrate(<TestComponent name="x" />, element);
328
+ expect(mountCount).toEqual(3);
329
+ expect(element.innerHTML).toBe(lastMarkup);
330
+
331
+ // Ensure the events system works after mount into server markup
332
+ expect(numClicks).toEqual(0);
333
+ ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance.refs.span));
334
+ expect(numClicks).toEqual(1);
335
+
336
+ ReactDOM.unmountComponentAtNode(element);
337
+ expect(element.innerHTML).toEqual('');
338
+
339
+ // Now simulate a situation where the app is not idempotent. React should
340
+ // warn but do the right thing.
341
+ element.innerHTML = lastMarkup;
342
+ instance = ReactDOM.hydrate(<TestComponent name="y" />, element);
343
+ expect(mountCount).toEqual(4);
344
+ expectDev(console.error.calls.count()).toBe(1);
345
+ expect(element.innerHTML.length > 0).toBe(true);
346
+ expect(element.innerHTML).not.toEqual(lastMarkup);
347
+
348
+ // Ensure the events system works after markup mismatch.
349
+ expect(numClicks).toEqual(1);
350
+ ReactTestUtils.Simulate.click(ReactDOM.findDOMNode(instance.refs.span));
351
+ expect(numClicks).toEqual(2);
352
+ });
353
354
it('should throw with silly args', () => {
355
expect(
356
ReactDOMServer.renderToString.bind(ReactDOMServer, {x: 123}),
357
).toThrowError(
402
- ReactDOMFeatureFlags.useFiber
403
- ? 'Objects are not valid as a React child (found: object with keys {x})'
404
- : 'renderToString(): Invalid component element.',
358
+ 'Objects are not valid as a React child (found: object with keys {x})',
359
);
360
});
361
});
@@ -515,9 +469,7 @@ describe('ReactDOMServer', () => {
469
expect(
470
ReactDOMServer.renderToStaticMarkup.bind(ReactDOMServer, {x: 123}),
471
).toThrowError(
518
- ReactDOMFeatureFlags.useFiber
519
- ? 'Objects are not valid as a React child (found: object with keys {x})'
520
- : 'renderToStaticMarkup(): Invalid component element.',
472
+ 'Objects are not valid as a React child (found: object with keys {x})',
473
);
474
});
475
src/renderers/dom/shared/__tests__/ReactServerRenderingBrowser-test.js
+12
-16
@@ -13,8 +13,6 @@ var React;
13
var ReactDOMServer;
14
var ReactDOMServerBrowser;
15
16
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
17
-
16
describe('ReactServerRenderingBrowser', () => {
17
beforeEach(() => {
18
jest.resetModules();
@@ -53,18 +51,16 @@ describe('ReactServerRenderingBrowser', () => {
51
);
52
});
53
56
- if (ReactDOMFeatureFlags.useFiber) {
57
- it('throws meaningfully for server-only APIs', () => {
58
- expect(() => ReactDOMServerBrowser.renderToNodeStream(<div />)).toThrow(
59
- 'ReactDOMServer.renderToNodeStream(): The streaming API is not available ' +
60
- 'in the browser. Use ReactDOMServer.renderToString() instead.',
61
- );
62
- expect(() =>
63
- ReactDOMServerBrowser.renderToStaticNodeStream(<div />),
64
- ).toThrow(
65
- 'ReactDOMServer.renderToStaticNodeStream(): The streaming API is not available ' +
66
- 'in the browser. Use ReactDOMServer.renderToStaticMarkup() instead.',
67
- );
68
- });
69
- }
54
+ it('throws meaningfully for server-only APIs', () => {
55
+ expect(() => ReactDOMServerBrowser.renderToNodeStream(<div />)).toThrow(
56
+ 'ReactDOMServer.renderToNodeStream(): The streaming API is not available ' +
57
+ 'in the browser. Use ReactDOMServer.renderToString() instead.',
58
+ );
59
+ expect(() =>
60
+ ReactDOMServerBrowser.renderToStaticNodeStream(<div />),
61
+ ).toThrow(
62
+ 'ReactDOMServer.renderToStaticNodeStream(): The streaming API is not available ' +
63
+ 'in the browser. Use ReactDOMServer.renderToStaticMarkup() instead.',
64
+ );
65
+ });
66
});
src/renderers/dom/shared/__tests__/renderSubtreeIntoContainer-test.js
+20
-23
@@ -12,7 +12,6 @@
12
var React = require('react');
13
var PropTypes = require('prop-types');
14
var ReactDOM = require('react-dom');
15
-var ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
15
var ReactTestUtils = require('react-dom/test-utils');
16
var renderSubtreeIntoContainer = require('react-dom')
17
.unstable_renderSubtreeIntoContainer;
@@ -299,26 +298,24 @@ describe('renderSubtreeIntoContainer', () => {
298
expect(portal2.textContent).toBe('foo');
299
});
300
302
- if (ReactDOMFeatureFlags.useFiber) {
303
- it('fails gracefully when mixing React 15 and 16', () => {
304
- class C extends React.Component {
305
- render() {
306
- return <div />;
307
- }
308
- }
309
- const c = ReactDOM.render(<C />, document.createElement('div'));
310
- // React 15 calls this:
311
- // https://github.com/facebook/react/blob/77b71fc3c4/src/renderers/dom/client/ReactMount.js#L478-L479
312
- expect(() => {
313
- c._reactInternalInstance._processChildContext({});
314
- }).toThrow(
315
- '_processChildContext is not available in React 16+. This likely ' +
316
- 'means you have multiple copies of React and are attempting to nest ' +
317
- 'a React 15 tree inside a React 16 tree using ' +
318
- "unstable_renderSubtreeIntoContainer, which isn't supported. Try to " +
319
- 'make sure you have only one copy of React (and ideally, switch to ' +
320
- 'ReactDOM.createPortal).',
321
- );
322
- });
323
- }
301
+ it('fails gracefully when mixing React 15 and 16', () => {
302
+ class C extends React.Component {
303
+ render() {
304
+ return <div />;
305
+ }
306
+ }
307
+ const c = ReactDOM.render(<C />, document.createElement('div'));
308
+ // React 15 calls this:
309
+ // https://github.com/facebook/react/blob/77b71fc3c4/src/renderers/dom/client/ReactMount.js#L478-L479
310
+ expect(() => {
311
+ c._reactInternalInstance._processChildContext({});
312
+ }).toThrow(
313
+ '_processChildContext is not available in React 16+. This likely ' +
314
+ 'means you have multiple copies of React and are attempting to nest ' +
315
+ 'a React 15 tree inside a React 16 tree using ' +
316
+ "unstable_renderSubtreeIntoContainer, which isn't supported. Try to " +
317
+ 'make sure you have only one copy of React (and ideally, switch to ' +
318
+ 'ReactDOM.createPortal).',
319
+ );
320
+ });
321
});
src/renderers/dom/shared/wrappers/__tests__/ReactDOMInput-test.js
-6
@@ -15,7 +15,6 @@ describe('ReactDOMInput', () => {
15
var React;
16
var ReactDOM;
17
var ReactDOMServer;
18
- var ReactDOMFeatureFlags;
18
var ReactTestUtils;
19
var inputValueTracking;
20
@@ -35,7 +34,6 @@ describe('ReactDOMInput', () => {
34
React = require('react');
35
ReactDOM = require('react-dom');
36
ReactDOMServer = require('react-dom/server');
38
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
37
ReactTestUtils = require('react-dom/test-utils');
38
// TODO: can we express this test with only public API?
39
inputValueTracking = require('inputValueTracking');
@@ -1187,7 +1185,6 @@ describe('ReactDOMInput', () => {
1185
<input value="0" type="range" min="0" max="100" step="1" />,
1186
);
1187
expect(log).toEqual([
1190
- ...(ReactDOMFeatureFlags.useFiber ? [] : ['set data-reactroot']),
1188
'set type',
1189
'set step',
1190
'set min',
@@ -1251,9 +1248,6 @@ describe('ReactDOMInput', () => {
1248
<input type="date" defaultValue="1980-01-01" />,
1249
);
1250
expect(log).toEqual([
1254
- ...(ReactDOMFeatureFlags.useFiber
1255
- ? []
1256
- : ['node.setAttribute("data-reactroot", "")']),
1251
'node.setAttribute("type", "date")',
1252
'node.setAttribute("value", "1980-01-01")',
1253
'node.value = ""',
src/renderers/dom/shared/wrappers/__tests__/ReactDOMOption-test.js
+3
-7
@@ -16,13 +16,11 @@ describe('ReactDOMOption', () => {
16
17
var React;
18
var ReactDOM;
19
- var ReactDOMFeatureFlags;
19
var ReactTestUtils;
20
21
beforeEach(() => {
22
React = require('react');
23
ReactDOM = require('react-dom');
25
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
24
ReactTestUtils = require('react-dom/test-utils');
25
});
26
@@ -45,11 +43,9 @@ describe('ReactDOMOption', () => {
43
expectDev(
44
normalizeCodeLocInfo(console.error.calls.argsFor(0)[0]),
45
).toContain(
48
- ReactDOMFeatureFlags.useFiber
49
- ? '<div> cannot appear as a child of <option>.\n' +
50
- ' in div (at **)\n' +
51
- ' in option (at **)'
52
- : 'Only strings and numbers are supported as <option> children.',
46
+ '<div> cannot appear as a child of <option>.\n' +
47
+ ' in div (at **)\n' +
48
+ ' in option (at **)',
49
);
50
});
51
src/renderers/dom/test/__tests__/ReactTestUtils-test.js
+1
-5
@@ -12,7 +12,6 @@
12
let createRenderer;
13
let React;
14
let ReactDOM;
15
-let ReactDOMFeatureFlags;
15
let ReactDOMServer;
16
let ReactTestUtils;
17
@@ -23,7 +22,6 @@ describe('ReactTestUtils', () => {
22
ReactDOM = require('react-dom');
23
ReactDOMServer = require('react-dom/server');
24
ReactTestUtils = require('react-dom/test-utils');
26
- ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
25
});
26
27
it('can scryRenderedDOMComponentsWithClass with TextComponent', () => {
@@ -173,9 +171,7 @@ describe('ReactTestUtils', () => {
171
172
const markup = ReactDOMServer.renderToString(<Root />);
173
const testDocument = getTestDocument(markup);
176
- const component = ReactDOMFeatureFlags.useFiber
177
- ? ReactDOM.hydrate(<Root />, testDocument)
178
- : ReactDOM.render(<Root />, testDocument);
174
+ const component = ReactDOM.hydrate(<Root />, testDocument);
175
176
expect(component.refs.html.tagName).toBe('HTML');
177
expect(component.refs.head.tagName).toBe('HEAD');
src/renderers/shared/__tests__/ReactDOMFrameScheduling-test.js
+1
-4
@@ -9,10 +9,7 @@
9
10
'use strict';
11
12
-const ReactDOMFeatureFlags = require('ReactDOMFeatureFlags');
13
-const describeFiber = ReactDOMFeatureFlags.useFiber ? describe : xdescribe;
14
-
15
-describeFiber('ReactDOMFrameScheduling', () => {
12
+describe('ReactDOMFrameScheduling', () => {
13
it('warns when requestAnimationFrame is not polyfilled in the browser', () => {
14
const previousRAF = global.requestAnimationFrame;
15
try {