Add explicit warning assertions to ReactDOMInput-test (#11744)
Dan Abramov committed
Dec 1, 2017 at 17:16 UTC
59763bf7f3ab3b06cd8ab5a5a83ae3dafc667aa9
1 file changed
+119
-25
packages/react-dom/src/__tests__/ReactDOMInput-test.js
+119
-25
@@ -38,10 +38,10 @@ describe('ReactDOMInput', () => {
38
ReactDOM = require('react-dom');
39
ReactDOMServer = require('react-dom/server');
40
ReactTestUtils = require('react-dom/test-utils');
41
- spyOnDev(console, 'error');
41
});
42
43
it('should properly control a value even if no event listener exists', () => {
44
+ spyOnDev(console, 'error');
45
var container = document.createElement('div');
46
var stub = ReactDOM.render(<input type="text" value="lion" />, container);
47
@@ -141,7 +141,12 @@ describe('ReactDOMInput', () => {
141
value="lion"
142
onChange={e => this.change(e.target.value)}
143
/>
144
- <input type="checkbox" ref={n => (this.b = n)} checked={true} />
144
+ <input
145
+ type="checkbox"
146
+ ref={n => (this.b = n)}
147
+ checked={true}
148
+ onChange={() => {}}
149
+ />
150
</div>
151
);
152
}
@@ -219,6 +224,7 @@ describe('ReactDOMInput', () => {
224
});
225
226
it('does change the string ".98" to "0.98" with no change handler', () => {
227
+ spyOnDev(console, 'error');
228
class Stub extends React.Component {
229
state = {
230
value: '.98',
@@ -233,9 +239,17 @@ describe('ReactDOMInput', () => {
239
stub.setState({value: '0.98'});
240
241
expect(node.value).toEqual('0.98');
242
+ if (__DEV__) {
243
+ expect(console.error.calls.count()).toBe(1);
244
+ expect(console.error.calls.argsFor(0)[0]).toContain(
245
+ 'You provided a `value` prop to a form field ' +
246
+ 'without an `onChange` handler.',
247
+ );
248
+ }
249
});
250
251
it('distinguishes precision for extra zeroes in string number values', () => {
252
+ spyOnDev(console, 'error');
253
class Stub extends React.Component {
254
state = {
255
value: '3.0000',
@@ -250,6 +264,13 @@ describe('ReactDOMInput', () => {
264
stub.setState({value: '3'});
265
266
expect(node.value).toEqual('3');
267
+ if (__DEV__) {
268
+ expect(console.error.calls.count()).toBe(1);
269
+ expect(console.error.calls.argsFor(0)[0]).toContain(
270
+ 'You provided a `value` prop to a form field ' +
271
+ 'without an `onChange` handler.',
272
+ );
273
+ }
274
});
275
276
it('should display `defaultValue` of number 0', () => {
@@ -336,18 +357,23 @@ describe('ReactDOMInput', () => {
357
});
358
359
it('should take `defaultValue` when changing to uncontrolled input', () => {
360
+ spyOnDev(console, 'error');
361
var container = document.createElement('div');
340
-
362
var node = ReactDOM.render(
363
<input type="text" value="0" readOnly="true" />,
364
container,
365
);
345
-
366
expect(node.value).toBe('0');
347
-
367
ReactDOM.render(<input type="text" defaultValue="1" />, container);
349
-
368
expect(node.value).toBe('0');
369
+
370
+ if (__DEV__) {
371
+ expect(console.error.calls.count()).toBe(1);
372
+ expect(console.error.calls.argsFor(0)[0]).toContain(
373
+ 'A component is changing a controlled input of type ' +
374
+ 'text to be uncontrolled.',
375
+ );
376
+ }
377
});
378
379
it('should render defaultValue for SSR', () => {
@@ -361,7 +387,7 @@ describe('ReactDOMInput', () => {
387
});
388
389
it('should render value for SSR', () => {
364
- var element = <input type="text" value="1" onChange={function() {}} />;
390
+ var element = <input type="text" value="1" onChange={() => {}} />;
391
var markup = ReactDOMServer.renderToString(element);
392
var div = document.createElement('div');
393
div.innerHTML = markup;
@@ -469,7 +495,7 @@ describe('ReactDOMInput', () => {
495
496
it('should not incur unnecessary DOM mutations', () => {
497
var container = document.createElement('div');
472
- ReactDOM.render(<input value="a" />, container);
498
+ ReactDOM.render(<input value="a" onChange={() => {}} />, container);
499
500
var node = container.firstChild;
501
var nodeValue = 'a';
@@ -483,16 +509,16 @@ describe('ReactDOMInput', () => {
509
}),
510
});
511
486
- ReactDOM.render(<input value="a" />, container);
512
+ ReactDOM.render(<input value="a" onChange={() => {}} />, container);
513
expect(nodeValueSetter.mock.calls.length).toBe(0);
514
489
- ReactDOM.render(<input value="b" />, container);
515
+ ReactDOM.render(<input value="b" onChange={() => {}} />, container);
516
expect(nodeValueSetter.mock.calls.length).toBe(1);
517
});
518
519
it('should not incur unnecessary DOM mutations for numeric type conversion', () => {
520
var container = document.createElement('div');
495
- ReactDOM.render(<input value="0" />, container);
521
+ ReactDOM.render(<input value="0" onChange={() => {}} />, container);
522
523
var node = container.firstChild;
524
var nodeValue = '0';
@@ -506,13 +532,13 @@ describe('ReactDOMInput', () => {
532
}),
533
});
534
509
- ReactDOM.render(<input value={0} />, container);
535
+ ReactDOM.render(<input value={0} onChange={() => {}} />, container);
536
expect(nodeValueSetter.mock.calls.length).toBe(0);
537
});
538
539
it('should not incur unnecessary DOM mutations for the boolean type conversion', () => {
540
var container = document.createElement('div');
515
- ReactDOM.render(<input value="true" />, container);
541
+ ReactDOM.render(<input value="true" onChange={() => {}} />, container);
542
543
var node = container.firstChild;
544
var nodeValue = 'true';
@@ -526,7 +552,7 @@ describe('ReactDOMInput', () => {
552
}),
553
});
554
529
- ReactDOM.render(<input value={true} />, container);
555
+ ReactDOM.render(<input value={true} onChange={() => {}} />, container);
556
expect(nodeValueSetter.mock.calls.length).toBe(0);
557
});
558
@@ -784,6 +810,7 @@ describe('ReactDOMInput', () => {
810
});
811
812
it('should warn with value and no onChange handler and readOnly specified', () => {
813
+ spyOnDev(console, 'error');
814
ReactTestUtils.renderIntoDocument(
815
<input type="text" value="zoink" readOnly={true} />,
816
);
@@ -818,6 +845,7 @@ describe('ReactDOMInput', () => {
845
});
846
847
it('should warn with checked and no onChange handler with readOnly specified', () => {
848
+ spyOnDev(console, 'error');
849
ReactTestUtils.renderIntoDocument(
850
<input type="checkbox" checked="false" readOnly={true} />,
851
);
@@ -841,6 +869,7 @@ describe('ReactDOMInput', () => {
869
});
870
871
it('should warn if value is null', () => {
872
+ spyOnDev(console, 'error');
873
ReactTestUtils.renderIntoDocument(<input type="text" value={null} />);
874
if (__DEV__) {
875
expect(console.error.calls.argsFor(0)[0]).toContain(
@@ -857,6 +886,7 @@ describe('ReactDOMInput', () => {
886
});
887
888
it('should warn if checked and defaultChecked props are specified', () => {
889
+ spyOnDev(console, 'error');
890
ReactTestUtils.renderIntoDocument(
891
<input
892
type="radio"
@@ -890,6 +920,7 @@ describe('ReactDOMInput', () => {
920
});
921
922
it('should warn if value and defaultValue props are specified', () => {
923
+ spyOnDev(console, 'error');
924
ReactTestUtils.renderIntoDocument(
925
<input type="text" value="foo" defaultValue="bar" readOnly={true} />,
926
);
@@ -913,6 +944,7 @@ describe('ReactDOMInput', () => {
944
});
945
946
it('should warn if controlled input switches to uncontrolled (value is undefined)', () => {
947
+ spyOnDev(console, 'error');
948
var stub = (
949
<input type="text" value="controlled" onChange={emptyFunction} />
950
);
@@ -932,6 +964,7 @@ describe('ReactDOMInput', () => {
964
});
965
966
it('should warn if controlled input switches to uncontrolled (value is null)', () => {
967
+ spyOnDev(console, 'error');
968
var stub = (
969
<input type="text" value="controlled" onChange={emptyFunction} />
970
);
@@ -951,6 +984,7 @@ describe('ReactDOMInput', () => {
984
});
985
986
it('should warn if controlled input switches to uncontrolled with defaultValue', () => {
987
+ spyOnDev(console, 'error');
988
var stub = (
989
<input type="text" value="controlled" onChange={emptyFunction} />
990
);
@@ -973,6 +1007,7 @@ describe('ReactDOMInput', () => {
1007
});
1008
1009
it('should warn if uncontrolled input (value is undefined) switches to controlled', () => {
1010
+ spyOnDev(console, 'error');
1011
var stub = <input type="text" />;
1012
var container = document.createElement('div');
1013
ReactDOM.render(stub, container);
@@ -990,6 +1025,7 @@ describe('ReactDOMInput', () => {
1025
});
1026
1027
it('should warn if uncontrolled input (value is null) switches to controlled', () => {
1028
+ spyOnDev(console, 'error');
1029
var stub = <input type="text" value={null} />;
1030
var container = document.createElement('div');
1031
ReactDOM.render(stub, container);
@@ -1007,6 +1043,7 @@ describe('ReactDOMInput', () => {
1043
});
1044
1045
it('should warn if controlled checkbox switches to uncontrolled (checked is undefined)', () => {
1046
+ spyOnDev(console, 'error');
1047
var stub = (
1048
<input type="checkbox" checked={true} onChange={emptyFunction} />
1049
);
@@ -1026,6 +1063,7 @@ describe('ReactDOMInput', () => {
1063
});
1064
1065
it('should warn if controlled checkbox switches to uncontrolled (checked is null)', () => {
1066
+ spyOnDev(console, 'error');
1067
var stub = (
1068
<input type="checkbox" checked={true} onChange={emptyFunction} />
1069
);
@@ -1045,6 +1083,7 @@ describe('ReactDOMInput', () => {
1083
});
1084
1085
it('should warn if controlled checkbox switches to uncontrolled with defaultChecked', () => {
1086
+ spyOnDev(console, 'error');
1087
var stub = (
1088
<input type="checkbox" checked={true} onChange={emptyFunction} />
1089
);
@@ -1064,6 +1103,7 @@ describe('ReactDOMInput', () => {
1103
});
1104
1105
it('should warn if uncontrolled checkbox (checked is undefined) switches to controlled', () => {
1106
+ spyOnDev(console, 'error');
1107
var stub = <input type="checkbox" />;
1108
var container = document.createElement('div');
1109
ReactDOM.render(stub, container);
@@ -1081,6 +1121,7 @@ describe('ReactDOMInput', () => {
1121
});
1122
1123
it('should warn if uncontrolled checkbox (checked is null) switches to controlled', () => {
1124
+ spyOnDev(console, 'error');
1125
var stub = <input type="checkbox" checked={null} />;
1126
var container = document.createElement('div');
1127
ReactDOM.render(stub, container);
@@ -1098,6 +1139,7 @@ describe('ReactDOMInput', () => {
1139
});
1140
1141
it('should warn if controlled radio switches to uncontrolled (checked is undefined)', () => {
1142
+ spyOnDev(console, 'error');
1143
var stub = <input type="radio" checked={true} onChange={emptyFunction} />;
1144
var container = document.createElement('div');
1145
ReactDOM.render(stub, container);
@@ -1115,6 +1157,7 @@ describe('ReactDOMInput', () => {
1157
});
1158
1159
it('should warn if controlled radio switches to uncontrolled (checked is null)', () => {
1160
+ spyOnDev(console, 'error');
1161
var stub = <input type="radio" checked={true} onChange={emptyFunction} />;
1162
var container = document.createElement('div');
1163
ReactDOM.render(stub, container);
@@ -1132,6 +1175,7 @@ describe('ReactDOMInput', () => {
1175
});
1176
1177
it('should warn if controlled radio switches to uncontrolled with defaultChecked', () => {
1178
+ spyOnDev(console, 'error');
1179
var stub = <input type="radio" checked={true} onChange={emptyFunction} />;
1180
var container = document.createElement('div');
1181
ReactDOM.render(stub, container);
@@ -1149,6 +1193,7 @@ describe('ReactDOMInput', () => {
1193
});
1194
1195
it('should warn if uncontrolled radio (checked is undefined) switches to controlled', () => {
1196
+ spyOnDev(console, 'error');
1197
var stub = <input type="radio" />;
1198
var container = document.createElement('div');
1199
ReactDOM.render(stub, container);
@@ -1166,6 +1211,7 @@ describe('ReactDOMInput', () => {
1211
});
1212
1213
it('should warn if uncontrolled radio (checked is null) switches to controlled', () => {
1214
+ spyOnDev(console, 'error');
1215
var stub = <input type="radio" checked={null} />;
1216
var container = document.createElement('div');
1217
ReactDOM.render(stub, container);
@@ -1195,9 +1241,6 @@ describe('ReactDOMInput', () => {
1241
container,
1242
);
1243
ReactDOM.render(<input type="radio" />, container);
1198
- if (__DEV__) {
1199
- expect(console.error.calls.count()).toBe(0);
1200
- }
1244
});
1245
1246
it('should not warn if radio value changes but never becomes uncontrolled', () => {
@@ -1216,12 +1259,10 @@ describe('ReactDOMInput', () => {
1259
/>,
1260
container,
1261
);
1219
- if (__DEV__) {
1220
- expect(console.error.calls.count()).toBe(0);
1221
- }
1262
});
1263
1264
it('should warn if radio checked false changes to become uncontrolled', () => {
1265
+ spyOnDev(console, 'error');
1266
var container = document.createElement('div');
1267
ReactDOM.render(
1268
<input
@@ -1269,7 +1310,14 @@ describe('ReactDOMInput', () => {
1310
});
1311
1312
ReactTestUtils.renderIntoDocument(
1272
- <input value="0" type="range" min="0" max="100" step="1" />,
1313
+ <input
1314
+ value="0"
1315
+ onChange={() => {}}
1316
+ type="range"
1317
+ min="0"
1318
+ max="100"
1319
+ step="1"
1320
+ />,
1321
);
1322
expect(log).toEqual([
1323
'set attribute type',
@@ -1433,7 +1481,7 @@ describe('ReactDOMInput', () => {
1481
describe('setting a controlled input to undefined', () => {
1482
var input;
1483
1436
- beforeEach(() => {
1484
+ function renderInputWithStringThenWithUndefined() {
1485
class Input extends React.Component {
1486
state = {value: 'first'};
1487
render() {
@@ -1450,21 +1498,39 @@ describe('ReactDOMInput', () => {
1498
input = ReactDOM.findDOMNode(stub);
1499
ReactTestUtils.Simulate.change(input, {target: {value: 'latest'}});
1500
ReactTestUtils.Simulate.change(input, {target: {value: undefined}});
1453
- });
1501
+ }
1502
1503
it('reverts the value attribute to the initial value', () => {
1504
+ spyOnDev(console, 'error');
1505
+ renderInputWithStringThenWithUndefined();
1506
expect(input.getAttribute('value')).toBe('first');
1507
+ if (__DEV__) {
1508
+ expect(console.error.calls.count()).toBe(1);
1509
+ expect(console.error.calls.argsFor(0)[0]).toContain(
1510
+ 'Input elements should not switch from controlled to ' +
1511
+ 'uncontrolled (or vice versa).',
1512
+ );
1513
+ }
1514
});
1515
1516
it('preserves the value property', () => {
1517
+ spyOnDev(console, 'error');
1518
+ renderInputWithStringThenWithUndefined();
1519
expect(input.value).toBe('latest');
1520
+ if (__DEV__) {
1521
+ expect(console.error.calls.count()).toBe(1);
1522
+ expect(console.error.calls.argsFor(0)[0]).toContain(
1523
+ 'Input elements should not switch from controlled to ' +
1524
+ 'uncontrolled (or vice versa).',
1525
+ );
1526
+ }
1527
});
1528
});
1529
1530
describe('setting a controlled input to null', () => {
1531
var input;
1532
1467
- beforeEach(() => {
1533
+ function renderInputWithStringThenWithNull() {
1534
class Input extends React.Component {
1535
state = {value: 'first'};
1536
render() {
@@ -1481,14 +1547,42 @@ describe('ReactDOMInput', () => {
1547
input = ReactDOM.findDOMNode(stub);
1548
ReactTestUtils.Simulate.change(input, {target: {value: 'latest'}});
1549
ReactTestUtils.Simulate.change(input, {target: {value: null}});
1484
- });
1550
+ }
1551
1552
it('reverts the value attribute to the initial value', () => {
1553
+ spyOnDev(console, 'error');
1554
+ renderInputWithStringThenWithNull();
1555
expect(input.getAttribute('value')).toBe('first');
1556
+ if (__DEV__) {
1557
+ expect(console.error.calls.count()).toBe(2);
1558
+ expect(console.error.calls.argsFor(0)[0]).toContain(
1559
+ '`value` prop on `input` should not be null. ' +
1560
+ 'Consider using an empty string to clear the component ' +
1561
+ 'or `undefined` for uncontrolled components.',
1562
+ );
1563
+ expect(console.error.calls.argsFor(1)[0]).toContain(
1564
+ 'Input elements should not switch from controlled ' +
1565
+ 'to uncontrolled (or vice versa).',
1566
+ );
1567
+ }
1568
});
1569
1570
it('preserves the value property', () => {
1571
+ spyOnDev(console, 'error');
1572
+ renderInputWithStringThenWithNull();
1573
expect(input.value).toBe('latest');
1574
+ if (__DEV__) {
1575
+ expect(console.error.calls.count()).toBe(2);
1576
+ expect(console.error.calls.argsFor(0)[0]).toContain(
1577
+ '`value` prop on `input` should not be null. ' +
1578
+ 'Consider using an empty string to clear the component ' +
1579
+ 'or `undefined` for uncontrolled components.',
1580
+ );
1581
+ expect(console.error.calls.argsFor(1)[0]).toContain(
1582
+ 'Input elements should not switch from controlled ' +
1583
+ 'to uncontrolled (or vice versa).',
1584
+ );
1585
+ }
1586
});
1587
});
1588
});