Repository: facebook/react
Pull request: Use createRoot in ReactDOMComponentTree-test


Changed files:
filename: packages/react-dom/src/__tests__/ReactDOMComponentTree-test.js
patch: @@ -11,12 +11,15 @@
 
 describe('ReactDOMComponentTree', () => {
   let React;
-  let ReactDOM;
+  let ReactDOMClient;
+  let act;
   let container;
 
   beforeEach(() => {
     React = require('react');
-    ReactDOM = require('react-dom');
+    ReactDOMClient = require('react-dom/client');
+    act = require('internal-test-utils').act;
+
     container = document.createElement('div');
     document.body.appendChild(container);
   });
@@ -26,25 +29,24 @@ describe('ReactDOMComponentTree', () => {
     container = null;
   });
 
-  it('finds nodes for instances on events', () => {
+  it('finds nodes for instances on events', async () => {
     const mouseOverID = 'mouseOverID';
     const clickID = 'clickID';
     let currentTargetID = null;
     // the current target of an event is set to result of getNodeFromInstance
     // when an event is dispatched so we can test behavior by invoking
     // events on elements in the tree and confirming the expected node is
     // set as the current target
-    class Component extends React.Component {
-      handler = e => {
+    function Component() {
+      const handler = e => {
         currentTargetID = e.currentTarget.id;
       };
-      render() {
-        return (
-          <div id={mouseOverID} onMouseOver={this.handler}>
-            <div id={clickID} onClick={this.handler} />
-          </div>
-        );
-      }
+
+      return (
+        <div id={mouseOverID} onMouseOver={handler}>
+          <div id={clickID} onClick={handler} />
+        </div>
+      );
     }
 
     function simulateMouseEvent(elem, type) {
@@ -54,34 +56,35 @@ describe('ReactDOMComponentTree', () => {
       elem.dispatchEvent(event);
     }
 
-    const component = <Component />;
-    ReactDOM.render(component, container);
+    const root = ReactDOMClient.createRoot(container);
+    await act(() => {
+      root.render(<Component />);
+    });
     expect(currentTargetID).toBe(null);
     simulateMouseEvent(document.getElementById(mouseOverID), 'mouseover');
     expect(currentTargetID).toBe(mouseOverID);
     simulateMouseEvent(document.getElementById(clickID), 'click');
     expect(currentTargetID).toBe(clickID);
   });
 
-  it('finds closest instance for node when an event happens', () => {
+  it('finds closest instance for node when an event happens', async () => {
     const nonReactElemID = 'aID';
     const innerHTML = {__html: `<div id="${nonReactElemID}"></div>`};
     const closestInstanceID = 'closestInstance';
     let currentTargetID = null;
 
-    class ClosestInstance extends React.Component {
-      _onClick = e => {
+    function ClosestInstance() {
+      const onClick = e => {
         currentTargetID = e.currentTarget.id;
       };
-      render() {
-        return (
-          <div
-            id={closestInstanceID}
-            onClick={this._onClick}
-            dangerouslySetInnerHTML={innerHTML}
-          />
-        );
-      }
+
+      return (
+        <div
+          id={closestInstanceID}
+          onClick={onClick}
+          dangerouslySetInnerHTML={innerHTML}
+        />
+      );
     }
 
     function simulateClick(elem) {
@@ -91,16 +94,22 @@ describe('ReactDOMComponentTree', () => {
       elem.dispatchEvent(event);
     }
 
-    const component = <ClosestInstance />;
-    ReactDOM.render(<section>{component}</section>, container);
+    const root = ReactDOMClient.createRoot(container);
+    await act(() => {
+      root.render(
+        <section>
+          <ClosestInstance />
+        </section>,
+      );
+    });
     expect(currentTargetID).toBe(null);
     simulateClick(document.getElementById(nonReactElemID));
     expect(currentTargetID).toBe(closestInstanceID);
   });
 
-  it('updates event handlers from fiber props', () => {
+  it('updates event handlers from fiber props', async () => {
     let action = '';
-    let instance;
+    let flip;
     const handlerA = () => (action = 'A');
     const handlerB = () => (action = 'B');
 
@@ -111,55 +120,56 @@ describe('ReactDOMComponentTree', () => {
       target.dispatchEvent(event);
     }
 
-    class HandlerFlipper extends React.Component {
-      state = {flip: false};
-      flip() {
-        this.setState({flip: true});
-      }
-      render() {
-        return (
-          <div
-            id="update"
-            onMouseOver={this.state.flip ? handlerB : handlerA}
-          />
-        );
-      }
+    function HandlerFlipper() {
+      const [flipVal, setFlipVal] = React.useState(false);
+      flip = () => setFlipVal(true);
+
+      return <div id="update" onMouseOver={flipVal ? handlerB : handlerA} />;
     }
 
-    ReactDOM.render(
-      <HandlerFlipper key="1" ref={n => (instance = n)} />,
-      container,
-    );
+    const root = ReactDOMClient.createRoot(container);
+    await act(() => {
+      root.render(<HandlerFlipper key="1" />);
+    });
     const node = container.firstChild;
-    simulateMouseOver(node);
+
+    await act(() => {
+      simulateMouseOver(node);
+    });
     expect(action).toEqual('A');
     action = '';
+
     // Render with the other event handler.
-    instance.flip();
-    simulateMouseOver(node);
+    await act(() => {
+      flip();
+    });
+    await act(() => {
+      simulateMouseOver(node);
+    });
     expect(action).toEqual('B');
   });
 
-  it('finds a controlled instance from node and gets its current fiber props', () => {
+  it('finds a controlled instance from node and gets its current fiber props', async () => {
+    let inputRef;
     const inputID = 'inputID';
     const startValue = undefined;
     const finishValue = 'finish';
 
-    class Controlled extends React.Component {
-      state = {value: startValue};
-      a = null;
-      _onChange = e => this.setState({value: e.currentTarget.value});
-      render() {
-        return (
-          <input
-            id={inputID}
-            type="text"
-            ref={n => (this.a = n)}
-            value={this.state.value}
-            onChange={this._onChange}
-          />
-        );
-      }
+    function Controlled() {
+      const [state, setState] = React.useState(startValue);
+      const ref = React.useRef();
+      inputRef = ref;
+      const onChange = e => setState(e.currentTarget.value);
+
+      return (
+        <input
+          id={inputID}
+          type="text"
+          ref={ref}
+          value={state}
+          onChange={onChange}
+        />
+      );
     }
 
     const setUntrackedInputValue = Object.getOwnPropertyDescriptor(
@@ -175,9 +185,17 @@ describe('ReactDOMComponentTree', () => {
       elem.dispatchEvent(inputEvent);
     }
 
-    const component = <Controlled />;
-    const instance = ReactDOM.render(component, container);
-    expect(() => simulateInput(instance.a, finishValue)).toErrorDev(
+    const root = ReactDOMClient.createRoot(container);
+    await act(() => {
+      root.render(<Controlled />);
+    });
+
+    await expect(
+      async () =>
+        await act(() => {
+          simulateInput(inputRef.current, finishValue);
+        }),
+    ).toErrorDev(
       'Warning: A component is changing an uncontrolled input to be controlled. ' +
         'This is likely caused by the value changing from undefined to ' +
         'a defined value, which should not happen. ' +
@@ -186,33 +204,4 @@ describe('ReactDOMComponentTree', () => {
         'https://reactjs.org/link/controlled-components',
     );
   });
-
-  it('finds instance of node that is attempted to be unmounted', () => {
-    const component = <div />;
-    const node = ReactDOM.render(<div>{component}</div>, container);
-    expect(() => ReactDOM.unmountComponentAtNode(node)).toErrorDev(
-      "unmountComponentAtNode(): The node you're attempting to unmount " +
-        'was rendered by React and is not a top-level container. You may ' +
-        'have accidentally passed in a React root node instead of its ' +
-        'container.',
-      {withoutStack: true},
-    );
-  });
-
-  it('finds instance from node to stop rendering over other react rendered components', () => {
-    const component = (
-      <div>
-        <span>Hello</span>
-      </div>
-    );
-    const anotherComponent = <div />;
-    const instance = ReactDOM.render(component, container);
-    expect(() => ReactDOM.render(anotherComponent, instance)).toErrorDev(
-      'render(...): Replacing React-rendered children with a new root ' +
-        'component. If you intended to update the children of this node, ' +
-        'you should instead have the existing children update their state ' +
-        'and render the new components instead of calling ReactDOM.render.',
-      {withoutStack: true},
-    );
-  });
 });

filename: packages/react-dom/src/__tests__/ReactDOMLegacyComponentTree-test.internal.js
patch: @@ -0,0 +1,58 @@
+/**
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @emails react-core
+ */
+
+'use strict';
+
+describe('ReactDOMComponentTree', () => {
+  let React;
+  let ReactDOM;
+  let container;
+
+  beforeEach(() => {
+    React = require('react');
+    ReactDOM = require('react-dom');
+
+    container = document.createElement('div');
+    document.body.appendChild(container);
+  });
+
+  afterEach(() => {
+    document.body.removeChild(container);
+    container = null;
+  });
+
+  it('finds instance of node that is attempted to be unmounted', () => {
+    const component = <div />;
+    const node = ReactDOM.render(<div>{component}</div>, container);
+    expect(() => ReactDOM.unmountComponentAtNode(node)).toErrorDev(
+      "unmountComponentAtNode(): The node you're attempting to unmount " +
+        'was rendered by React and is not a top-level container. You may ' +
+        'have accidentally passed in a React root node instead of its ' +
+        'container.',
+      {withoutStack: true},
+    );
+  });
+
+  it('finds instance from node to stop rendering over other react rendered components', () => {
+    const component = (
+      <div>
+        <span>Hello</span>
+      </div>
+    );
+    const anotherComponent = <div />;
+    const instance = ReactDOM.render(component, container);
+    expect(() => ReactDOM.render(anotherComponent, instance)).toErrorDev(
+      'render(...): Replacing React-rendered children with a new root ' +
+        'component. If you intended to update the children of this node, ' +
+        'you should instead have the existing children update their state ' +
+        'and render the new components instead of calling ReactDOM.render.',
+      {withoutStack: true},
+    );
+  });
+});