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. // These tests are based on ReactJSXElement-test,
    
  11. // ReactJSXElementValidator-test, ReactComponent-test,
    
  12. // and ReactElementJSX-test.
    
  13. 
    
  14. jest.mock('react/jsx-runtime', () => require('./jsx-runtime'), {virtual: true});
    
  15. jest.mock('react/jsx-dev-runtime', () => require('./jsx-dev-runtime'), {
    
  16.   virtual: true,
    
  17. });
    
  18. 
    
  19. let React = require('react');
    
  20. let ReactDOM = require('react-dom');
    
  21. let ReactTestUtils = {
    
  22.   renderIntoDocument(el) {
    
  23.     const container = document.createElement('div');
    
  24.     return ReactDOM.render(el, container);
    
  25.   },
    
  26. };
    
  27. let PropTypes = require('prop-types');
    
  28. let Component = class Component extends React.Component {
    
  29.   render() {
    
  30.     return <div />;
    
  31.   }
    
  32. };
    
  33. let RequiredPropComponent = class extends React.Component {
    
  34.   render() {
    
  35.     return <span>{this.props.prop}</span>;
    
  36.   }
    
  37. };
    
  38. RequiredPropComponent.displayName = 'RequiredPropComponent';
    
  39. RequiredPropComponent.propTypes = {prop: PropTypes.string.isRequired};
    
  40. 
    
  41. it('works', () => {
    
  42.   const container = document.createElement('div');
    
  43.   ReactDOM.render(<h1>hello</h1>, container);
    
  44.   expect(container.textContent).toBe('hello');
    
  45. });
    
  46. 
    
  47. it('returns a complete element according to spec', () => {
    
  48.   const element = <Component />;
    
  49.   expect(element.type).toBe(Component);
    
  50.   expect(element.key).toBe(null);
    
  51.   expect(element.ref).toBe(null);
    
  52.   const expectation = {};
    
  53.   Object.freeze(expectation);
    
  54.   expect(element.props).toEqual(expectation);
    
  55. });
    
  56. 
    
  57. it('allows a lower-case to be passed as the string type', () => {
    
  58.   const element = <div />;
    
  59.   expect(element.type).toBe('div');
    
  60.   expect(element.key).toBe(null);
    
  61.   expect(element.ref).toBe(null);
    
  62.   const expectation = {};
    
  63.   Object.freeze(expectation);
    
  64.   expect(element.props).toEqual(expectation);
    
  65. });
    
  66. 
    
  67. it('allows a string to be passed as the type', () => {
    
  68.   const TagName = 'div';
    
  69.   const element = <TagName />;
    
  70.   expect(element.type).toBe('div');
    
  71.   expect(element.key).toBe(null);
    
  72.   expect(element.ref).toBe(null);
    
  73.   const expectation = {};
    
  74.   Object.freeze(expectation);
    
  75.   expect(element.props).toEqual(expectation);
    
  76. });
    
  77. 
    
  78. it('returns an immutable element', () => {
    
  79.   const element = <Component />;
    
  80.   if (process.env.NODE_ENV === 'development') {
    
  81.     expect(() => (element.type = 'div')).toThrow();
    
  82.   } else {
    
  83.     expect(() => (element.type = 'div')).not.toThrow();
    
  84.   }
    
  85. });
    
  86. 
    
  87. it('does not reuse the object that is spread into props', () => {
    
  88.   const config = {foo: 1};
    
  89.   const element = <Component {...config} />;
    
  90.   expect(element.props.foo).toBe(1);
    
  91.   config.foo = 2;
    
  92.   expect(element.props.foo).toBe(1);
    
  93. });
    
  94. 
    
  95. it('extracts key and ref from the rest of the props', () => {
    
  96.   const element = <Component key="12" ref="34" foo="56" />;
    
  97.   expect(element.type).toBe(Component);
    
  98.   expect(element.key).toBe('12');
    
  99.   expect(element.ref).toBe('34');
    
  100.   const expectation = {foo: '56'};
    
  101.   Object.freeze(expectation);
    
  102.   expect(element.props).toEqual(expectation);
    
  103. });
    
  104. 
    
  105. it('coerces the key to a string', () => {
    
  106.   const element = <Component key={12} foo="56" />;
    
  107.   expect(element.type).toBe(Component);
    
  108.   expect(element.key).toBe('12');
    
  109.   expect(element.ref).toBe(null);
    
  110.   const expectation = {foo: '56'};
    
  111.   Object.freeze(expectation);
    
  112.   expect(element.props).toEqual(expectation);
    
  113. });
    
  114. 
    
  115. it('merges JSX children onto the children prop', () => {
    
  116.   const a = 1;
    
  117.   const element = <Component children="text">{a}</Component>;
    
  118.   expect(element.props.children).toBe(a);
    
  119. });
    
  120. 
    
  121. it('does not override children if no JSX children are provided', () => {
    
  122.   const element = <Component children="text" />;
    
  123.   expect(element.props.children).toBe('text');
    
  124. });
    
  125. 
    
  126. it('overrides children if null is provided as a JSX child', () => {
    
  127.   const element = <Component children="text">{null}</Component>;
    
  128.   expect(element.props.children).toBe(null);
    
  129. });
    
  130. 
    
  131. it('overrides children if undefined is provided as an argument', () => {
    
  132.   const element = <Component children="text">{undefined}</Component>;
    
  133.   expect(element.props.children).toBe(undefined);
    
  134. 
    
  135.   const element2 = React.cloneElement(
    
  136.     <Component children="text" />,
    
  137.     {},
    
  138.     undefined
    
  139.   );
    
  140.   expect(element2.props.children).toBe(undefined);
    
  141. });
    
  142. 
    
  143. it('merges JSX children onto the children prop in an array', () => {
    
  144.   const a = 1;
    
  145.   const b = 2;
    
  146.   const c = 3;
    
  147.   const element = (
    
  148.     <Component>
    
  149.       {a}
    
  150.       {b}
    
  151.       {c}
    
  152.     </Component>
    
  153.   );
    
  154.   expect(element.props.children).toEqual([1, 2, 3]);
    
  155. });
    
  156. 
    
  157. it('allows static methods to be called using the type property', () => {
    
  158.   class StaticMethodComponent {
    
  159.     static someStaticMethod() {
    
  160.       return 'someReturnValue';
    
  161.     }
    
  162.     render() {
    
  163.       return <div />;
    
  164.     }
    
  165.   }
    
  166. 
    
  167.   const element = <StaticMethodComponent />;
    
  168.   expect(element.type.someStaticMethod()).toBe('someReturnValue');
    
  169. });
    
  170. 
    
  171. it('identifies valid elements', () => {
    
  172.   expect(React.isValidElement(<div />)).toEqual(true);
    
  173.   expect(React.isValidElement(<Component />)).toEqual(true);
    
  174. 
    
  175.   expect(React.isValidElement(null)).toEqual(false);
    
  176.   expect(React.isValidElement(true)).toEqual(false);
    
  177.   expect(React.isValidElement({})).toEqual(false);
    
  178.   expect(React.isValidElement('string')).toEqual(false);
    
  179.   expect(React.isValidElement(Component)).toEqual(false);
    
  180.   expect(React.isValidElement({type: 'div', props: {}})).toEqual(false);
    
  181. });
    
  182. 
    
  183. it('is indistinguishable from a plain object', () => {
    
  184.   const element = <div className="foo" />;
    
  185.   const object = {};
    
  186.   expect(element.constructor).toBe(object.constructor);
    
  187. });
    
  188. 
    
  189. it('should use default prop value when removing a prop', () => {
    
  190.   Component.defaultProps = {fruit: 'persimmon'};
    
  191. 
    
  192.   const container = document.createElement('div');
    
  193.   const instance = ReactDOM.render(<Component fruit="mango" />, container);
    
  194.   expect(instance.props.fruit).toBe('mango');
    
  195. 
    
  196.   ReactDOM.render(<Component />, container);
    
  197.   expect(instance.props.fruit).toBe('persimmon');
    
  198. });
    
  199. 
    
  200. it('should normalize props with default values', () => {
    
  201.   class NormalizingComponent extends React.Component {
    
  202.     render() {
    
  203.       return <span>{this.props.prop}</span>;
    
  204.     }
    
  205.   }
    
  206.   NormalizingComponent.defaultProps = {prop: 'testKey'};
    
  207. 
    
  208.   const container = document.createElement('div');
    
  209.   const instance = ReactDOM.render(<NormalizingComponent />, container);
    
  210.   expect(instance.props.prop).toBe('testKey');
    
  211. 
    
  212.   const inst2 = ReactDOM.render(
    
  213.     <NormalizingComponent prop={null} />,
    
  214.     container
    
  215.   );
    
  216.   expect(inst2.props.prop).toBe(null);
    
  217. });
    
  218. 
    
  219. it('warns for keys for arrays of elements in children position', () => {
    
  220.   expect(() =>
    
  221.     ReactTestUtils.renderIntoDocument(
    
  222.       <Component>{[<Component />, <Component />]}</Component>
    
  223.     )
    
  224.   ).toErrorDev('Each child in a list should have a unique "key" prop.');
    
  225. });
    
  226. 
    
  227. it('warns for keys for arrays of elements with owner info', () => {
    
  228.   class InnerComponent extends React.Component {
    
  229.     render() {
    
  230.       return <Component>{this.props.childSet}</Component>;
    
  231.     }
    
  232.   }
    
  233. 
    
  234.   class ComponentWrapper extends React.Component {
    
  235.     render() {
    
  236.       return <InnerComponent childSet={[<Component />, <Component />]} />;
    
  237.     }
    
  238.   }
    
  239. 
    
  240.   expect(() =>
    
  241.     ReactTestUtils.renderIntoDocument(<ComponentWrapper />)
    
  242.   ).toErrorDev(
    
  243.     'Each child in a list should have a unique "key" prop.' +
    
  244.       '\n\nCheck the render method of `InnerComponent`. ' +
    
  245.       'It was passed a child from ComponentWrapper. '
    
  246.   );
    
  247. });
    
  248. 
    
  249. it('does not warn for arrays of elements with keys', () => {
    
  250.   ReactTestUtils.renderIntoDocument(
    
  251.     <Component>{[<Component key="#1" />, <Component key="#2" />]}</Component>
    
  252.   );
    
  253. });
    
  254. 
    
  255. it('does not warn for iterable elements with keys', () => {
    
  256.   const iterable = {
    
  257.     '@@iterator': function () {
    
  258.       let i = 0;
    
  259.       return {
    
  260.         next: function () {
    
  261.           const done = ++i > 2;
    
  262.           return {
    
  263.             value: done ? undefined : <Component key={'#' + i} />,
    
  264.             done: done,
    
  265.           };
    
  266.         },
    
  267.       };
    
  268.     },
    
  269.   };
    
  270. 
    
  271.   ReactTestUtils.renderIntoDocument(<Component>{iterable}</Component>);
    
  272. });
    
  273. 
    
  274. it('does not warn for numeric keys in entry iterable as a child', () => {
    
  275.   const iterable = {
    
  276.     '@@iterator': function () {
    
  277.       let i = 0;
    
  278.       return {
    
  279.         next: function () {
    
  280.           const done = ++i > 2;
    
  281.           return {value: done ? undefined : [i, <Component />], done: done};
    
  282.         },
    
  283.       };
    
  284.     },
    
  285.   };
    
  286.   iterable.entries = iterable['@@iterator'];
    
  287. 
    
  288.   ReactTestUtils.renderIntoDocument(<Component>{iterable}</Component>);
    
  289. });
    
  290. 
    
  291. it('does not warn when the element is directly as children', () => {
    
  292.   ReactTestUtils.renderIntoDocument(
    
  293.     <Component>
    
  294.       <Component />
    
  295.       <Component />
    
  296.     </Component>
    
  297.   );
    
  298. });
    
  299. 
    
  300. it('does not warn when the child array contains non-elements', () => {
    
  301.   void (<Component>{[{}, {}]}</Component>);
    
  302. });
    
  303. 
    
  304. it('should give context for PropType errors in nested components.', () => {
    
  305.   // In this test, we're making sure that if a proptype error is found in a
    
  306.   // component, we give a small hint as to which parent instantiated that
    
  307.   // component as per warnings about key usage in ReactElementValidator.
    
  308.   function MyComp({color}) {
    
  309.     return <div>My color is {color}</div>;
    
  310.   }
    
  311.   MyComp.propTypes = {
    
  312.     color: PropTypes.string,
    
  313.   };
    
  314.   class ParentComp extends React.Component {
    
  315.     render() {
    
  316.       return <MyComp color={123} />;
    
  317.     }
    
  318.   }
    
  319.   expect(() => ReactTestUtils.renderIntoDocument(<ParentComp />)).toErrorDev(
    
  320.     'Warning: Failed prop type: ' +
    
  321.       'Invalid prop `color` of type `number` supplied to `MyComp`, ' +
    
  322.       'expected `string`.\n' +
    
  323.       '    in MyComp (at **)\n' +
    
  324.       '    in ParentComp (at **)'
    
  325.   );
    
  326. });
    
  327. 
    
  328. it('gives a helpful error when passing null, undefined, or boolean', () => {
    
  329.   const Undefined = undefined;
    
  330.   const Null = null;
    
  331.   const True = true;
    
  332.   const Div = 'div';
    
  333.   expect(() => void (<Undefined />)).toErrorDev(
    
  334.     'Warning: React.jsx: type is invalid -- expected a string ' +
    
  335.       '(for built-in components) or a class/function (for composite ' +
    
  336.       'components) but got: undefined. You likely forgot to export your ' +
    
  337.       "component from the file it's defined in, or you might have mixed up " +
    
  338.       'default and named imports.' +
    
  339.       (process.env.BABEL_ENV === 'development'
    
  340.         ? '\n\nCheck your code at **.'
    
  341.         : ''),
    
  342.     {withoutStack: true}
    
  343.   );
    
  344.   expect(() => void (<Null />)).toErrorDev(
    
  345.     'Warning: React.jsx: type is invalid -- expected a string ' +
    
  346.       '(for built-in components) or a class/function (for composite ' +
    
  347.       'components) but got: null.' +
    
  348.       (process.env.BABEL_ENV === 'development'
    
  349.         ? '\n\nCheck your code at **.'
    
  350.         : ''),
    
  351.     {withoutStack: true}
    
  352.   );
    
  353.   expect(() => void (<True />)).toErrorDev(
    
  354.     'Warning: React.jsx: type is invalid -- expected a string ' +
    
  355.       '(for built-in components) or a class/function (for composite ' +
    
  356.       'components) but got: boolean.' +
    
  357.       (process.env.BABEL_ENV === 'development'
    
  358.         ? '\n\nCheck your code at **.'
    
  359.         : ''),
    
  360.     {withoutStack: true}
    
  361.   );
    
  362.   // No error expected
    
  363.   void (<Div />);
    
  364. });
    
  365. 
    
  366. it('should check default prop values', () => {
    
  367.   RequiredPropComponent.defaultProps = {prop: null};
    
  368. 
    
  369.   expect(() =>
    
  370.     ReactTestUtils.renderIntoDocument(<RequiredPropComponent />)
    
  371.   ).toErrorDev(
    
  372.     'Warning: Failed prop type: The prop `prop` is marked as required in ' +
    
  373.       '`RequiredPropComponent`, but its value is `null`.\n' +
    
  374.       '    in RequiredPropComponent (at **)'
    
  375.   );
    
  376. });
    
  377. 
    
  378. it('should warn on invalid prop types', () => {
    
  379.   // Since there is no prevalidation step for ES6 classes, there is no hook
    
  380.   // for us to issue a warning earlier than element creation when the error
    
  381.   // actually occurs. Since this step is skipped in production, we should just
    
  382.   // warn instead of throwing for this case.
    
  383.   class NullPropTypeComponent extends React.Component {
    
  384.     render() {
    
  385.       return <span>{this.props.prop}</span>;
    
  386.     }
    
  387.   }
    
  388.   NullPropTypeComponent.propTypes = {
    
  389.     prop: null,
    
  390.   };
    
  391.   expect(() =>
    
  392.     ReactTestUtils.renderIntoDocument(<NullPropTypeComponent />)
    
  393.   ).toErrorDev(
    
  394.     'NullPropTypeComponent: prop type `prop` is invalid; it must be a ' +
    
  395.       'function, usually from the `prop-types` package,'
    
  396.   );
    
  397. });
    
  398. 
    
  399. it('should warn on invalid context types', () => {
    
  400.   class NullContextTypeComponent extends React.Component {
    
  401.     render() {
    
  402.       return <span>{this.props.prop}</span>;
    
  403.     }
    
  404.   }
    
  405.   NullContextTypeComponent.contextTypes = {
    
  406.     prop: null,
    
  407.   };
    
  408.   expect(() =>
    
  409.     ReactTestUtils.renderIntoDocument(<NullContextTypeComponent />)
    
  410.   ).toErrorDev(
    
  411.     'NullContextTypeComponent: context type `prop` is invalid; it must ' +
    
  412.       'be a function, usually from the `prop-types` package,'
    
  413.   );
    
  414. });
    
  415. 
    
  416. it('should warn if getDefaultProps is specified on the class', () => {
    
  417.   class GetDefaultPropsComponent extends React.Component {
    
  418.     render() {
    
  419.       return <span>{this.props.prop}</span>;
    
  420.     }
    
  421.   }
    
  422.   GetDefaultPropsComponent.getDefaultProps = () => ({
    
  423.     prop: 'foo',
    
  424.   });
    
  425.   expect(() =>
    
  426.     ReactTestUtils.renderIntoDocument(<GetDefaultPropsComponent />)
    
  427.   ).toErrorDev(
    
  428.     'getDefaultProps is only used on classic React.createClass definitions.' +
    
  429.       ' Use a static property named `defaultProps` instead.',
    
  430.     {withoutStack: true}
    
  431.   );
    
  432. });
    
  433. 
    
  434. it('should warn if component declares PropTypes instead of propTypes', () => {
    
  435.   class MisspelledPropTypesComponent extends React.Component {
    
  436.     render() {
    
  437.       return <span>{this.props.prop}</span>;
    
  438.     }
    
  439.   }
    
  440.   MisspelledPropTypesComponent.PropTypes = {
    
  441.     prop: PropTypes.string,
    
  442.   };
    
  443.   expect(() =>
    
  444.     ReactTestUtils.renderIntoDocument(
    
  445.       <MisspelledPropTypesComponent prop="hi" />
    
  446.     )
    
  447.   ).toErrorDev(
    
  448.     'Warning: Component MisspelledPropTypesComponent declared `PropTypes` ' +
    
  449.       'instead of `propTypes`. Did you misspell the property assignment?',
    
  450.     {withoutStack: true}
    
  451.   );
    
  452. });
    
  453. 
    
  454. it('warns for fragments with illegal attributes', () => {
    
  455.   class Foo extends React.Component {
    
  456.     render() {
    
  457.       return <React.Fragment a={1}>hello</React.Fragment>;
    
  458.     }
    
  459.   }
    
  460. 
    
  461.   expect(() => ReactTestUtils.renderIntoDocument(<Foo />)).toErrorDev(
    
  462.     'Invalid prop `a` supplied to `React.Fragment`. React.Fragment ' +
    
  463.       'can only have `key` and `children` props.'
    
  464.   );
    
  465. });
    
  466. 
    
  467. it('warns for fragments with refs', () => {
    
  468.   class Foo extends React.Component {
    
  469.     render() {
    
  470.       return (
    
  471.         <React.Fragment
    
  472.           ref={bar => {
    
  473.             this.foo = bar;
    
  474.           }}>
    
  475.           hello
    
  476.         </React.Fragment>
    
  477.       );
    
  478.     }
    
  479.   }
    
  480. 
    
  481.   expect(() => ReactTestUtils.renderIntoDocument(<Foo />)).toErrorDev(
    
  482.     'Invalid attribute `ref` supplied to `React.Fragment`.'
    
  483.   );
    
  484. });
    
  485. 
    
  486. it('does not warn for fragments of multiple elements without keys', () => {
    
  487.   ReactTestUtils.renderIntoDocument(
    
  488.     <>
    
  489.       <span>1</span>
    
  490.       <span>2</span>
    
  491.     </>
    
  492.   );
    
  493. });
    
  494. 
    
  495. it('warns for fragments of multiple elements with same key', () => {
    
  496.   expect(() =>
    
  497.     ReactTestUtils.renderIntoDocument(
    
  498.       <>
    
  499.         <span key="a">1</span>
    
  500.         <span key="a">2</span>
    
  501.         <span key="b">3</span>
    
  502.       </>
    
  503.     )
    
  504.   ).toErrorDev('Encountered two children with the same key, `a`.', {
    
  505.     withoutStack: true,
    
  506.   });
    
  507. });
    
  508. 
    
  509. it('does not call lazy initializers eagerly', () => {
    
  510.   let didCall = false;
    
  511.   const Lazy = React.lazy(() => {
    
  512.     didCall = true;
    
  513.     return {then() {}};
    
  514.   });
    
  515.   <Lazy />;
    
  516.   expect(didCall).toBe(false);
    
  517. });
    
  518. 
    
  519. it('supports classic refs', () => {
    
  520.   class Foo extends React.Component {
    
  521.     render() {
    
  522.       return <div className="foo" ref="inner" />;
    
  523.     }
    
  524.   }
    
  525.   const container = document.createElement('div');
    
  526.   const instance = ReactDOM.render(<Foo />, container);
    
  527.   expect(instance.refs.inner.className).toBe('foo');
    
  528. });
    
  529. 
    
  530. it('should support refs on owned components', () => {
    
  531.   const innerObj = {};
    
  532.   const outerObj = {};
    
  533. 
    
  534.   class Wrapper extends React.Component {
    
  535.     getObject = () => {
    
  536.       return this.props.object;
    
  537.     };
    
  538. 
    
  539.     render() {
    
  540.       return <div>{this.props.children}</div>;
    
  541.     }
    
  542.   }
    
  543. 
    
  544.   class Component extends React.Component {
    
  545.     render() {
    
  546.       const inner = <Wrapper object={innerObj} ref="inner" />;
    
  547.       const outer = (
    
  548.         <Wrapper object={outerObj} ref="outer">
    
  549.           {inner}
    
  550.         </Wrapper>
    
  551.       );
    
  552.       return outer;
    
  553.     }
    
  554. 
    
  555.     componentDidMount() {
    
  556.       expect(this.refs.inner.getObject()).toEqual(innerObj);
    
  557.       expect(this.refs.outer.getObject()).toEqual(outerObj);
    
  558.     }
    
  559.   }
    
  560. 
    
  561.   ReactTestUtils.renderIntoDocument(<Component />);
    
  562. });
    
  563. 
    
  564. it('should support callback-style refs', () => {
    
  565.   const innerObj = {};
    
  566.   const outerObj = {};
    
  567. 
    
  568.   class Wrapper extends React.Component {
    
  569.     getObject = () => {
    
  570.       return this.props.object;
    
  571.     };
    
  572. 
    
  573.     render() {
    
  574.       return <div>{this.props.children}</div>;
    
  575.     }
    
  576.   }
    
  577. 
    
  578.   let mounted = false;
    
  579. 
    
  580.   class Component extends React.Component {
    
  581.     render() {
    
  582.       const inner = (
    
  583.         <Wrapper object={innerObj} ref={c => (this.innerRef = c)} />
    
  584.       );
    
  585.       const outer = (
    
  586.         <Wrapper object={outerObj} ref={c => (this.outerRef = c)}>
    
  587.           {inner}
    
  588.         </Wrapper>
    
  589.       );
    
  590.       return outer;
    
  591.     }
    
  592. 
    
  593.     componentDidMount() {
    
  594.       expect(this.innerRef.getObject()).toEqual(innerObj);
    
  595.       expect(this.outerRef.getObject()).toEqual(outerObj);
    
  596.       mounted = true;
    
  597.     }
    
  598.   }
    
  599. 
    
  600.   ReactTestUtils.renderIntoDocument(<Component />);
    
  601.   expect(mounted).toBe(true);
    
  602. });
    
  603. 
    
  604. it('should support object-style refs', () => {
    
  605.   const innerObj = {};
    
  606.   const outerObj = {};
    
  607. 
    
  608.   class Wrapper extends React.Component {
    
  609.     getObject = () => {
    
  610.       return this.props.object;
    
  611.     };
    
  612. 
    
  613.     render() {
    
  614.       return <div>{this.props.children}</div>;
    
  615.     }
    
  616.   }
    
  617. 
    
  618.   let mounted = false;
    
  619. 
    
  620.   class Component extends React.Component {
    
  621.     constructor() {
    
  622.       super();
    
  623.       this.innerRef = React.createRef();
    
  624.       this.outerRef = React.createRef();
    
  625.     }
    
  626.     render() {
    
  627.       const inner = <Wrapper object={innerObj} ref={this.innerRef} />;
    
  628.       const outer = (
    
  629.         <Wrapper object={outerObj} ref={this.outerRef}>
    
  630.           {inner}
    
  631.         </Wrapper>
    
  632.       );
    
  633.       return outer;
    
  634.     }
    
  635. 
    
  636.     componentDidMount() {
    
  637.       expect(this.innerRef.current.getObject()).toEqual(innerObj);
    
  638.       expect(this.outerRef.current.getObject()).toEqual(outerObj);
    
  639.       mounted = true;
    
  640.     }
    
  641.   }
    
  642. 
    
  643.   ReactTestUtils.renderIntoDocument(<Component />);
    
  644.   expect(mounted).toBe(true);
    
  645. });
    
  646. 
    
  647. it('should support new-style refs with mixed-up owners', () => {
    
  648.   class Wrapper extends React.Component {
    
  649.     getTitle = () => {
    
  650.       return this.props.title;
    
  651.     };
    
  652. 
    
  653.     render() {
    
  654.       return this.props.getContent();
    
  655.     }
    
  656.   }
    
  657. 
    
  658.   let mounted = false;
    
  659. 
    
  660.   class Component extends React.Component {
    
  661.     getInner = () => {
    
  662.       // (With old-style refs, it's impossible to get a ref to this div
    
  663.       // because Wrapper is the current owner when this function is called.)
    
  664.       return <div className="inner" ref={c => (this.innerRef = c)} />;
    
  665.     };
    
  666. 
    
  667.     render() {
    
  668.       return (
    
  669.         <Wrapper
    
  670.           title="wrapper"
    
  671.           ref={c => (this.wrapperRef = c)}
    
  672.           getContent={this.getInner}
    
  673.         />
    
  674.       );
    
  675.     }
    
  676. 
    
  677.     componentDidMount() {
    
  678.       // Check .props.title to make sure we got the right elements back
    
  679.       expect(this.wrapperRef.getTitle()).toBe('wrapper');
    
  680.       expect(this.innerRef.className).toBe('inner');
    
  681.       mounted = true;
    
  682.     }
    
  683.   }
    
  684. 
    
  685.   ReactTestUtils.renderIntoDocument(<Component />);
    
  686.   expect(mounted).toBe(true);
    
  687. });
    
  688. 
    
  689. it('should warn when `key` is being accessed on composite element', () => {
    
  690.   const container = document.createElement('div');
    
  691.   class Child extends React.Component {
    
  692.     render() {
    
  693.       return <div> {this.props.key} </div>;
    
  694.     }
    
  695.   }
    
  696.   class Parent extends React.Component {
    
  697.     render() {
    
  698.       return (
    
  699.         <div>
    
  700.           <Child key="0" />
    
  701.           <Child key="1" />
    
  702.           <Child key="2" />
    
  703.         </div>
    
  704.       );
    
  705.     }
    
  706.   }
    
  707.   expect(() => ReactDOM.render(<Parent />, container)).toErrorDev(
    
  708.     'Child: `key` is not a prop. Trying to access it will result ' +
    
  709.       'in `undefined` being returned. If you need to access the same ' +
    
  710.       'value within the child component, you should pass it as a different ' +
    
  711.       'prop. (https://reactjs.org/link/special-props)'
    
  712.   );
    
  713. });
    
  714. 
    
  715. it('should warn when `ref` is being accessed', () => {
    
  716.   const container = document.createElement('div');
    
  717.   class Child extends React.Component {
    
  718.     render() {
    
  719.       return <div> {this.props.ref} </div>;
    
  720.     }
    
  721.   }
    
  722.   class Parent extends React.Component {
    
  723.     render() {
    
  724.       return (
    
  725.         <div>
    
  726.           <Child ref="childElement" />
    
  727.         </div>
    
  728.       );
    
  729.     }
    
  730.   }
    
  731.   expect(() => ReactDOM.render(<Parent />, container)).toErrorDev(
    
  732.     'Child: `ref` is not a prop. Trying to access it will result ' +
    
  733.       'in `undefined` being returned. If you need to access the same ' +
    
  734.       'value within the child component, you should pass it as a different ' +
    
  735.       'prop. (https://reactjs.org/link/special-props)'
    
  736.   );
    
  737. });
    
  738. 
    
  739. it('should warn when owner and self are different for string refs', () => {
    
  740.   class ClassWithRenderProp extends React.Component {
    
  741.     render() {
    
  742.       return this.props.children();
    
  743.     }
    
  744.   }
    
  745. 
    
  746.   class ClassParent extends React.Component {
    
  747.     render() {
    
  748.       return (
    
  749.         <ClassWithRenderProp>{() => <div ref="myRef" />}</ClassWithRenderProp>
    
  750.       );
    
  751.     }
    
  752.   }
    
  753. 
    
  754.   const container = document.createElement('div');
    
  755.   if (process.env.BABEL_ENV === 'development') {
    
  756.     expect(() => ReactDOM.render(<ClassParent />, container)).toErrorDev([
    
  757.       'Warning: Component "ClassWithRenderProp" contains the string ref "myRef". ' +
    
  758.         'Support for string refs will be removed in a future major release. ' +
    
  759.         'This case cannot be automatically converted to an arrow function. ' +
    
  760.         'We ask you to manually fix this case by using useRef() or createRef() instead. ' +
    
  761.         'Learn more about using refs safely here: ' +
    
  762.         'https://reactjs.org/link/strict-mode-string-ref',
    
  763.     ]);
    
  764.   } else {
    
  765.     ReactDOM.render(<ClassParent />, container);
    
  766.   }
    
  767. });