diff --git a/packages/react-dom/src/__tests__/refs-destruction-test.js b/packages/react-dom/src/__tests__/refs-destruction-test.js index d8a3e750b8fd2..97009c9e77806 100644 --- a/packages/react-dom/src/__tests__/refs-destruction-test.js +++ b/packages/react-dom/src/__tests__/refs-destruction-test.js @@ -11,9 +11,12 @@ let React; let ReactDOM; +let ReactDOMClient; let ReactTestUtils; - let TestComponent; +let act; +let theInnerDivRef; +let theInnerClassComponentRef; describe('refs-destruction', () => { beforeEach(() => { @@ -21,7 +24,9 @@ describe('refs-destruction', () => { React = require('react'); ReactDOM = require('react-dom'); + ReactDOMClient = require('react-dom/client'); ReactTestUtils = require('react-dom/test-utils'); + act = require('internal-test-utils').act; class ClassComponent extends React.Component { render() { @@ -30,8 +35,11 @@ describe('refs-destruction', () => { } TestComponent = class extends React.Component { - theInnerDivRef = React.createRef(); - theInnerClassComponentRef = React.createRef(); + constructor(props) { + super(props); + theInnerDivRef = React.createRef(); + theInnerClassComponentRef = React.createRef(); + } render() { if (this.props.destroy) { @@ -46,8 +54,8 @@ describe('refs-destruction', () => { } else { return (
-
- +
+
); } @@ -55,60 +63,79 @@ describe('refs-destruction', () => { }; }); - it('should remove refs when destroying the parent', () => { + afterEach(() => { + theInnerClassComponentRef = null; + theInnerDivRef = null; + }); + + it('should remove refs when destroying the parent', async () => { const container = document.createElement('div'); - const testInstance = ReactDOM.render(, container); + const root = ReactDOMClient.createRoot(container); + await act(async () => { + root.render(); + }); - expect( - ReactTestUtils.isDOMComponent(testInstance.theInnerDivRef.current), - ).toBe(true); - expect(testInstance.theInnerClassComponentRef.current).toBeTruthy(); + expect(ReactTestUtils.isDOMComponent(theInnerDivRef.current)).toBe(true); + expect(theInnerClassComponentRef.current).toBeTruthy(); - ReactDOM.unmountComponentAtNode(container); + root.unmount(); - expect(testInstance.theInnerDivRef.current).toBe(null); - expect(testInstance.theInnerClassComponentRef.current).toBe(null); + expect(theInnerDivRef.current).toBe(null); + expect(theInnerClassComponentRef.current).toBe(null); }); - it('should remove refs when destroying the child', () => { + it('should remove refs when destroying the child', async () => { const container = document.createElement('div'); - const testInstance = ReactDOM.render(, container); - expect( - ReactTestUtils.isDOMComponent(testInstance.theInnerDivRef.current), - ).toBe(true); - expect(testInstance.theInnerClassComponentRef.current).toBeTruthy(); + const root = ReactDOMClient.createRoot(container); + await act(async () => { + root.render(); + }); + + expect(ReactTestUtils.isDOMComponent(theInnerDivRef.current)).toBe(true); + expect(theInnerClassComponentRef.current).toBeTruthy(); - ReactDOM.render(, container); + await act(async () => { + root.render(); + }); - expect(testInstance.theInnerDivRef.current).toBe(null); - expect(testInstance.theInnerClassComponentRef.current).toBe(null); + expect(theInnerDivRef.current).toBe(null); + expect(theInnerClassComponentRef.current).toBe(null); }); - it('should remove refs when removing the child ref attribute', () => { + it('should remove refs when removing the child ref attribute', async () => { const container = document.createElement('div'); - const testInstance = ReactDOM.render(, container); + const root = ReactDOMClient.createRoot(container); + await act(async () => { + root.render(); + }); - expect( - ReactTestUtils.isDOMComponent(testInstance.theInnerDivRef.current), - ).toBe(true); - expect(testInstance.theInnerClassComponentRef.current).toBeTruthy(); + expect(ReactTestUtils.isDOMComponent(theInnerDivRef.current)).toBe(true); + expect(theInnerClassComponentRef.current).toBeTruthy(); - ReactDOM.render(, container); + await act(async () => { + root.render(); + }); - expect(testInstance.theInnerDivRef.current).toBe(null); - expect(testInstance.theInnerClassComponentRef.current).toBe(null); + expect(theInnerDivRef.current).toBe(null); + expect(theInnerClassComponentRef.current).toBe(null); }); - it('should not error when destroying child with ref asynchronously', () => { + it('should not error when destroying child with ref asynchronously', async () => { + let nestedRoot; class Modal extends React.Component { componentDidMount() { this.div = document.createElement('div'); + nestedRoot = ReactDOMClient.createRoot(this.div); document.body.appendChild(this.div); this.componentDidUpdate(); } componentDidUpdate() { - ReactDOM.render(
{this.props.children}
, this.div); + setTimeout(() => { + ReactDOM.flushSync(() => { + nestedRoot.render(
{this.props.children}
); + }); + }, 0); } componentWillUnmount() { @@ -116,7 +143,7 @@ describe('refs-destruction', () => { // some async animation setTimeout(function () { expect(function () { - ReactDOM.unmountComponentAtNode(self.div); + nestedRoot.unmount(); }).not.toThrow(); document.body.removeChild(self.div); }, 0); @@ -144,8 +171,12 @@ describe('refs-destruction', () => { } const container = document.createElement('div'); - ReactDOM.render(, container); - ReactDOM.render(