Repository: facebook/react
Pull request: Convert ReactIdentity-test.js to createRoot


Changed files:
filename: packages/react-dom/src/__tests__/ReactIdentity-test.js
patch: @@ -10,18 +10,20 @@
 'use strict';
 
 let React;
-let ReactDOM;
+let ReactDOMClient;
 let ReactTestUtils;
+let act;
 
 describe('ReactIdentity', () => {
   beforeEach(() => {
     jest.resetModules();
     React = require('react');
-    ReactDOM = require('react-dom');
+    ReactDOMClient = require('react-dom/client');
     ReactTestUtils = require('react-dom/test-utils');
+    act = require('internal-test-utils').act;
   });
 
-  it('should allow key property to express identity', () => {
+  it('should allow key property to express identity', async () => {
     let node;
     const Component = props => (
       <div ref={c => (node = c)}>
@@ -31,41 +33,48 @@ describe('ReactIdentity', () => {
     );
 
     const container = document.createElement('div');
-    ReactDOM.render(<Component />, container);
+    const root = ReactDOMClient.createRoot(container);
+    await act(async () => {
+      root.render(<Component />);
+    });
     const origChildren = Array.from(node.childNodes);
-    ReactDOM.render(<Component swap={true} />, container);
+    await act(async () => {
+      root.render(<Component swap={true} />);
+    });
     const newChildren = Array.from(node.childNodes);
     expect(origChildren[0]).toBe(newChildren[1]);
     expect(origChildren[1]).toBe(newChildren[0]);
   });
 
-  it('should use composite identity', () => {
+  it('should use composite identity', async () => {
     class Wrapper extends React.Component {
       render() {
         return <a>{this.props.children}</a>;
       }
     }
 
     const container = document.createElement('div');
+    const root = ReactDOMClient.createRoot(container);
     let node1;
     let node2;
-    ReactDOM.render(
-      <Wrapper key="wrap1">
-        <span ref={c => (node1 = c)} />
-      </Wrapper>,
-      container,
-    );
-    ReactDOM.render(
-      <Wrapper key="wrap2">
-        <span ref={c => (node2 = c)} />
-      </Wrapper>,
-      container,
-    );
-
+    await act(async () => {
+      root.render(
+        <Wrapper key="wrap1">
+          <span ref={c => (node1 = c)} />
+        </Wrapper>,
+      );
+    });
+    await act(async () => {
+      root.render(
+        <Wrapper key="wrap2">
+          <span ref={c => (node2 = c)} />
+        </Wrapper>,
+      );
+    });
     expect(node1).not.toBe(node2);
   });
 
-  function renderAComponentWithKeyIntoContainer(key, container) {
+  async function renderAComponentWithKeyIntoContainer(key, root) {
     class Wrapper extends React.Component {
       spanRef = React.createRef();
       render() {
@@ -76,36 +85,41 @@ describe('ReactIdentity', () => {
         );
       }
     }
-
-    const instance = ReactDOM.render(<Wrapper />, container);
-    const span = instance.spanRef.current;
+    const wrapperRef = React.createRef();
+    await act(async () => {
+      root.render(<Wrapper ref={wrapperRef} />);
+    });
+    const span = wrapperRef.current.spanRef.current;
     expect(span).not.toBe(null);
   }
 
-  it('should allow any character as a key, in a detached parent', () => {
+  it('should allow any character as a key, in a detached parent', async () => {
     const detachedContainer = document.createElement('div');
-    renderAComponentWithKeyIntoContainer("<'WEIRD/&\\key'>", detachedContainer);
+    const root = ReactDOMClient.createRoot(detachedContainer);
+    await renderAComponentWithKeyIntoContainer("<'WEIRD/&\\key'>", root);
   });
 
-  it('should allow any character as a key, in an attached parent', () => {
+  it('should allow any character as a key, in an attached parent', async () => {
     // This test exists to protect against implementation details that
     // incorrectly query escaped IDs using DOM tools like getElementById.
     const attachedContainer = document.createElement('div');
+    const root = ReactDOMClient.createRoot(attachedContainer);
     document.body.appendChild(attachedContainer);
 
-    renderAComponentWithKeyIntoContainer("<'WEIRD/&\\key'>", attachedContainer);
+    await renderAComponentWithKeyIntoContainer("<'WEIRD/&\\key'>", root);
 
     document.body.removeChild(attachedContainer);
   });
 
-  it('should not allow scripts in keys to execute', () => {
+  it('should not allow scripts in keys to execute', async () => {
     const h4x0rKey =
       '"><script>window[\'YOUVEBEENH4X0RED\']=true;</script><div id="';
 
     const attachedContainer = document.createElement('div');
+    const root = ReactDOMClient.createRoot(attachedContainer);
     document.body.appendChild(attachedContainer);
 
-    renderAComponentWithKeyIntoContainer(h4x0rKey, attachedContainer);
+    await renderAComponentWithKeyIntoContainer(h4x0rKey, root);
 
     document.body.removeChild(attachedContainer);
 
@@ -209,7 +223,7 @@ describe('ReactIdentity', () => {
     }).not.toThrow();
   });
 
-  it('should retain key during updates in composite components', () => {
+  it('should retain key during updates in composite components', async () => {
     class TestComponent extends React.Component {
       render() {
         return <div>{this.props.children}</div>;
@@ -236,16 +250,23 @@ describe('ReactIdentity', () => {
     const instance0 = <span key="A" />;
     const instance1 = <span key="B" />;
 
-    let wrapped = <TestContainer first={instance0} second={instance1} />;
-
-    wrapped = ReactDOM.render(wrapped, document.createElement('div'));
-    const div = ReactDOM.findDOMNode(wrapped);
+    const container = document.createElement('div');
+    const root = ReactDOMClient.createRoot(container);
+    const wrappedRef = React.createRef();
+    await act(async () => {
+      root.render(
+        <TestContainer first={instance0} second={instance1} ref={wrappedRef} />,
+      );
+    });
+    const div = container.firstChild;
 
-    const beforeA = div.childNodes[0];
-    const beforeB = div.childNodes[1];
-    wrapped.swap();
-    const afterA = div.childNodes[1];
-    const afterB = div.childNodes[0];
+    const beforeA = div.firstChild;
+    const beforeB = div.lastChild;
+    await act(async () => {
+      wrappedRef.current.swap();
+    });
+    const afterA = div.lastChild;
+    const afterB = div.firstChild;
 
     expect(beforeA).toBe(afterA);
     expect(beforeB).toBe(afterB);
@@ -264,7 +285,7 @@ describe('ReactIdentity', () => {
     }).not.toThrow();
   });
 
-  it('should throw if key is a Temporal-like object', () => {
+  it('should throw if key is a Temporal-like object', async () => {
     class TemporalLike {
       valueOf() {
         // Throwing here is the behavior of ECMAScript "Temporal" date/time API.
@@ -277,15 +298,15 @@ describe('ReactIdentity', () => {
     }
 
     const el = document.createElement('div');
-    const test = () =>
-      ReactDOM.render(
-        <div>
-          <span key={new TemporalLike()} />
-        </div>,
-        el,
-      );
-    expect(() =>
-      expect(test).toThrowError(new TypeError('prod message')),
+    const root = ReactDOMClient.createRoot(el);
+    await expect(() =>
+      expect(() => {
+        root.render(
+          <div>
+            <span key={new TemporalLike()} />
+          </div>,
+        );
+      }).toThrowError(new TypeError('prod message')),
     ).toErrorDev(
       'The provided key is an unsupported type TemporalLike.' +
         ' This value must be coerced to a string before using it here.',