Skip to content

Commit 1e2d2a3

Browse files
committed
Fixes and tests
1 parent 8bf0648 commit 1e2d2a3

File tree

4 files changed

+67
-54
lines changed

4 files changed

+67
-54
lines changed

packages/react-dom/src/__tests__/ReactDOMInput-test.js

Lines changed: 49 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -47,30 +47,70 @@ describe('ReactDOMInput', () => {
4747
document.body.removeChild(container);
4848
});
4949

50-
it('should warn of no event listener with a falsey value of 0', () => {
50+
it('should warn for controlled value of 0 with missing onChange', () => {
5151
expect(() => {
52-
ReactTestUtils.renderIntoDocument(<input type="text" value={0} />);
52+
ReactDOM.render(<input type="text" value={0} />, container);
5353
}).toWarnDev(
5454
'Failed prop type: You provided a `value` prop to a form field without an `onChange` handler.',
5555
);
5656
});
5757

58-
it('should warn of no event listener with a falsey value of ""', () => {
58+
it('should warn for controlled value of "" with missing onChange', () => {
5959
expect(() => {
60-
ReactTestUtils.renderIntoDocument(<input type="text" value="" />);
60+
ReactDOM.render(<input type="text" value="" />, container);
6161
}).toWarnDev(
6262
'Failed prop type: You provided a `value` prop to a form field without an `onChange` handler.',
6363
);
6464
});
6565

66-
it('should warn of no event listener with a value of "0"', () => {
66+
it('should warn for controlled value of "0" with missing onChange', () => {
6767
expect(() => {
68-
ReactTestUtils.renderIntoDocument(<input type="text" value="0" />);
68+
ReactDOM.render(<input type="text" value="0" />, container);
6969
}).toWarnDev(
7070
'Failed prop type: You provided a `value` prop to a form field without an `onChange` handler.',
7171
);
7272
});
7373

74+
it('should warn for controlled value of false with missing onChange', () => {
75+
expect(() =>
76+
ReactDOM.render(<input type="checkbox" checked={false} />, container),
77+
).toWarnDev(
78+
'Failed prop type: You provided a `checked` prop to a form field without an `onChange` handler.',
79+
);
80+
});
81+
82+
it('should warn with checked and no onChange handler with readOnly specified', () => {
83+
ReactDOM.render(
84+
<input type="checkbox" checked={false} readOnly={true} />,
85+
container,
86+
);
87+
ReactDOM.unmountComponentAtNode(container);
88+
89+
expect(() =>
90+
ReactDOM.render(
91+
<input type="checkbox" checked={false} readOnly={false} />,
92+
container,
93+
),
94+
).toWarnDev(
95+
'Failed prop type: You provided a `checked` prop to a form field without an `onChange` handler. ' +
96+
'This will render a read-only field. If the field should be mutable use `defaultChecked`. ' +
97+
'Otherwise, set either `onChange` or `readOnly`.',
98+
);
99+
});
100+
101+
it('should not warn about missing onChange in uncontrolled inputs', () => {
102+
ReactDOM.render(<input />, container);
103+
ReactDOM.unmountComponentAtNode(container);
104+
ReactDOM.render(<input value={undefined} />, container);
105+
ReactDOM.unmountComponentAtNode(container);
106+
ReactDOM.render(<input type="text" />, container);
107+
ReactDOM.unmountComponentAtNode(container);
108+
ReactDOM.render(<input type="text" value={undefined} />, container);
109+
ReactDOM.render(<input type="checkbox" />, container);
110+
ReactDOM.unmountComponentAtNode(container);
111+
ReactDOM.render(<input type="checkbox" checked={undefined} />, container);
112+
});
113+
74114
it('should properly control a value even if no event listener exists', () => {
75115
let node;
76116

@@ -928,35 +968,6 @@ describe('ReactDOMInput', () => {
928968
dispatchEventOnNode(node, 'input');
929969
});
930970

931-
it('should warn of no event listener with a falsey checked prop', () => {
932-
expect(() =>
933-
ReactTestUtils.renderIntoDocument(
934-
<input type="checkbox" checked="false" />,
935-
),
936-
).toWarnDev(
937-
'Failed prop type: You provided a `checked` prop to a form field without an `onChange` handler.',
938-
);
939-
});
940-
941-
it('should warn with checked and no onChange handler with readOnly specified', () => {
942-
ReactDOM.render(
943-
<input type="checkbox" checked="false" readOnly={true} />,
944-
container,
945-
);
946-
ReactDOM.unmountComponentAtNode(container);
947-
948-
expect(() =>
949-
ReactDOM.render(
950-
<input type="checkbox" checked="false" readOnly={false} />,
951-
container,
952-
),
953-
).toWarnDev(
954-
'Failed prop type: You provided a `checked` prop to a form field without an `onChange` handler. ' +
955-
'This will render a read-only field. If the field should be mutable use `defaultChecked`. ' +
956-
'Otherwise, set either `onChange` or `readOnly`.',
957-
);
958-
});
959-
960971
it('should update defaultValue to empty string', () => {
961972
ReactDOM.render(<input type="text" defaultValue={'foo'} />, container);
962973
ReactDOM.render(<input type="text" defaultValue={''} />, container);
@@ -1184,15 +1195,10 @@ describe('ReactDOMInput', () => {
11841195
});
11851196

11861197
it('should warn if uncontrolled checkbox (checked is null) switches to controlled', () => {
1187-
const stub = (
1188-
<input type="checkbox" checked={null} />
1189-
);
1198+
const stub = <input type="checkbox" checked={null} />;
11901199
ReactDOM.render(stub, container);
11911200
expect(() =>
1192-
ReactDOM.render(
1193-
<input type="checkbox" checked={true} />,
1194-
container,
1195-
),
1201+
ReactDOM.render(<input type="checkbox" checked={true} />, container),
11961202
).toWarnDev(
11971203
'Warning: A component is changing an uncontrolled input of type checkbox to be controlled. ' +
11981204
'Input elements should not switch from uncontrolled to controlled (or vice versa). ' +
@@ -1218,10 +1224,7 @@ describe('ReactDOMInput', () => {
12181224
const stub = <input type="radio" checked={true} onChange={emptyFunction} />;
12191225
ReactDOM.render(stub, container);
12201226
expect(() =>
1221-
ReactDOM.render(
1222-
<input type="radio" checked={null} />,
1223-
container,
1224-
),
1227+
ReactDOM.render(<input type="radio" checked={null} />, container),
12251228
).toWarnDev(
12261229
'Warning: A component is changing a controlled input of type radio to be uncontrolled. ' +
12271230
'Input elements should not switch from controlled to uncontrolled (or vice versa). ' +

packages/react-dom/src/__tests__/ReactDOMSelect-test.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,13 @@ describe('ReactDOMSelect', () => {
654654
);
655655
});
656656

657+
it('should not warn about missing onChange in uncontrolled textareas', () => {
658+
const container = document.createElement('div');
659+
ReactDOM.render(<select />, container);
660+
ReactDOM.unmountComponentAtNode(container);
661+
ReactDOM.render(<select value={undefined} />, container);
662+
});
663+
657664
it('should be able to safely remove select onChange', () => {
658665
function changeView() {
659666
ReactDOM.unmountComponentAtNode(container);

packages/react-dom/src/__tests__/ReactDOMTextarea-test.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -387,19 +387,15 @@ describe('ReactDOMTextarea', () => {
387387

388388
it('should warn if value is null', () => {
389389
expect(() =>
390-
ReactTestUtils.renderIntoDocument(
391-
<textarea value={null} onChange={emptyFunction} />,
392-
),
390+
ReactTestUtils.renderIntoDocument(<textarea value={null} />),
393391
).toWarnDev(
394392
'`value` prop on `textarea` should not be null. ' +
395393
'Consider using an empty string to clear the component or `undefined` ' +
396394
'for uncontrolled components.',
397395
);
398396

399397
// No additional warnings are expected
400-
ReactTestUtils.renderIntoDocument(
401-
<textarea value={null} onChange={emptyFunction} />,
402-
);
398+
ReactTestUtils.renderIntoDocument(<textarea value={null} />);
403399
});
404400

405401
it('should warn if value and defaultValue are specified', () => {
@@ -420,4 +416,11 @@ describe('ReactDOMTextarea', () => {
420416
<textarea value="foo" defaultValue="bar" readOnly={true} />,
421417
);
422418
});
419+
420+
it('should not warn about missing onChange in uncontrolled textareas', () => {
421+
const container = document.createElement('div');
422+
ReactDOM.render(<textarea />, container);
423+
ReactDOM.unmountComponentAtNode(container);
424+
ReactDOM.render(<textarea value={undefined} />, container);
425+
});
423426
});

packages/react-dom/src/shared/ReactControlledValuePropTypes.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ if (__DEV__) {
3535
props.onChange ||
3636
props.readOnly ||
3737
props.disabled ||
38-
props.value === null
38+
props[propName] == null
3939
) {
4040
return null;
4141
}
@@ -52,7 +52,7 @@ if (__DEV__) {
5252
props.onChange ||
5353
props.readOnly ||
5454
props.disabled ||
55-
props.value === null
55+
props[propName] == null
5656
) {
5757
return null;
5858
}

0 commit comments

Comments
 (0)