| 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 | 'use strict'; |
| 11 | |
| 12 | const React = require('react'); |
| 13 | const ReactDOM = require('react-dom'); |
| 14 | const StrictMode = React.StrictMode; |
| 15 | const assertConsoleErrorDev = |
| 16 | require('internal-test-utils').assertConsoleErrorDev; |
| 17 | |
| 18 | describe('findDOMNode', () => { |
| 19 | // @gate www && classic |
| 20 | it('findDOMNode should return null if passed null', () => { |
| 21 | expect(ReactDOM.findDOMNode(null)).toBe(null); |
| 22 | }); |
| 23 | |
| 24 | // @gate www && classic && !disableLegacyMode |
| 25 | it('findDOMNode should find dom element', () => { |
| 26 | class MyNode extends React.Component { |
| 27 | render() { |
| 28 | return ( |
| 29 | <div> |
| 30 | <span>Noise</span> |
| 31 | </div> |
| 32 | ); |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | const container = document.createElement('div'); |
| 37 | const myNode = ReactDOM.render(<MyNode />, container); |
| 38 | const myDiv = ReactDOM.findDOMNode(myNode); |
| 39 | const mySameDiv = ReactDOM.findDOMNode(myDiv); |
| 40 | expect(myDiv.tagName).toBe('DIV'); |
| 41 | expect(mySameDiv).toBe(myDiv); |
| 42 | }); |
| 43 | |
| 44 | // @gate www && classic && !disableLegacyMode |
| 45 | it('findDOMNode should find dom element after an update from null', () => { |
| 46 | function Bar({flag}) { |
| 47 | if (flag) { |
| 48 | return <span>A</span>; |
| 49 | } |
| 50 | return null; |
| 51 | } |
| 52 | class MyNode extends React.Component { |
| 53 | render() { |
| 54 | return <Bar flag={this.props.flag} />; |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | const container = document.createElement('div'); |
| 59 | |
| 60 | const myNodeA = ReactDOM.render(<MyNode />, container); |
| 61 | const a = ReactDOM.findDOMNode(myNodeA); |
| 62 | expect(a).toBe(null); |
| 63 | |
| 64 | const myNodeB = ReactDOM.render(<MyNode flag={true} />, container); |
| 65 | expect(myNodeA === myNodeB).toBe(true); |
| 66 | |
| 67 | const b = ReactDOM.findDOMNode(myNodeB); |
| 68 | expect(b.tagName).toBe('SPAN'); |
| 69 | }); |
| 70 | |
| 71 | // @gate www && classic |
| 72 | it('findDOMNode should reject random objects', () => { |
| 73 | expect(function () { |
| 74 | ReactDOM.findDOMNode({foo: 'bar'}); |
| 75 | }).toThrow('Argument appears to not be a ReactComponent. Keys: foo'); |
| 76 | }); |
| 77 | |
| 78 | // @gate www && classic && !disableLegacyMode |
| 79 | it('findDOMNode should reject unmounted objects with render func', () => { |
| 80 | class Foo extends React.Component { |
| 81 | render() { |
| 82 | return <div />; |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | const container = document.createElement('div'); |
| 87 | const inst = ReactDOM.render(<Foo />, container); |
| 88 | ReactDOM.unmountComponentAtNode(container); |
| 89 | |
| 90 | expect(() => ReactDOM.findDOMNode(inst)).toThrow( |
| 91 | 'Unable to find node on an unmounted component.', |
| 92 | ); |
| 93 | }); |
| 94 | |
| 95 | // @gate www && classic && !disableLegacyMode |
| 96 | it('findDOMNode should not throw an error when called within a component that is not mounted', () => { |
| 97 | class Bar extends React.Component { |
| 98 | UNSAFE_componentWillMount() { |
| 99 | expect(ReactDOM.findDOMNode(this)).toBeNull(); |
| 100 | } |
| 101 | |
| 102 | render() { |
| 103 | return <div />; |
| 104 | } |
| 105 | } |
| 106 | expect(() => { |
| 107 | const container = document.createElement('div'); |
| 108 | ReactDOM.render(<Bar />, container); |
| 109 | }).not.toThrow(); |
| 110 | }); |
| 111 | |
| 112 | // @gate www && classic && !disableLegacyMode |
| 113 | it('findDOMNode should warn if used to find a host component inside StrictMode', () => { |
| 114 | let parent = undefined; |
| 115 | let child = undefined; |
| 116 | |
| 117 | class ContainsStrictModeChild extends React.Component { |
| 118 | render() { |
| 119 | return ( |
| 120 | <StrictMode> |
| 121 | <div ref={n => (child = n)} /> |
| 122 | </StrictMode> |
| 123 | ); |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | const container = document.createElement('div'); |
| 128 | ReactDOM.render( |
| 129 | <ContainsStrictModeChild ref={n => (parent = n)} />, |
| 130 | container, |
| 131 | ); |
| 132 | |
| 133 | const match = ReactDOM.findDOMNode(parent); |
| 134 | assertConsoleErrorDev([ |
| 135 | 'findDOMNode is deprecated in StrictMode. ' + |
| 136 | 'findDOMNode was passed an instance of ContainsStrictModeChild which renders StrictMode children. ' + |
| 137 | 'Instead, add a ref directly to the element you want to reference. ' + |
| 138 | 'Learn more about using refs safely here: ' + |
| 139 | 'https://react.dev/link/strict-mode-find-node' + |
| 140 | '\n in div (at **)' + |
| 141 | '\n in ContainsStrictModeChild (at **)', |
| 142 | ]); |
| 143 | expect(match).toBe(child); |
| 144 | }); |
| 145 | |
| 146 | // @gate www && classic && !disableLegacyMode |
| 147 | it('findDOMNode should warn if passed a component that is inside StrictMode', () => { |
| 148 | let parent = undefined; |
| 149 | let child = undefined; |
| 150 | |
| 151 | class IsInStrictMode extends React.Component { |
| 152 | render() { |
| 153 | return <div ref={n => (child = n)} />; |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | const container = document.createElement('div'); |
| 158 | |
| 159 | ReactDOM.render( |
| 160 | <StrictMode> |
| 161 | <IsInStrictMode ref={n => (parent = n)} /> |
| 162 | </StrictMode>, |
| 163 | container, |
| 164 | ); |
| 165 | |
| 166 | const match = ReactDOM.findDOMNode(parent); |
| 167 | assertConsoleErrorDev([ |
| 168 | 'findDOMNode is deprecated in StrictMode. ' + |
| 169 | 'findDOMNode was passed an instance of IsInStrictMode which is inside StrictMode. ' + |
| 170 | 'Instead, add a ref directly to the element you want to reference. ' + |
| 171 | 'Learn more about using refs safely here: ' + |
| 172 | 'https://react.dev/link/strict-mode-find-node' + |
| 173 | '\n in div (at **)' + |
| 174 | '\n in IsInStrictMode (at **)', |
| 175 | ]); |
| 176 | expect(match).toBe(child); |
| 177 | }); |
| 178 | }); |