@@ -523,4 +523,110 @@ describe('ReactPerformanceTracks', () => {
523523 ] ,
524524 ] ) ;
525525 } ) ;
526+
527+ // @gate __DEV__ && enableComponentPerformanceTrack
528+ it ( 'diffs HTML-like objects' , async ( ) => {
529+ const App = function App ( { container} ) {
530+ Scheduler . unstable_advanceTime ( 10 ) ;
531+ React . useEffect ( ( ) => { } , [ container ] ) ;
532+ } ;
533+
534+ class Window { }
535+ const createOpaqueOriginWindow = ( ) => {
536+ return new Proxy ( new Window ( ) , {
537+ get ( target , prop ) {
538+ if ( prop === Symbol . toStringTag ) {
539+ return target [ Symbol . toStringTag ] ;
540+ }
541+ // Some properties are allowed if JS itself is accessign those e.g.
542+ // Symbol.toStringTag.
543+ // Just make sure React isn't accessing arbitrary properties.
544+ throw new Error (
545+ `Failed to read named property '${ String ( prop ) } ' from Window` ,
546+ ) ;
547+ } ,
548+ } ) ;
549+ } ;
550+
551+ class OpaqueOriginHTMLIFrameElement {
552+ constructor ( textContent ) {
553+ this . textContent = textContent ;
554+ }
555+ contentWindow = createOpaqueOriginWindow ( ) ;
556+ nodeType = 1 ;
557+ [ Symbol . toStringTag ] = 'HTMLIFrameElement' ;
558+ }
559+
560+ Scheduler . unstable_advanceTime ( 1 ) ;
561+ await act ( ( ) => {
562+ ReactNoop . render (
563+ < App
564+ container = { new OpaqueOriginHTMLIFrameElement ( 'foo' ) }
565+ contentWindow = { createOpaqueOriginWindow ( ) }
566+ /> ,
567+ ) ;
568+ } ) ;
569+
570+ expect ( performanceMeasureCalls ) . toEqual ( [
571+ [
572+ 'Mount' ,
573+ {
574+ detail : {
575+ devtools : {
576+ color : 'warning' ,
577+ properties : null ,
578+ tooltipText : 'Mount' ,
579+ track : 'Components ⚛' ,
580+ } ,
581+ } ,
582+ end : 11 ,
583+ start : 1 ,
584+ } ,
585+ ] ,
586+ ] ) ;
587+ performanceMeasureCalls . length = 0 ;
588+
589+ Scheduler . unstable_advanceTime ( 10 ) ;
590+
591+ await act ( ( ) => {
592+ ReactNoop . render (
593+ < App
594+ container = { new OpaqueOriginHTMLIFrameElement ( 'bar' ) }
595+ contentWindow = { createOpaqueOriginWindow ( ) }
596+ /> ,
597+ ) ;
598+ } ) ;
599+
600+ expect ( performanceMeasureCalls ) . toEqual ( [
601+ [
602+ 'App' ,
603+ {
604+ detail : {
605+ devtools : {
606+ color : 'primary-dark' ,
607+ properties : [
608+ [ 'Changed Props' , '' ] ,
609+ [ '- container' , 'HTMLIFrameElement' ] ,
610+ [ '- contentWindow' , 'Window' ] ,
611+ [ '- nodeType' , '1' ] ,
612+ [ '- textContent' , '"foo"' ] ,
613+ [ '+ container' , 'HTMLIFrameElement' ] ,
614+ [ '+ contentWindow' , 'Window' ] ,
615+ [ '+ nodeType' , '1' ] ,
616+ [ '+ textContent' , '"bar"' ] ,
617+ [
618+ ' contentWindow' ,
619+ 'Referentially unequal but deeply equal objects. Consider memoization.' ,
620+ ] ,
621+ ] ,
622+ tooltipText : 'App' ,
623+ track : 'Components ⚛' ,
624+ } ,
625+ } ,
626+ end : 31 ,
627+ start : 21 ,
628+ } ,
629+ ] ,
630+ ] ) ;
631+ } ) ;
526632} ) ;
0 commit comments