1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @emails react-core
    
  8.  */
    
  9. 
    
  10. 'use strict';
    
  11. 
    
  12. function emptyFunction() {}
    
  13. 
    
  14. describe('ReactDOMTextarea', () => {
    
  15.   let React;
    
  16.   let ReactDOM;
    
  17.   let ReactDOMServer;
    
  18.   let ReactTestUtils;
    
  19. 
    
  20.   let renderTextarea;
    
  21. 
    
  22.   const ReactFeatureFlags = require('shared/ReactFeatureFlags');
    
  23. 
    
  24.   beforeEach(() => {
    
  25.     jest.resetModules();
    
  26. 
    
  27.     React = require('react');
    
  28.     ReactDOM = require('react-dom');
    
  29.     ReactDOMServer = require('react-dom/server');
    
  30.     ReactTestUtils = require('react-dom/test-utils');
    
  31. 
    
  32.     renderTextarea = function (component, container) {
    
  33.       if (!container) {
    
  34.         container = document.createElement('div');
    
  35.       }
    
  36.       const node = ReactDOM.render(component, container);
    
  37. 
    
  38.       // Fixing jsdom's quirky behavior -- in reality, the parser should strip
    
  39.       // off the leading newline but we need to do it by hand here.
    
  40.       node.defaultValue = node.innerHTML.replace(/^\n/, '');
    
  41.       return node;
    
  42.     };
    
  43.   });
    
  44. 
    
  45.   afterEach(() => {
    
  46.     jest.restoreAllMocks();
    
  47.   });
    
  48. 
    
  49.   it('should allow setting `defaultValue`', () => {
    
  50.     const container = document.createElement('div');
    
  51.     const node = renderTextarea(<textarea defaultValue="giraffe" />, container);
    
  52. 
    
  53.     expect(node.value).toBe('giraffe');
    
  54. 
    
  55.     // Changing `defaultValue` should do nothing.
    
  56.     renderTextarea(<textarea defaultValue="gorilla" />, container);
    
  57.     expect(node.value).toEqual('giraffe');
    
  58. 
    
  59.     node.value = 'cat';
    
  60. 
    
  61.     renderTextarea(<textarea defaultValue="monkey" />, container);
    
  62.     expect(node.value).toEqual('cat');
    
  63.   });
    
  64. 
    
  65.   it('should display `defaultValue` of number 0', () => {
    
  66.     const stub = <textarea defaultValue={0} />;
    
  67.     const node = renderTextarea(stub);
    
  68. 
    
  69.     expect(node.value).toBe('0');
    
  70.   });
    
  71. 
    
  72.   it('should display "false" for `defaultValue` of `false`', () => {
    
  73.     const stub = <textarea defaultValue={false} />;
    
  74.     const node = renderTextarea(stub);
    
  75. 
    
  76.     expect(node.value).toBe('false');
    
  77.   });
    
  78. 
    
  79.   it('should display "foobar" for `defaultValue` of `objToString`', () => {
    
  80.     const objToString = {
    
  81.       toString: function () {
    
  82.         return 'foobar';
    
  83.       },
    
  84.     };
    
  85. 
    
  86.     const stub = <textarea defaultValue={objToString} />;
    
  87.     const node = renderTextarea(stub);
    
  88. 
    
  89.     expect(node.value).toBe('foobar');
    
  90.   });
    
  91. 
    
  92.   it('should set defaultValue', () => {
    
  93.     const container = document.createElement('div');
    
  94.     ReactDOM.render(<textarea defaultValue="foo" />, container);
    
  95.     ReactDOM.render(<textarea defaultValue="bar" />, container);
    
  96.     ReactDOM.render(<textarea defaultValue="noise" />, container);
    
  97.     expect(container.firstChild.defaultValue).toBe('noise');
    
  98.   });
    
  99. 
    
  100.   it('should not render value as an attribute', () => {
    
  101.     const stub = <textarea value="giraffe" onChange={emptyFunction} />;
    
  102.     const node = renderTextarea(stub);
    
  103. 
    
  104.     expect(node.getAttribute('value')).toBe(null);
    
  105.   });
    
  106. 
    
  107.   it('should display `value` of number 0', () => {
    
  108.     const stub = <textarea value={0} onChange={emptyFunction} />;
    
  109.     const node = renderTextarea(stub);
    
  110. 
    
  111.     expect(node.value).toBe('0');
    
  112.   });
    
  113. 
    
  114.   it('should update defaultValue to empty string', () => {
    
  115.     const container = document.createElement('div');
    
  116.     ReactDOM.render(<textarea defaultValue={'foo'} />, container);
    
  117.     ReactDOM.render(<textarea defaultValue={''} />, container);
    
  118.     expect(container.firstChild.defaultValue).toBe('');
    
  119.   });
    
  120. 
    
  121.   it('should allow setting `value` to `giraffe`', () => {
    
  122.     const container = document.createElement('div');
    
  123.     let stub = <textarea value="giraffe" onChange={emptyFunction} />;
    
  124.     const node = renderTextarea(stub, container);
    
  125. 
    
  126.     expect(node.value).toBe('giraffe');
    
  127. 
    
  128.     stub = ReactDOM.render(
    
  129.       <textarea value="gorilla" onChange={emptyFunction} />,
    
  130.       container,
    
  131.     );
    
  132.     expect(node.value).toEqual('gorilla');
    
  133.   });
    
  134. 
    
  135.   it('will not initially assign an empty value (covers case where firefox throws a validation error when required attribute is set)', () => {
    
  136.     const container = document.createElement('div');
    
  137. 
    
  138.     let counter = 0;
    
  139.     const originalCreateElement = document.createElement;
    
  140.     spyOnDevAndProd(document, 'createElement').mockImplementation(
    
  141.       function (type) {
    
  142.         const el = originalCreateElement.apply(this, arguments);
    
  143.         let value = '';
    
  144.         if (type === 'textarea') {
    
  145.           Object.defineProperty(el, 'value', {
    
  146.             get: function () {
    
  147.               return value;
    
  148.             },
    
  149.             set: function (val) {
    
  150.               value = String(val);
    
  151.               counter++;
    
  152.             },
    
  153.           });
    
  154.         }
    
  155.         return el;
    
  156.       },
    
  157.     );
    
  158. 
    
  159.     ReactDOM.render(<textarea value="" readOnly={true} />, container);
    
  160. 
    
  161.     expect(counter).toEqual(0);
    
  162.   });
    
  163. 
    
  164.   it('should render defaultValue for SSR', () => {
    
  165.     const markup = ReactDOMServer.renderToString(<textarea defaultValue="1" />);
    
  166.     const div = document.createElement('div');
    
  167.     div.innerHTML = markup;
    
  168.     expect(div.firstChild.innerHTML).toBe('1');
    
  169.     expect(div.firstChild.getAttribute('defaultValue')).toBe(null);
    
  170.   });
    
  171. 
    
  172.   it('should render value for SSR', () => {
    
  173.     const element = <textarea value="1" onChange={function () {}} />;
    
  174.     const markup = ReactDOMServer.renderToString(element);
    
  175.     const div = document.createElement('div');
    
  176.     div.innerHTML = markup;
    
  177.     expect(div.firstChild.innerHTML).toBe('1');
    
  178.     expect(div.firstChild.getAttribute('defaultValue')).toBe(null);
    
  179.   });
    
  180. 
    
  181.   it('should allow setting `value` to `true`', () => {
    
  182.     const container = document.createElement('div');
    
  183.     let stub = <textarea value="giraffe" onChange={emptyFunction} />;
    
  184.     const node = renderTextarea(stub, container);
    
  185. 
    
  186.     expect(node.value).toBe('giraffe');
    
  187. 
    
  188.     stub = ReactDOM.render(
    
  189.       <textarea value={true} onChange={emptyFunction} />,
    
  190.       container,
    
  191.     );
    
  192.     expect(node.value).toEqual('true');
    
  193.   });
    
  194. 
    
  195.   it('should allow setting `value` to `false`', () => {
    
  196.     const container = document.createElement('div');
    
  197.     let stub = <textarea value="giraffe" onChange={emptyFunction} />;
    
  198.     const node = renderTextarea(stub, container);
    
  199. 
    
  200.     expect(node.value).toBe('giraffe');
    
  201. 
    
  202.     stub = ReactDOM.render(
    
  203.       <textarea value={false} onChange={emptyFunction} />,
    
  204.       container,
    
  205.     );
    
  206.     expect(node.value).toEqual('false');
    
  207.   });
    
  208. 
    
  209.   it('should allow setting `value` to `objToString`', () => {
    
  210.     const container = document.createElement('div');
    
  211.     let stub = <textarea value="giraffe" onChange={emptyFunction} />;
    
  212.     const node = renderTextarea(stub, container);
    
  213. 
    
  214.     expect(node.value).toBe('giraffe');
    
  215. 
    
  216.     const objToString = {
    
  217.       toString: function () {
    
  218.         return 'foo';
    
  219.       },
    
  220.     };
    
  221.     stub = ReactDOM.render(
    
  222.       <textarea value={objToString} onChange={emptyFunction} />,
    
  223.       container,
    
  224.     );
    
  225.     expect(node.value).toEqual('foo');
    
  226.   });
    
  227. 
    
  228.   it('should throw when value is set to a Temporal-like object', () => {
    
  229.     class TemporalLike {
    
  230.       valueOf() {
    
  231.         // Throwing here is the behavior of ECMAScript "Temporal" date/time API.
    
  232.         // See https://tc39.es/proposal-temporal/docs/plaindate.html#valueOf
    
  233.         throw new TypeError('prod message');
    
  234.       }
    
  235.       toString() {
    
  236.         return '2020-01-01';
    
  237.       }
    
  238.     }
    
  239.     const container = document.createElement('div');
    
  240.     const stub = <textarea value="giraffe" onChange={emptyFunction} />;
    
  241.     const node = renderTextarea(stub, container);
    
  242. 
    
  243.     expect(node.value).toBe('giraffe');
    
  244. 
    
  245.     const test = () =>
    
  246.       ReactDOM.render(
    
  247.         <textarea value={new TemporalLike()} onChange={emptyFunction} />,
    
  248.         container,
    
  249.       );
    
  250.     expect(() =>
    
  251.       expect(test).toThrowError(new TypeError('prod message')),
    
  252.     ).toErrorDev(
    
  253.       'Form field values (value, checked, defaultValue, or defaultChecked props) must be ' +
    
  254.         'strings, not TemporalLike. This value must be coerced to a string before using it here.',
    
  255.     );
    
  256.   });
    
  257. 
    
  258.   it('should take updates to `defaultValue` for uncontrolled textarea', () => {
    
  259.     const container = document.createElement('div');
    
  260. 
    
  261.     const node = ReactDOM.render(<textarea defaultValue="0" />, container);
    
  262. 
    
  263.     expect(node.value).toBe('0');
    
  264. 
    
  265.     ReactDOM.render(<textarea defaultValue="1" />, container);
    
  266. 
    
  267.     expect(node.value).toBe('0');
    
  268.   });
    
  269. 
    
  270.   it('should take updates to children in lieu of `defaultValue` for uncontrolled textarea', () => {
    
  271.     const container = document.createElement('div');
    
  272. 
    
  273.     const node = ReactDOM.render(<textarea defaultValue="0" />, container);
    
  274. 
    
  275.     expect(node.value).toBe('0');
    
  276. 
    
  277.     ReactDOM.render(<textarea>1</textarea>, container);
    
  278. 
    
  279.     expect(node.value).toBe('0');
    
  280.   });
    
  281. 
    
  282.   it('should not incur unnecessary DOM mutations', () => {
    
  283.     const container = document.createElement('div');
    
  284.     ReactDOM.render(<textarea value="a" onChange={emptyFunction} />, container);
    
  285. 
    
  286.     const node = container.firstChild;
    
  287.     let nodeValue = 'a';
    
  288.     const nodeValueSetter = jest.fn();
    
  289.     Object.defineProperty(node, 'value', {
    
  290.       get: function () {
    
  291.         return nodeValue;
    
  292.       },
    
  293.       set: nodeValueSetter.mockImplementation(function (newValue) {
    
  294.         nodeValue = newValue;
    
  295.       }),
    
  296.     });
    
  297. 
    
  298.     ReactDOM.render(<textarea value="a" onChange={emptyFunction} />, container);
    
  299.     expect(nodeValueSetter).toHaveBeenCalledTimes(0);
    
  300. 
    
  301.     ReactDOM.render(<textarea value="b" onChange={emptyFunction} />, container);
    
  302.     expect(nodeValueSetter).toHaveBeenCalledTimes(1);
    
  303.   });
    
  304. 
    
  305.   it('should properly control a value of number `0`', () => {
    
  306.     const stub = <textarea value={0} onChange={emptyFunction} />;
    
  307.     const setUntrackedValue = Object.getOwnPropertyDescriptor(
    
  308.       HTMLTextAreaElement.prototype,
    
  309.       'value',
    
  310.     ).set;
    
  311. 
    
  312.     const container = document.createElement('div');
    
  313.     document.body.appendChild(container);
    
  314. 
    
  315.     try {
    
  316.       const node = renderTextarea(stub, container);
    
  317. 
    
  318.       setUntrackedValue.call(node, 'giraffe');
    
  319.       node.dispatchEvent(
    
  320.         new Event('input', {bubbles: true, cancelable: false}),
    
  321.       );
    
  322.       expect(node.value).toBe('0');
    
  323.     } finally {
    
  324.       document.body.removeChild(container);
    
  325.     }
    
  326.   });
    
  327. 
    
  328.   if (ReactFeatureFlags.disableTextareaChildren) {
    
  329.     it('should ignore children content', () => {
    
  330.       const container = document.createElement('div');
    
  331.       let stub = <textarea>giraffe</textarea>;
    
  332.       let node;
    
  333. 
    
  334.       expect(() => {
    
  335.         node = renderTextarea(stub, container);
    
  336.       }).toErrorDev(
    
  337.         'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
    
  338.       );
    
  339.       expect(node.value).toBe('');
    
  340.       // Changing children should do nothing, it functions like `defaultValue`.
    
  341.       stub = ReactDOM.render(<textarea>gorilla</textarea>, container);
    
  342.       expect(node.value).toEqual('');
    
  343.     });
    
  344.   }
    
  345. 
    
  346.   if (ReactFeatureFlags.disableTextareaChildren) {
    
  347.     it('should receive defaultValue and still ignore children content', () => {
    
  348.       let node;
    
  349. 
    
  350.       expect(() => {
    
  351.         node = renderTextarea(
    
  352.           <textarea defaultValue="dragon">monkey</textarea>,
    
  353.         );
    
  354.       }).toErrorDev(
    
  355.         'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
    
  356.       );
    
  357.       expect(node.value).toBe('dragon');
    
  358.     });
    
  359.   }
    
  360. 
    
  361.   if (!ReactFeatureFlags.disableTextareaChildren) {
    
  362.     it('should treat children like `defaultValue`', () => {
    
  363.       const container = document.createElement('div');
    
  364.       let stub = <textarea>giraffe</textarea>;
    
  365.       let node;
    
  366. 
    
  367.       expect(() => {
    
  368.         node = renderTextarea(stub, container);
    
  369.       }).toErrorDev(
    
  370.         'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
    
  371.       );
    
  372. 
    
  373.       expect(node.value).toBe('giraffe');
    
  374. 
    
  375.       // Changing children should do nothing, it functions like `defaultValue`.
    
  376.       stub = ReactDOM.render(<textarea>gorilla</textarea>, container);
    
  377.       expect(node.value).toEqual('giraffe');
    
  378.     });
    
  379.   }
    
  380. 
    
  381.   it('should keep value when switching to uncontrolled element if not changed', () => {
    
  382.     const container = document.createElement('div');
    
  383. 
    
  384.     const node = renderTextarea(
    
  385.       <textarea value="kitten" onChange={emptyFunction} />,
    
  386.       container,
    
  387.     );
    
  388. 
    
  389.     expect(node.value).toBe('kitten');
    
  390. 
    
  391.     ReactDOM.render(<textarea defaultValue="gorilla" />, container);
    
  392. 
    
  393.     expect(node.value).toEqual('kitten');
    
  394.   });
    
  395. 
    
  396.   it('should keep value when switching to uncontrolled element if changed', () => {
    
  397.     const container = document.createElement('div');
    
  398. 
    
  399.     const node = renderTextarea(
    
  400.       <textarea value="kitten" onChange={emptyFunction} />,
    
  401.       container,
    
  402.     );
    
  403. 
    
  404.     expect(node.value).toBe('kitten');
    
  405. 
    
  406.     ReactDOM.render(
    
  407.       <textarea value="puppies" onChange={emptyFunction} />,
    
  408.       container,
    
  409.     );
    
  410. 
    
  411.     expect(node.value).toBe('puppies');
    
  412. 
    
  413.     ReactDOM.render(<textarea defaultValue="gorilla" />, container);
    
  414. 
    
  415.     expect(node.value).toEqual('puppies');
    
  416.   });
    
  417. 
    
  418.   if (ReactFeatureFlags.disableTextareaChildren) {
    
  419.     it('should ignore numbers as children', () => {
    
  420.       let node;
    
  421.       expect(() => {
    
  422.         node = renderTextarea(<textarea>{17}</textarea>);
    
  423.       }).toErrorDev(
    
  424.         'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
    
  425.       );
    
  426.       expect(node.value).toBe('');
    
  427.     });
    
  428.   }
    
  429. 
    
  430.   if (!ReactFeatureFlags.disableTextareaChildren) {
    
  431.     it('should allow numbers as children', () => {
    
  432.       let node;
    
  433.       expect(() => {
    
  434.         node = renderTextarea(<textarea>{17}</textarea>);
    
  435.       }).toErrorDev(
    
  436.         'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
    
  437.       );
    
  438.       expect(node.value).toBe('17');
    
  439.     });
    
  440.   }
    
  441. 
    
  442.   if (ReactFeatureFlags.disableTextareaChildren) {
    
  443.     it('should ignore booleans as children', () => {
    
  444.       let node;
    
  445.       expect(() => {
    
  446.         node = renderTextarea(<textarea>{false}</textarea>);
    
  447.       }).toErrorDev(
    
  448.         'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
    
  449.       );
    
  450.       expect(node.value).toBe('');
    
  451.     });
    
  452.   }
    
  453. 
    
  454.   if (!ReactFeatureFlags.disableTextareaChildren) {
    
  455.     it('should allow booleans as children', () => {
    
  456.       let node;
    
  457.       expect(() => {
    
  458.         node = renderTextarea(<textarea>{false}</textarea>);
    
  459.       }).toErrorDev(
    
  460.         'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
    
  461.       );
    
  462.       expect(node.value).toBe('false');
    
  463.     });
    
  464.   }
    
  465. 
    
  466.   if (ReactFeatureFlags.disableTextareaChildren) {
    
  467.     it('should ignore objects as children', () => {
    
  468.       const obj = {
    
  469.         toString: function () {
    
  470.           return 'sharkswithlasers';
    
  471.         },
    
  472.       };
    
  473.       let node;
    
  474.       expect(() => {
    
  475.         node = renderTextarea(<textarea>{obj}</textarea>);
    
  476.       }).toErrorDev(
    
  477.         'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
    
  478.       );
    
  479.       expect(node.value).toBe('');
    
  480.     });
    
  481.   }
    
  482. 
    
  483.   if (!ReactFeatureFlags.disableTextareaChildren) {
    
  484.     it('should allow objects as children', () => {
    
  485.       const obj = {
    
  486.         toString: function () {
    
  487.           return 'sharkswithlasers';
    
  488.         },
    
  489.       };
    
  490.       let node;
    
  491.       expect(() => {
    
  492.         node = renderTextarea(<textarea>{obj}</textarea>);
    
  493.       }).toErrorDev(
    
  494.         'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
    
  495.       );
    
  496.       expect(node.value).toBe('sharkswithlasers');
    
  497.     });
    
  498.   }
    
  499. 
    
  500.   if (!ReactFeatureFlags.disableTextareaChildren) {
    
  501.     it('should throw with multiple or invalid children', () => {
    
  502.       expect(() => {
    
  503.         expect(() =>
    
  504.           ReactTestUtils.renderIntoDocument(
    
  505.             <textarea>
    
  506.               {'hello'}
    
  507.               {'there'}
    
  508.             </textarea>,
    
  509.           ),
    
  510.         ).toThrow('<textarea> can only have at most one child');
    
  511.       }).toErrorDev(
    
  512.         'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
    
  513.       );
    
  514. 
    
  515.       let node;
    
  516.       expect(() => {
    
  517.         expect(
    
  518.           () =>
    
  519.             (node = renderTextarea(
    
  520.               <textarea>
    
  521.                 <strong />
    
  522.               </textarea>,
    
  523.             )),
    
  524.         ).not.toThrow();
    
  525.       }).toErrorDev(
    
  526.         'Use the `defaultValue` or `value` props instead of setting children on <textarea>.',
    
  527.       );
    
  528. 
    
  529.       expect(node.value).toBe('[object Object]');
    
  530.     });
    
  531.   }
    
  532. 
    
  533.   it('should unmount', () => {
    
  534.     const container = document.createElement('div');
    
  535.     renderTextarea(<textarea />, container);
    
  536.     ReactDOM.unmountComponentAtNode(container);
    
  537.   });
    
  538. 
    
  539.   it('should warn if value is null', () => {
    
  540.     expect(() =>
    
  541.       ReactTestUtils.renderIntoDocument(<textarea value={null} />),
    
  542.     ).toErrorDev(
    
  543.       '`value` prop on `textarea` should not be null. ' +
    
  544.         'Consider using an empty string to clear the component or `undefined` ' +
    
  545.         'for uncontrolled components.',
    
  546.     );
    
  547. 
    
  548.     // No additional warnings are expected
    
  549.     ReactTestUtils.renderIntoDocument(<textarea value={null} />);
    
  550.   });
    
  551. 
    
  552.   it('should warn if value and defaultValue are specified', () => {
    
  553.     const InvalidComponent = () => (
    
  554.       <textarea value="foo" defaultValue="bar" readOnly={true} />
    
  555.     );
    
  556.     expect(() =>
    
  557.       ReactTestUtils.renderIntoDocument(<InvalidComponent />),
    
  558.     ).toErrorDev(
    
  559.       'InvalidComponent contains a textarea with both value and defaultValue props. ' +
    
  560.         'Textarea elements must be either controlled or uncontrolled ' +
    
  561.         '(specify either the value prop, or the defaultValue prop, but not ' +
    
  562.         'both). Decide between using a controlled or uncontrolled textarea ' +
    
  563.         'and remove one of these props. More info: ' +
    
  564.         'https://reactjs.org/link/controlled-components',
    
  565.     );
    
  566. 
    
  567.     // No additional warnings are expected
    
  568.     ReactTestUtils.renderIntoDocument(<InvalidComponent />);
    
  569.   });
    
  570. 
    
  571.   it('should not warn about missing onChange in uncontrolled textareas', () => {
    
  572.     const container = document.createElement('div');
    
  573.     ReactDOM.render(<textarea />, container);
    
  574.     ReactDOM.unmountComponentAtNode(container);
    
  575.     ReactDOM.render(<textarea value={undefined} />, container);
    
  576.   });
    
  577. 
    
  578.   it('does not set textContent if value is unchanged', () => {
    
  579.     const container = document.createElement('div');
    
  580.     let node;
    
  581.     let instance;
    
  582.     // Setting defaultValue on a textarea is equivalent to setting textContent,
    
  583.     // and is the method we currently use, so we can observe if defaultValue is
    
  584.     // is set to determine if textContent is being recreated.
    
  585.     // https://html.spec.whatwg.org/#the-textarea-element
    
  586.     let defaultValue;
    
  587.     const set = jest.fn(value => {
    
  588.       defaultValue = value;
    
  589.     });
    
  590.     const get = jest.fn(value => {
    
  591.       return defaultValue;
    
  592.     });
    
  593.     class App extends React.Component {
    
  594.       state = {count: 0, text: 'foo'};
    
  595.       componentDidMount() {
    
  596.         instance = this;
    
  597.       }
    
  598.       render() {
    
  599.         return (
    
  600.           <div>
    
  601.             <span>{this.state.count}</span>
    
  602.             <textarea
    
  603.               ref={n => (node = n)}
    
  604.               value="foo"
    
  605.               onChange={emptyFunction}
    
  606.               data-count={this.state.count}
    
  607.             />
    
  608.           </div>
    
  609.         );
    
  610.       }
    
  611.     }
    
  612.     ReactDOM.render(<App />, container);
    
  613.     defaultValue = node.defaultValue;
    
  614.     Object.defineProperty(node, 'defaultValue', {get, set});
    
  615.     instance.setState({count: 1});
    
  616.     expect(set.mock.calls.length).toBe(0);
    
  617.   });
    
  618. 
    
  619.   describe('When given a Symbol value', () => {
    
  620.     it('treats initial Symbol value as an empty string', () => {
    
  621.       const container = document.createElement('div');
    
  622.       expect(() =>
    
  623.         ReactDOM.render(
    
  624.           <textarea value={Symbol('foobar')} onChange={() => {}} />,
    
  625.           container,
    
  626.         ),
    
  627.       ).toErrorDev('Invalid value for prop `value`');
    
  628.       const node = container.firstChild;
    
  629. 
    
  630.       expect(node.value).toBe('');
    
  631.     });
    
  632. 
    
  633.     it('treats initial Symbol children as an empty string', () => {
    
  634.       const container = document.createElement('div');
    
  635.       expect(() =>
    
  636.         ReactDOM.render(
    
  637.           <textarea onChange={() => {}}>{Symbol('foo')}</textarea>,
    
  638.           container,
    
  639.         ),
    
  640.       ).toErrorDev('Use the `defaultValue` or `value` props');
    
  641.       const node = container.firstChild;
    
  642. 
    
  643.       expect(node.value).toBe('');
    
  644.     });
    
  645. 
    
  646.     it('treats updated Symbol value as an empty string', () => {
    
  647.       const container = document.createElement('div');
    
  648.       ReactDOM.render(<textarea value="foo" onChange={() => {}} />, container);
    
  649.       expect(() =>
    
  650.         ReactDOM.render(
    
  651.           <textarea value={Symbol('foo')} onChange={() => {}} />,
    
  652.           container,
    
  653.         ),
    
  654.       ).toErrorDev('Invalid value for prop `value`');
    
  655.       const node = container.firstChild;
    
  656. 
    
  657.       expect(node.value).toBe('');
    
  658.     });
    
  659. 
    
  660.     it('treats initial Symbol defaultValue as an empty string', () => {
    
  661.       const container = document.createElement('div');
    
  662.       ReactDOM.render(<textarea defaultValue={Symbol('foobar')} />, container);
    
  663.       const node = container.firstChild;
    
  664. 
    
  665.       // TODO: defaultValue is a reserved prop and is not validated. Check warnings when they are.
    
  666.       expect(node.value).toBe('');
    
  667.     });
    
  668. 
    
  669.     it('treats updated Symbol defaultValue as an empty string', () => {
    
  670.       const container = document.createElement('div');
    
  671.       ReactDOM.render(<textarea defaultValue="foo" />, container);
    
  672.       ReactDOM.render(<textarea defaultValue={Symbol('foobar')} />, container);
    
  673.       const node = container.firstChild;
    
  674. 
    
  675.       // TODO: defaultValue is a reserved prop and is not validated. Check warnings when they are.
    
  676.       expect(node.value).toBe('foo');
    
  677.     });
    
  678.   });
    
  679. 
    
  680.   describe('When given a function value', () => {
    
  681.     it('treats initial function value as an empty string', () => {
    
  682.       const container = document.createElement('div');
    
  683.       expect(() =>
    
  684.         ReactDOM.render(
    
  685.           <textarea value={() => {}} onChange={() => {}} />,
    
  686.           container,
    
  687.         ),
    
  688.       ).toErrorDev('Invalid value for prop `value`');
    
  689.       const node = container.firstChild;
    
  690. 
    
  691.       expect(node.value).toBe('');
    
  692.     });
    
  693. 
    
  694.     it('treats initial function children as an empty string', () => {
    
  695.       const container = document.createElement('div');
    
  696.       expect(() =>
    
  697.         ReactDOM.render(
    
  698.           <textarea onChange={() => {}}>{() => {}}</textarea>,
    
  699.           container,
    
  700.         ),
    
  701.       ).toErrorDev('Use the `defaultValue` or `value` props');
    
  702.       const node = container.firstChild;
    
  703. 
    
  704.       expect(node.value).toBe('');
    
  705.     });
    
  706. 
    
  707.     it('treats updated function value as an empty string', () => {
    
  708.       const container = document.createElement('div');
    
  709.       ReactDOM.render(<textarea value="foo" onChange={() => {}} />, container);
    
  710.       expect(() =>
    
  711.         ReactDOM.render(
    
  712.           <textarea value={() => {}} onChange={() => {}} />,
    
  713.           container,
    
  714.         ),
    
  715.       ).toErrorDev('Invalid value for prop `value`');
    
  716.       const node = container.firstChild;
    
  717. 
    
  718.       expect(node.value).toBe('');
    
  719.     });
    
  720. 
    
  721.     it('treats initial function defaultValue as an empty string', () => {
    
  722.       const container = document.createElement('div');
    
  723.       ReactDOM.render(<textarea defaultValue={() => {}} />, container);
    
  724.       const node = container.firstChild;
    
  725. 
    
  726.       // TODO: defaultValue is a reserved prop and is not validated. Check warnings when they are.
    
  727.       expect(node.value).toBe('');
    
  728.     });
    
  729. 
    
  730.     it('treats updated function defaultValue as an empty string', () => {
    
  731.       const container = document.createElement('div');
    
  732.       ReactDOM.render(<textarea defaultValue="foo" />, container);
    
  733.       ReactDOM.render(<textarea defaultValue={() => {}} />, container);
    
  734.       const node = container.firstChild;
    
  735. 
    
  736.       // TODO: defaultValue is a reserved prop and is not validated. Check warnings when they are.
    
  737.       expect(node.value).toBe('foo');
    
  738.     });
    
  739.   });
    
  740. 
    
  741.   it('should remove previous `defaultValue`', () => {
    
  742.     const container = document.createElement('div');
    
  743.     const node = ReactDOM.render(<textarea defaultValue="0" />, container);
    
  744. 
    
  745.     expect(node.value).toBe('0');
    
  746.     expect(node.defaultValue).toBe('0');
    
  747. 
    
  748.     ReactDOM.render(<textarea />, container);
    
  749.     expect(node.defaultValue).toBe('');
    
  750.   });
    
  751. 
    
  752.   it('should treat `defaultValue={null}` as missing', () => {
    
  753.     const container = document.createElement('div');
    
  754.     const node = ReactDOM.render(<textarea defaultValue="0" />, container);
    
  755. 
    
  756.     expect(node.value).toBe('0');
    
  757.     expect(node.defaultValue).toBe('0');
    
  758. 
    
  759.     ReactDOM.render(<textarea defaultValue={null} />, container);
    
  760.     expect(node.defaultValue).toBe('');
    
  761.   });
    
  762. });