@@ -1043,6 +1043,63 @@ describe('ReactDOMComponent', () => {
10431043      expect ( nodeValueSetter ) . toHaveBeenCalledTimes ( 2 ) ; 
10441044    } ) ; 
10451045
1046+     it ( 'should not incur unnecessary DOM mutations for controlled string properties' ,  ( )  =>  { 
1047+       function  onChange ( )  { } 
1048+       const  container  =  document . createElement ( 'div' ) ; 
1049+       ReactDOM . render ( < input  value = ""  onChange = { onChange }  /> ,  container ) ; 
1050+ 
1051+       const  node  =  container . firstChild ; 
1052+ 
1053+       let  nodeValue  =  '' ; 
1054+       const  nodeValueSetter  =  jest . fn ( ) ; 
1055+       Object . defineProperty ( node ,  'value' ,  { 
1056+         get : function  ( )  { 
1057+           return  nodeValue ; 
1058+         } , 
1059+         set : nodeValueSetter . mockImplementation ( function  ( newValue )  { 
1060+           nodeValue  =  newValue ; 
1061+         } ) , 
1062+       } ) ; 
1063+ 
1064+       ReactDOM . render ( < input  value = "foo"  onChange = { onChange }  /> ,  container ) ; 
1065+       expect ( nodeValueSetter ) . toHaveBeenCalledTimes ( 1 ) ; 
1066+ 
1067+       ReactDOM . render ( 
1068+         < input  value = "foo"  data-unrelated = { true }  onChange = { onChange }  /> , 
1069+         container , 
1070+       ) ; 
1071+       expect ( nodeValueSetter ) . toHaveBeenCalledTimes ( 1 ) ; 
1072+ 
1073+       expect ( ( )  =>  { 
1074+         ReactDOM . render ( < input  onChange = { onChange }  /> ,  container ) ; 
1075+       } ) . toErrorDev ( 
1076+         'A component is changing a controlled input to be uncontrolled. This is likely caused by '  + 
1077+           'the value changing from a defined to undefined, which should not happen. Decide between '  + 
1078+           'using a controlled or uncontrolled input element for the lifetime of the component.' , 
1079+       ) ; 
1080+       expect ( nodeValueSetter ) . toHaveBeenCalledTimes ( 1 ) ; 
1081+ 
1082+       expect ( ( )  =>  { 
1083+         ReactDOM . render ( < input  value = { null }  onChange = { onChange }  /> ,  container ) ; 
1084+       } ) . toErrorDev ( 
1085+         'value` prop on `input` should not be null. Consider using an empty string to clear the '  + 
1086+           'component or `undefined` for uncontrolled components.' , 
1087+       ) ; 
1088+       expect ( nodeValueSetter ) . toHaveBeenCalledTimes ( 1 ) ; 
1089+ 
1090+       expect ( ( )  =>  { 
1091+         ReactDOM . render ( < input  value = ""  onChange = { onChange }  /> ,  container ) ; 
1092+       } ) . toErrorDev ( 
1093+         ' A component is changing an uncontrolled input to be controlled. This is likely caused by '  + 
1094+           'the value changing from undefined to a defined value, which should not happen. Decide between '  + 
1095+           'using a controlled or uncontrolled input element for the lifetime of the component.' , 
1096+       ) ; 
1097+       expect ( nodeValueSetter ) . toHaveBeenCalledTimes ( 2 ) ; 
1098+ 
1099+       ReactDOM . render ( < input  onChange = { onChange }  /> ,  container ) ; 
1100+       expect ( nodeValueSetter ) . toHaveBeenCalledTimes ( 2 ) ; 
1101+     } ) ; 
1102+ 
10461103    it ( 'should not incur unnecessary DOM mutations for boolean properties' ,  ( )  =>  { 
10471104      const  container  =  document . createElement ( 'div' ) ; 
10481105      function  onChange ( )  { 
@@ -1066,7 +1123,12 @@ describe('ReactDOMComponent', () => {
10661123      } ) ; 
10671124
10681125      ReactDOM . render ( 
1069-         < input  type = "checkbox"  onChange = { onChange }  checked = { true }  /> , 
1126+         < input 
1127+           type = "checkbox" 
1128+           onChange = { onChange } 
1129+           checked = { true } 
1130+           data-unrelated = { true } 
1131+         /> , 
10701132        container , 
10711133      ) ; 
10721134      expect ( nodeValueSetter ) . toHaveBeenCalledTimes ( 0 ) ; 
@@ -1094,15 +1156,13 @@ describe('ReactDOMComponent', () => {
10941156          'using a controlled or uncontrolled input element for the lifetime of the component.' , 
10951157      ) ; 
10961158
1097-       // TODO: Non-null values are updated twice on inputs. This is should ideally be fixed. 
1098-       expect ( nodeValueSetter ) . toHaveBeenCalledTimes ( 3 ) ; 
1159+       expect ( nodeValueSetter ) . toHaveBeenCalledTimes ( 2 ) ; 
10991160
11001161      ReactDOM . render ( 
11011162        < input  type = "checkbox"  onChange = { onChange }  checked = { true }  /> , 
11021163        container , 
11031164      ) ; 
1104-       // TODO: Non-null values are updated twice on inputs. This is should ideally be fixed. 
1105-       expect ( nodeValueSetter ) . toHaveBeenCalledTimes ( 5 ) ; 
1165+       expect ( nodeValueSetter ) . toHaveBeenCalledTimes ( 3 ) ; 
11061166    } ) ; 
11071167
11081168    it ( 'should ignore attribute list for elements with the "is" attribute' ,  ( )  =>  { 
0 commit comments