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.  * @flow
    
  8.  */
    
  9. 
    
  10. describe('profiling HostRoot', () => {
    
  11.   let React;
    
  12.   let ReactDOMClient;
    
  13.   let Scheduler;
    
  14.   let legacyRender;
    
  15.   let store;
    
  16.   let utils;
    
  17.   let getEffectDurations;
    
  18.   let effectDurations;
    
  19.   let passiveEffectDurations;
    
  20. 
    
  21.   beforeEach(() => {
    
  22.     utils = require('./utils');
    
  23.     utils.beforeEachProfiling();
    
  24. 
    
  25.     legacyRender = utils.legacyRender;
    
  26. 
    
  27.     getEffectDurations = require('../backend/utils').getEffectDurations;
    
  28. 
    
  29.     store = global.store;
    
  30. 
    
  31.     React = require('react');
    
  32.     ReactDOMClient = require('react-dom/client');
    
  33.     Scheduler = require('scheduler');
    
  34. 
    
  35.     effectDurations = [];
    
  36.     passiveEffectDurations = [];
    
  37. 
    
  38.     // This is the DevTools hook installed by the env.beforEach()
    
  39.     // The hook is installed as a read-only property on the window,
    
  40.     // so for our test purposes we can just override the commit hook.
    
  41.     const hook = global.__REACT_DEVTOOLS_GLOBAL_HOOK__;
    
  42.     hook.onPostCommitFiberRoot = function onPostCommitFiberRoot(
    
  43.       rendererID,
    
  44.       root,
    
  45.     ) {
    
  46.       const {effectDuration, passiveEffectDuration} = getEffectDurations(root);
    
  47.       effectDurations.push(effectDuration);
    
  48.       passiveEffectDurations.push(passiveEffectDuration);
    
  49.     };
    
  50.   });
    
  51. 
    
  52.   // @reactVersion >=18.0
    
  53.   it('should expose passive and layout effect durations for render()', () => {
    
  54.     function App() {
    
  55.       React.useEffect(() => {
    
  56.         Scheduler.unstable_advanceTime(10);
    
  57.       });
    
  58.       React.useLayoutEffect(() => {
    
  59.         Scheduler.unstable_advanceTime(100);
    
  60.       });
    
  61.       return null;
    
  62.     }
    
  63. 
    
  64.     utils.act(() => store.profilerStore.startProfiling());
    
  65.     utils.act(() => {
    
  66.       const container = document.createElement('div');
    
  67.       legacyRender(<App />, container);
    
  68.     });
    
  69.     utils.act(() => store.profilerStore.stopProfiling());
    
  70. 
    
  71.     expect(effectDurations).toHaveLength(1);
    
  72.     const effectDuration = effectDurations[0];
    
  73.     expect(effectDuration === null || effectDuration === 100).toBe(true);
    
  74.     expect(passiveEffectDurations).toHaveLength(1);
    
  75.     const passiveEffectDuration = passiveEffectDurations[0];
    
  76.     expect(passiveEffectDuration === null || passiveEffectDuration === 10).toBe(
    
  77.       true,
    
  78.     );
    
  79.   });
    
  80. 
    
  81.   // @reactVersion >=18.0
    
  82.   it('should expose passive and layout effect durations for createRoot()', () => {
    
  83.     function App() {
    
  84.       React.useEffect(() => {
    
  85.         Scheduler.unstable_advanceTime(10);
    
  86.       });
    
  87.       React.useLayoutEffect(() => {
    
  88.         Scheduler.unstable_advanceTime(100);
    
  89.       });
    
  90.       return null;
    
  91.     }
    
  92. 
    
  93.     utils.act(() => store.profilerStore.startProfiling());
    
  94.     utils.act(() => {
    
  95.       const container = document.createElement('div');
    
  96.       const root = ReactDOMClient.createRoot(container);
    
  97.       root.render(<App />);
    
  98.     });
    
  99.     utils.act(() => store.profilerStore.stopProfiling());
    
  100. 
    
  101.     expect(effectDurations).toHaveLength(1);
    
  102.     const effectDuration = effectDurations[0];
    
  103.     expect(effectDuration === null || effectDuration === 100).toBe(true);
    
  104.     expect(passiveEffectDurations).toHaveLength(1);
    
  105.     const passiveEffectDuration = passiveEffectDurations[0];
    
  106.     expect(passiveEffectDuration === null || passiveEffectDuration === 10).toBe(
    
  107.       true,
    
  108.     );
    
  109.   });
    
  110. 
    
  111.   // @reactVersion >=18.0
    
  112.   it('should properly reset passive and layout effect durations between commits', () => {
    
  113.     function App({shouldCascade}) {
    
  114.       const [, setState] = React.useState(false);
    
  115.       React.useEffect(() => {
    
  116.         Scheduler.unstable_advanceTime(10);
    
  117.       });
    
  118.       React.useLayoutEffect(() => {
    
  119.         Scheduler.unstable_advanceTime(100);
    
  120.       });
    
  121.       React.useLayoutEffect(() => {
    
  122.         if (shouldCascade) {
    
  123.           setState(true);
    
  124.         }
    
  125.       }, [shouldCascade]);
    
  126.       return null;
    
  127.     }
    
  128. 
    
  129.     const container = document.createElement('div');
    
  130.     const root = ReactDOMClient.createRoot(container);
    
  131. 
    
  132.     utils.act(() => store.profilerStore.startProfiling());
    
  133.     utils.act(() => root.render(<App />));
    
  134.     utils.act(() => root.render(<App shouldCascade={true} />));
    
  135.     utils.act(() => store.profilerStore.stopProfiling());
    
  136. 
    
  137.     expect(effectDurations).toHaveLength(3);
    
  138.     expect(passiveEffectDurations).toHaveLength(3);
    
  139. 
    
  140.     for (let i = 0; i < effectDurations.length; i++) {
    
  141.       const effectDuration = effectDurations[i];
    
  142.       expect(effectDuration === null || effectDuration === 100).toBe(true);
    
  143.       const passiveEffectDuration = passiveEffectDurations[i];
    
  144.       expect(
    
  145.         passiveEffectDuration === null || passiveEffectDuration === 10,
    
  146.       ).toBe(true);
    
  147.     }
    
  148.   });
    
  149. });