@@ -274,8 +274,56 @@ describe('ReactElementClone', () => {
274274
275275 const root = ReactDOMClient . createRoot ( document . createElement ( 'div' ) ) ;
276276 await act ( ( ) => root . render ( < Grandparent /> ) ) ;
277- expect ( component . childRef ) . toEqual ( { current : null } ) ;
278- expect ( component . parentRef . current . xyzRef . current . tagName ) . toBe ( 'SPAN' ) ;
277+ if ( gate ( flags => flags . enableRefAsProp && flags . disableStringRefs ) ) {
278+ expect ( component . childRef ) . toEqual ( { current : null } ) ;
279+ expect ( component . parentRef . current . xyzRef . current . tagName ) . toBe ( 'SPAN' ) ;
280+ } else if (
281+ gate ( flags => ! flags . enableRefAsProp && ! flags . disableStringRefs )
282+ ) {
283+ expect ( component . childRef ) . toEqual ( { current : null } ) ;
284+ expect ( component . parentRef . current . xyzRef . current . tagName ) . toBe ( 'SPAN' ) ;
285+ } else if (
286+ gate ( flags => flags . enableRefAsProp && ! flags . disableStringRefs )
287+ ) {
288+ expect ( component . childRef ) . toEqual ( { current : null } ) ;
289+ expect ( component . parentRef . current . xyzRef . current . tagName ) . toBe ( 'SPAN' ) ;
290+ } else {
291+ // Not going to bother testing every possible combination.
292+ }
293+ } ) ;
294+
295+ // @gate !disableStringRefs
296+ it ( 'should steal the ref if a new string ref is specified without an owner' , async ( ) => {
297+ // Regression test for this specific feature combination calling cloneElement on an element
298+ // without an owner
299+ await expect ( async ( ) => {
300+ // create an element without an owner
301+ const element = React . createElement ( 'div' , { id : 'some-id' } ) ;
302+ class Parent extends React . Component {
303+ render ( ) {
304+ return < Child > { element } </ Child > ;
305+ }
306+ }
307+ let child ;
308+ class Child extends React . Component {
309+ render ( ) {
310+ child = this ;
311+ const clone = React . cloneElement ( this . props . children , {
312+ ref : 'xyz' ,
313+ } ) ;
314+ return < div > { clone } </ div > ;
315+ }
316+ }
317+
318+ const root = ReactDOMClient . createRoot ( document . createElement ( 'div' ) ) ;
319+ await act ( ( ) => root . render ( < Parent /> ) ) ;
320+ expect ( child . refs . xyz . tagName ) . toBe ( 'DIV' ) ;
321+ } ) . toErrorDev ( [
322+ 'Warning: Component "Child" contains the string ref "xyz". Support for ' +
323+ 'string refs will be removed in a future major release. We recommend ' +
324+ 'using useRef() or createRef() instead. Learn more about using refs ' +
325+ 'safely here: https://react.dev/link/strict-mode-string-ref' ,
326+ ] ) ;
279327 } ) ;
280328
281329 it ( 'should overwrite props' , async ( ) => {
@@ -371,6 +419,15 @@ describe('ReactElementClone', () => {
371419 ) {
372420 expect ( clone . ref ) . toBe ( element . ref ) ;
373421 expect ( clone . props ) . toEqual ( { foo : 'ef' } ) ;
422+ } else if (
423+ gate ( flags => flags . enableRefAsProp && ! flags . disableStringRefs )
424+ ) {
425+ expect ( ( ) => {
426+ expect ( clone . ref ) . toBe ( element . ref ) ;
427+ } ) . toErrorDev ( 'Accessing element.ref was removed in React 19' , {
428+ withoutStack : true ,
429+ } ) ;
430+ expect ( clone . props ) . toEqual ( { foo : 'ef' , ref : element . ref } ) ;
374431 } else {
375432 // Not going to bother testing every possible combination.
376433 }
0 commit comments