Repository: facebook/react
Pull request: Convert createReactClassIntegration-test to createRoot

Convert createReactClassIntegration-test to createRoot


Changed files:
filename: packages/react/src/__tests__/createReactClassIntegration-test.js
patch: @@ -9,18 +9,21 @@
 
 'use strict';
 
+let act;
+
 let PropTypes;
 let React;
-let ReactDOM;
+let ReactDOMClient;
 let ReactTestUtils;
 let createReactClass;
 
 describe('create-react-class-integration', () => {
   beforeEach(() => {
     jest.resetModules();
+    ({act} = require('internal-test-utils'));
     PropTypes = require('prop-types');
     React = require('react');
-    ReactDOM = require('react-dom');
+    ReactDOMClient = require('react-dom/client');
     ReactTestUtils = require('react-dom/test-utils');
     createReactClass = require('create-react-class/factory')(
       React.Component,
@@ -292,7 +295,7 @@ describe('create-react-class-integration', () => {
   });
 
   // @gate !disableLegacyContext
-  it('renders based on context getInitialState', () => {
+  it('renders based on context getInitialState', async () => {
     const Foo = createReactClass({
       contextTypes: {
         className: PropTypes.string,
@@ -318,7 +321,10 @@ describe('create-react-class-integration', () => {
     });
 
     const container = document.createElement('div');
-    ReactDOM.render(<Outer />, container);
+    const root = ReactDOMClient.createRoot(container);
+    await act(() => {
+      root.render(<Outer />);
+    });
     expect(container.firstChild.className).toBe('foo');
   });
 
@@ -388,7 +394,7 @@ describe('create-react-class-integration', () => {
     expect(ops).toEqual(['Render: 0', 'Render: 1', 'Callback: 1']);
   });
 
-  it('getDerivedStateFromProps updates state when props change', () => {
+  it('getDerivedStateFromProps updates state when props change', async () => {
     const Component = createReactClass({
       getInitialState() {
         return {
@@ -404,23 +410,26 @@ describe('create-react-class-integration', () => {
     });
 
     const container = document.createElement('div');
-    const instance = ReactDOM.render(
-      <div>
-        <Component incrementBy={0} />
-      </div>,
-      container,
-    );
-    expect(instance.textContent).toEqual('count:1');
-    ReactDOM.render(
-      <div>
-        <Component incrementBy={2} />
-      </div>,
-      container,
-    );
-    expect(instance.textContent).toEqual('count:3');
+    const root = ReactDOMClient.createRoot(container);
+    await act(() => {
+      root.render(
+        <div>
+          <Component incrementBy={0} />
+        </div>,
+      );
+    });
+    expect(container.firstChild.textContent).toEqual('count:1');
+    await act(() => {
+      root.render(
+        <div>
+          <Component incrementBy={2} />
+        </div>,
+      );
+    });
+    expect(container.firstChild.textContent).toEqual('count:3');
   });
 
-  it('should support the new static getDerivedStateFromProps method', () => {
+  it('should support the new static getDerivedStateFromProps method', async () => {
     let instance;
     const Component = createReactClass({
       statics: {
@@ -438,11 +447,14 @@ describe('create-react-class-integration', () => {
         return null;
       },
     });
-    ReactDOM.render(<Component />, document.createElement('div'));
+    const root = ReactDOMClient.createRoot(document.createElement('div'));
+    await act(() => {
+      root.render(<Component />);
+    });
     expect(instance.state.foo).toBe('bar');
   });
 
-  it('warns if getDerivedStateFromProps is not static', () => {
+  it('warns if getDerivedStateFromProps is not static', async () => {
     const Foo = createReactClass({
       displayName: 'Foo',
       getDerivedStateFromProps() {
@@ -452,15 +464,18 @@ describe('create-react-class-integration', () => {
         return <div />;
       },
     });
-    expect(() =>
-      ReactDOM.render(<Foo foo="foo" />, document.createElement('div')),
-    ).toErrorDev(
+    await expect(async () => {
+      const root = ReactDOMClient.createRoot(document.createElement('div'));
+      await act(() => {
+        root.render(<Foo foo="foo" />);
+      });
+    }).toErrorDev(
       'Foo: getDerivedStateFromProps() is defined as an instance method ' +
         'and will be ignored. Instead, declare it as a static method.',
     );
   });
 
-  it('warns if getDerivedStateFromError is not static', () => {
+  it('warns if getDerivedStateFromError is not static', async () => {
     const Foo = createReactClass({
       displayName: 'Foo',
       getDerivedStateFromError() {
@@ -470,15 +485,18 @@ describe('create-react-class-integration', () => {
         return <div />;
       },
     });
-    expect(() =>
-      ReactDOM.render(<Foo foo="foo" />, document.createElement('div')),
-    ).toErrorDev(
+    await expect(async () => {
+      const root = ReactDOMClient.createRoot(document.createElement('div'));
+      await act(() => {
+        root.render(<Foo foo="foo" />);
+      });
+    }).toErrorDev(
       'Foo: getDerivedStateFromError() is defined as an instance method ' +
         'and will be ignored. Instead, declare it as a static method.',
     );
   });
 
-  it('warns if getSnapshotBeforeUpdate is static', () => {
+  it('warns if getSnapshotBeforeUpdate is static', async () => {
     const Foo = createReactClass({
       displayName: 'Foo',
       statics: {
@@ -490,15 +508,18 @@ describe('create-react-class-integration', () => {
         return <div />;
       },
     });
-    expect(() =>
-      ReactDOM.render(<Foo foo="foo" />, document.createElement('div')),
-    ).toErrorDev(
+    await expect(async () => {
+      const root = ReactDOMClient.createRoot(document.createElement('div'));
+      await act(() => {
+        root.render(<Foo foo="foo" />);
+      });
+    }).toErrorDev(
       'Foo: getSnapshotBeforeUpdate() is defined as a static method ' +
         'and will be ignored. Instead, declare it as an instance method.',
     );
   });
 
-  it('should warn if state is not properly initialized before getDerivedStateFromProps', () => {
+  it('should warn if state is not properly initialized before getDerivedStateFromProps', async () => {
     const Component = createReactClass({
       displayName: 'Component',
       statics: {
@@ -510,17 +531,20 @@ describe('create-react-class-integration', () => {
         return null;
       },
     });
-    expect(() =>
-      ReactDOM.render(<Component />, document.createElement('div')),
-    ).toErrorDev(
+    await expect(async () => {
+      const root = ReactDOMClient.createRoot(document.createElement('div'));
+      await act(() => {
+        root.render(<Component />);
+      });
+    }).toErrorDev(
       '`Component` uses `getDerivedStateFromProps` but its initial state is ' +
         'null. This is not recommended. Instead, define the initial state by ' +
         'assigning an object to `this.state` in the constructor of `Component`. ' +
         'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.',
     );
   });
 
-  it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new static gDSFP is present', () => {
+  it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new static gDSFP is present', async () => {
     const Component = createReactClass({
       statics: {
         getDerivedStateFromProps: function () {
@@ -544,9 +568,12 @@ describe('create-react-class-integration', () => {
       },
     });
 
-    expect(() => {
-      expect(() => {
-        ReactDOM.render(<Component />, document.createElement('div'));
+    await expect(async () => {
+      await expect(async () => {
+        const root = ReactDOMClient.createRoot(document.createElement('div'));
+        await act(() => {
+          root.render(<Component />);
+        });
       }).toErrorDev(
         'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
           'Component uses getDerivedStateFromProps() but also contains the following legacy lifecycles:\n' +
@@ -564,10 +591,13 @@ describe('create-react-class-integration', () => {
       ],
       {withoutStack: true},
     );
-    ReactDOM.render(<Component foo={1} />, document.createElement('div'));
+    const root = ReactDOMClient.createRoot(document.createElement('div'));
+    await act(() => {
+      root.render(<Component foo={1} />);
+    });
   });
 
-  it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new getSnapshotBeforeUpdate is present', () => {
+  it('should not invoke deprecated lifecycles (cWM/cWRP/cWU) if new getSnapshotBeforeUpdate is present', async () => {
     const Component = createReactClass({
       getSnapshotBeforeUpdate: function () {
         return null;
@@ -587,9 +617,12 @@ describe('create-react-class-integration', () => {
       },
     });
 
-    expect(() => {
-      expect(() => {
-        ReactDOM.render(<Component />, document.createElement('div'));
+    await expect(async () => {
+      await expect(async () => {
+        const root = ReactDOMClient.createRoot(document.createElement('div'));
+        await act(() => {
+          root.render(<Component />);
+        });
       }).toErrorDev(
         'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
           'Component uses getSnapshotBeforeUpdate() but also contains the following legacy lifecycles:\n' +
@@ -607,10 +640,13 @@ describe('create-react-class-integration', () => {
       ],
       {withoutStack: true},
     );
-    ReactDOM.render(<Component foo={1} />, document.createElement('div'));
+    await act(() => {
+      const root2 = ReactDOMClient.createRoot(document.createElement('div'));
+      root2.render(<Component foo={1} />);
+    });
   });
 
-  it('should invoke both deprecated and new lifecycles if both are present', () => {
+  it('should invoke both deprecated and new lifecycles if both are present', async () => {
     const log = [];
 
     const Component = createReactClass({
@@ -641,8 +677,13 @@ describe('create-react-class-integration', () => {
       },
     });
 
-    const div = document.createElement('div');
-    expect(() => ReactDOM.render(<Component foo="bar" />, div)).toWarnDev(
+    const root = ReactDOMClient.createRoot(document.createElement('div'));
+
+    await expect(async () => {
+      await act(() => {
+        root.render(<Component foo="bar" />);
+      });
+    }).toWarnDev(
       [
         'componentWillMount has been renamed',
         'componentWillReceiveProps has been renamed',
@@ -654,7 +695,9 @@ describe('create-react-class-integration', () => {
 
     log.length = 0;
 
-    ReactDOM.render(<Component foo="baz" />, div);
+    await act(() => {
+      root.render(<Component foo="baz" />);
+    });
     expect(log).toEqual([
       'componentWillReceiveProps',
       'UNSAFE_componentWillReceiveProps',
@@ -663,7 +706,7 @@ describe('create-react-class-integration', () => {
     ]);
   });
 
-  it('isMounted works', () => {
+  it('isMounted works', async () => {
     const ops = [];
     let instance;
     const Component = createReactClass({
@@ -716,19 +759,28 @@ describe('create-react-class-integration', () => {
       },
     });
 
-    const container = document.createElement('div');
+    const root = ReactDOMClient.createRoot(document.createElement('div'));
 
-    expect(() => ReactDOM.render(<Component />, container)).toErrorDev(
+    await expect(async () => {
+      await act(() => {
+        root.render(<Component />);
+      });
+    }).toErrorDev(
       'Warning: MyComponent: isMounted is deprecated. Instead, make sure to ' +
         'clean up subscriptions and pending requests in componentWillUnmount ' +
         'to prevent memory leaks.',
       {withoutStack: true},
     );
 
     // Dedupe
-    ReactDOM.render(<Component />, container);
 
-    ReactDOM.unmountComponentAtNode(container);
+    await act(() => {
+      root.render(<Component />);
+    });
+
+    await act(() => {
+      root.unmount();
+    });
     instance.log('after unmount');
     expect(ops).toEqual([
       'getInitialState: false',