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. 'use strict';
    
  11. 
    
  12. import {normalizeCodeLocInfo} from './utils';
    
  13. 
    
  14. describe('Timeline profiler', () => {
    
  15.   let React;
    
  16.   let ReactDOM;
    
  17.   let ReactDOMClient;
    
  18.   let Scheduler;
    
  19.   let utils;
    
  20.   let assertLog;
    
  21.   let waitFor;
    
  22. 
    
  23.   describe('User Timing API', () => {
    
  24.     let clearedMarks;
    
  25.     let featureDetectionMarkName = null;
    
  26.     let marks;
    
  27.     let setPerformanceMock;
    
  28. 
    
  29.     function createUserTimingPolyfill() {
    
  30.       featureDetectionMarkName = null;
    
  31. 
    
  32.       clearedMarks = [];
    
  33.       marks = [];
    
  34. 
    
  35.       // Remove file-system specific bits or version-specific bits of information from the module range marks.
    
  36.       function filterMarkData(markName) {
    
  37.         if (markName.startsWith('--react-internal-module-start')) {
    
  38.           return '--react-internal-module-start-  at filtered (<anonymous>:0:0)';
    
  39.         } else if (markName.startsWith('--react-internal-module-stop')) {
    
  40.           return '--react-internal-module-stop-  at filtered (<anonymous>:1:1)';
    
  41.         } else if (markName.startsWith('--react-version')) {
    
  42.           return '--react-version-<filtered-version>';
    
  43.         } else {
    
  44.           return markName;
    
  45.         }
    
  46.       }
    
  47. 
    
  48.       // This is not a true polyfill, but it gives us enough to capture marks.
    
  49.       // Reference: https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API
    
  50.       return {
    
  51.         clearMarks(markName) {
    
  52.           markName = filterMarkData(markName);
    
  53. 
    
  54.           clearedMarks.push(markName);
    
  55.           marks = marks.filter(mark => mark !== markName);
    
  56.         },
    
  57.         mark(markName, markOptions) {
    
  58.           markName = filterMarkData(markName);
    
  59. 
    
  60.           if (featureDetectionMarkName === null) {
    
  61.             featureDetectionMarkName = markName;
    
  62.           }
    
  63. 
    
  64.           marks.push(markName);
    
  65. 
    
  66.           if (markOptions != null) {
    
  67.             // This is triggers the feature detection.
    
  68.             markOptions.startTime++;
    
  69.           }
    
  70.         },
    
  71.       };
    
  72.     }
    
  73. 
    
  74.     function clearPendingMarks() {
    
  75.       clearedMarks.splice(0);
    
  76.     }
    
  77. 
    
  78.     beforeEach(() => {
    
  79.       utils = require('./utils');
    
  80.       utils.beforeEachProfiling();
    
  81. 
    
  82.       React = require('react');
    
  83.       ReactDOM = require('react-dom');
    
  84.       ReactDOMClient = require('react-dom/client');
    
  85.       Scheduler = require('scheduler');
    
  86. 
    
  87.       const InternalTestUtils = require('internal-test-utils');
    
  88.       assertLog = InternalTestUtils.assertLog;
    
  89.       waitFor = InternalTestUtils.waitFor;
    
  90. 
    
  91.       setPerformanceMock =
    
  92.         require('react-devtools-shared/src/backend/profilingHooks').setPerformanceMock_ONLY_FOR_TESTING;
    
  93.       setPerformanceMock(createUserTimingPolyfill());
    
  94. 
    
  95.       const store = global.store;
    
  96. 
    
  97.       // Start profiling so that data will actually be recorded.
    
  98.       utils.act(() => store.profilerStore.startProfiling());
    
  99. 
    
  100.       global.IS_REACT_ACT_ENVIRONMENT = true;
    
  101.     });
    
  102. 
    
  103.     afterEach(() => {
    
  104.       // Verify all logged marks also get cleared.
    
  105.       expect(marks).toHaveLength(0);
    
  106. 
    
  107.       setPerformanceMock(null);
    
  108.     });
    
  109. 
    
  110.     describe('getLanesFromTransportDecimalBitmask', () => {
    
  111.       let getLanesFromTransportDecimalBitmask;
    
  112. 
    
  113.       beforeEach(() => {
    
  114.         getLanesFromTransportDecimalBitmask =
    
  115.           require('react-devtools-timeline/src/import-worker/preprocessData').getLanesFromTransportDecimalBitmask;
    
  116.       });
    
  117. 
    
  118.       // @reactVersion >= 18.0
    
  119.       it('should return array of lane numbers from bitmask string', () => {
    
  120.         expect(getLanesFromTransportDecimalBitmask('1')).toEqual([0]);
    
  121.         expect(getLanesFromTransportDecimalBitmask('512')).toEqual([9]);
    
  122.         expect(getLanesFromTransportDecimalBitmask('3')).toEqual([0, 1]);
    
  123.         expect(getLanesFromTransportDecimalBitmask('1234')).toEqual([
    
  124.           1, 4, 6, 7, 10,
    
  125.         ]); // 2 + 16 + 64 + 128 + 1024
    
  126.         expect(
    
  127.           getLanesFromTransportDecimalBitmask('1073741824'), // 0b1000000000000000000000000000000
    
  128.         ).toEqual([30]);
    
  129.         expect(
    
  130.           getLanesFromTransportDecimalBitmask('2147483647'), // 0b1111111111111111111111111111111
    
  131.         ).toEqual(Array.from(Array(31).keys()));
    
  132.       });
    
  133. 
    
  134.       // @reactVersion >= 18.0
    
  135.       it('should return empty array if laneBitmaskString is not a bitmask', () => {
    
  136.         expect(getLanesFromTransportDecimalBitmask('')).toEqual([]);
    
  137.         expect(getLanesFromTransportDecimalBitmask('hello')).toEqual([]);
    
  138.         expect(getLanesFromTransportDecimalBitmask('-1')).toEqual([]);
    
  139.         expect(getLanesFromTransportDecimalBitmask('-0')).toEqual([]);
    
  140.       });
    
  141. 
    
  142.       // @reactVersion >= 18.0
    
  143.       it('should ignore lanes outside REACT_TOTAL_NUM_LANES', () => {
    
  144.         const REACT_TOTAL_NUM_LANES =
    
  145.           require('react-devtools-timeline/src/constants').REACT_TOTAL_NUM_LANES;
    
  146. 
    
  147.         // Sanity check; this test may need to be updated when the no. of fiber lanes are changed.
    
  148.         expect(REACT_TOTAL_NUM_LANES).toBe(31);
    
  149. 
    
  150.         expect(
    
  151.           getLanesFromTransportDecimalBitmask(
    
  152.             '4294967297', // 2^32 + 1
    
  153.           ),
    
  154.         ).toEqual([0]);
    
  155.       });
    
  156.     });
    
  157. 
    
  158.     describe('preprocessData', () => {
    
  159.       let preprocessData;
    
  160. 
    
  161.       beforeEach(() => {
    
  162.         preprocessData =
    
  163.           require('react-devtools-timeline/src/import-worker/preprocessData').default;
    
  164.       });
    
  165. 
    
  166.       // These should be dynamic to mimic a real profile,
    
  167.       // but reprooducible between test runs.
    
  168.       let pid = 0;
    
  169.       let tid = 0;
    
  170.       let startTime = 0;
    
  171. 
    
  172.       function createUserTimingEntry(data) {
    
  173.         return {
    
  174.           pid: ++pid,
    
  175.           tid: ++tid,
    
  176.           ts: ++startTime,
    
  177.           ...data,
    
  178.         };
    
  179.       }
    
  180. 
    
  181.       function createProfilerVersionEntry() {
    
  182.         const SCHEDULING_PROFILER_VERSION =
    
  183.           require('react-devtools-timeline/src/constants').SCHEDULING_PROFILER_VERSION;
    
  184.         return createUserTimingEntry({
    
  185.           cat: 'blink.user_timing',
    
  186.           name: '--profiler-version-' + SCHEDULING_PROFILER_VERSION,
    
  187.         });
    
  188.       }
    
  189. 
    
  190.       function createReactVersionEntry() {
    
  191.         return createUserTimingEntry({
    
  192.           cat: 'blink.user_timing',
    
  193.           name: '--react-version-<filtered-version>',
    
  194.         });
    
  195.       }
    
  196. 
    
  197.       function createLaneLabelsEntry() {
    
  198.         return createUserTimingEntry({
    
  199.           cat: 'blink.user_timing',
    
  200.           name: '--react-lane-labels-Sync,InputContinuousHydration,InputContinuous,DefaultHydration,Default,TransitionHydration,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Retry,Retry,Retry,Retry,Retry,SelectiveHydration,IdleHydration,Idle,Offscreen',
    
  201.         });
    
  202.       }
    
  203. 
    
  204.       function createNativeEventEntry(type, duration) {
    
  205.         return createUserTimingEntry({
    
  206.           cat: 'devtools.timeline',
    
  207.           name: 'EventDispatch',
    
  208.           args: {data: {type}},
    
  209.           dur: duration,
    
  210.           tdur: duration,
    
  211.         });
    
  212.       }
    
  213. 
    
  214.       function creactCpuProfilerSample() {
    
  215.         return createUserTimingEntry({
    
  216.           args: {data: {startTime: ++startTime}},
    
  217.           cat: 'disabled-by-default-v8.cpu_profiler',
    
  218.           id: '0x1',
    
  219.           name: 'Profile',
    
  220.           ph: 'P',
    
  221.         });
    
  222.       }
    
  223. 
    
  224.       function createBoilerplateEntries() {
    
  225.         return [
    
  226.           createProfilerVersionEntry(),
    
  227.           createReactVersionEntry(),
    
  228.           createLaneLabelsEntry(),
    
  229.         ];
    
  230.       }
    
  231. 
    
  232.       function createUserTimingData(sampleMarks) {
    
  233.         const cpuProfilerSample = creactCpuProfilerSample();
    
  234. 
    
  235.         const randomSample = createUserTimingEntry({
    
  236.           dur: 100,
    
  237.           tdur: 200,
    
  238.           ph: 'X',
    
  239.           cat: 'disabled-by-default-devtools.timeline',
    
  240.           name: 'RunTask',
    
  241.           args: {},
    
  242.         });
    
  243. 
    
  244.         const userTimingData = [cpuProfilerSample, randomSample];
    
  245. 
    
  246.         sampleMarks.forEach(markName => {
    
  247.           userTimingData.push({
    
  248.             pid: ++pid,
    
  249.             tid: ++tid,
    
  250.             ts: ++startTime,
    
  251.             args: {data: {}},
    
  252.             cat: 'blink.user_timing',
    
  253.             name: markName,
    
  254.             ph: 'R',
    
  255.           });
    
  256.         });
    
  257. 
    
  258.         return userTimingData;
    
  259.       }
    
  260. 
    
  261.       beforeEach(() => {
    
  262.         tid = 0;
    
  263.         pid = 0;
    
  264.         startTime = 0;
    
  265.       });
    
  266. 
    
  267.       // @reactVersion >= 18.0
    
  268.       it('should throw given an empty timeline', async () => {
    
  269.         await expect(async () => preprocessData([])).rejects.toThrow();
    
  270.       });
    
  271. 
    
  272.       // @reactVersion >= 18.0
    
  273.       it('should throw given a timeline with no Profile event', async () => {
    
  274.         const randomSample = createUserTimingEntry({
    
  275.           dur: 100,
    
  276.           tdur: 200,
    
  277.           ph: 'X',
    
  278.           cat: 'disabled-by-default-devtools.timeline',
    
  279.           name: 'RunTask',
    
  280.           args: {},
    
  281.         });
    
  282. 
    
  283.         await expect(async () =>
    
  284.           preprocessData([randomSample]),
    
  285.         ).rejects.toThrow();
    
  286.       });
    
  287. 
    
  288.       // @reactVersion >= 18.0
    
  289.       it('should throw given a timeline without an explicit profiler version mark nor any other React marks', async () => {
    
  290.         const cpuProfilerSample = creactCpuProfilerSample();
    
  291. 
    
  292.         await expect(
    
  293.           async () => await preprocessData([cpuProfilerSample]),
    
  294.         ).rejects.toThrow(
    
  295.           'Please provide profiling data from an React application',
    
  296.         );
    
  297.       });
    
  298. 
    
  299.       // @reactVersion >= 18.0
    
  300.       it('should throw given a timeline with React scheduling marks, but without an explicit profiler version mark', async () => {
    
  301.         const cpuProfilerSample = creactCpuProfilerSample();
    
  302.         const scheduleRenderSample = createUserTimingEntry({
    
  303.           cat: 'blink.user_timing',
    
  304.           name: '--schedule-render-512-',
    
  305.         });
    
  306.         const samples = [cpuProfilerSample, scheduleRenderSample];
    
  307. 
    
  308.         await expect(async () => await preprocessData(samples)).rejects.toThrow(
    
  309.           'This version of profiling data is not supported',
    
  310.         );
    
  311.       });
    
  312. 
    
  313.       // @reactVersion >= 18.0
    
  314.       it('should return empty data given a timeline with no React scheduling profiling marks', async () => {
    
  315.         const cpuProfilerSample = creactCpuProfilerSample();
    
  316.         const randomSample = createUserTimingEntry({
    
  317.           dur: 100,
    
  318.           tdur: 200,
    
  319.           ph: 'X',
    
  320.           cat: 'disabled-by-default-devtools.timeline',
    
  321.           name: 'RunTask',
    
  322.           args: {},
    
  323.         });
    
  324. 
    
  325.         const data = await preprocessData([
    
  326.           ...createBoilerplateEntries(),
    
  327.           cpuProfilerSample,
    
  328.           randomSample,
    
  329.         ]);
    
  330.         expect(data).toMatchInlineSnapshot(`
    
  331.                 {
    
  332.                   "batchUIDToMeasuresMap": Map {},
    
  333.                   "componentMeasures": [],
    
  334.                   "duration": 0.005,
    
  335.                   "flamechart": [],
    
  336.                   "internalModuleSourceToRanges": Map {},
    
  337.                   "laneToLabelMap": Map {
    
  338.                     0 => "Sync",
    
  339.                     1 => "InputContinuousHydration",
    
  340.                     2 => "InputContinuous",
    
  341.                     3 => "DefaultHydration",
    
  342.                     4 => "Default",
    
  343.                     5 => "TransitionHydration",
    
  344.                     6 => "Transition",
    
  345.                     7 => "Transition",
    
  346.                     8 => "Transition",
    
  347.                     9 => "Transition",
    
  348.                     10 => "Transition",
    
  349.                     11 => "Transition",
    
  350.                     12 => "Transition",
    
  351.                     13 => "Transition",
    
  352.                     14 => "Transition",
    
  353.                     15 => "Transition",
    
  354.                     16 => "Transition",
    
  355.                     17 => "Transition",
    
  356.                     18 => "Transition",
    
  357.                     19 => "Transition",
    
  358.                     20 => "Transition",
    
  359.                     21 => "Transition",
    
  360.                     22 => "Retry",
    
  361.                     23 => "Retry",
    
  362.                     24 => "Retry",
    
  363.                     25 => "Retry",
    
  364.                     26 => "Retry",
    
  365.                     27 => "SelectiveHydration",
    
  366.                     28 => "IdleHydration",
    
  367.                     29 => "Idle",
    
  368.                     30 => "Offscreen",
    
  369.                   },
    
  370.                   "laneToReactMeasureMap": Map {
    
  371.                     0 => [],
    
  372.                     1 => [],
    
  373.                     2 => [],
    
  374.                     3 => [],
    
  375.                     4 => [],
    
  376.                     5 => [],
    
  377.                     6 => [],
    
  378.                     7 => [],
    
  379.                     8 => [],
    
  380.                     9 => [],
    
  381.                     10 => [],
    
  382.                     11 => [],
    
  383.                     12 => [],
    
  384.                     13 => [],
    
  385.                     14 => [],
    
  386.                     15 => [],
    
  387.                     16 => [],
    
  388.                     17 => [],
    
  389.                     18 => [],
    
  390.                     19 => [],
    
  391.                     20 => [],
    
  392.                     21 => [],
    
  393.                     22 => [],
    
  394.                     23 => [],
    
  395.                     24 => [],
    
  396.                     25 => [],
    
  397.                     26 => [],
    
  398.                     27 => [],
    
  399.                     28 => [],
    
  400.                     29 => [],
    
  401.                     30 => [],
    
  402.                   },
    
  403.                   "nativeEvents": [],
    
  404.                   "networkMeasures": [],
    
  405.                   "otherUserTimingMarks": [],
    
  406.                   "reactVersion": "<filtered-version>",
    
  407.                   "schedulingEvents": [],
    
  408.                   "snapshotHeight": 0,
    
  409.                   "snapshots": [],
    
  410.                   "startTime": 1,
    
  411.                   "suspenseEvents": [],
    
  412.                   "thrownErrors": [],
    
  413.                 }
    
  414.           `);
    
  415.       });
    
  416. 
    
  417.       // @reactVersion >= 18.0
    
  418.       it('should process legacy data format (before lane labels were added)', async () => {
    
  419.         const cpuProfilerSample = creactCpuProfilerSample();
    
  420. 
    
  421.         // Data below is hard-coded based on an older profile sample.
    
  422.         // Should be fine since this is explicitly a legacy-format test.
    
  423.         const data = await preprocessData([
    
  424.           ...createBoilerplateEntries(),
    
  425.           cpuProfilerSample,
    
  426.           createUserTimingEntry({
    
  427.             cat: 'blink.user_timing',
    
  428.             name: '--schedule-render-512-',
    
  429.           }),
    
  430.           createUserTimingEntry({
    
  431.             cat: 'blink.user_timing',
    
  432.             name: '--render-start-512',
    
  433.           }),
    
  434.           createUserTimingEntry({
    
  435.             cat: 'blink.user_timing',
    
  436.             name: '--render-stop',
    
  437.           }),
    
  438.           createUserTimingEntry({
    
  439.             cat: 'blink.user_timing',
    
  440.             name: '--commit-start-512',
    
  441.           }),
    
  442.           createUserTimingEntry({
    
  443.             cat: 'blink.user_timing',
    
  444.             name: '--layout-effects-start-512',
    
  445.           }),
    
  446.           createUserTimingEntry({
    
  447.             cat: 'blink.user_timing',
    
  448.             name: '--layout-effects-stop',
    
  449.           }),
    
  450.           createUserTimingEntry({
    
  451.             cat: 'blink.user_timing',
    
  452.             name: '--commit-stop',
    
  453.           }),
    
  454.         ]);
    
  455.         expect(data).toMatchInlineSnapshot(`
    
  456.           {
    
  457.             "batchUIDToMeasuresMap": Map {
    
  458.               0 => [
    
  459.                 {
    
  460.                   "batchUID": 0,
    
  461.                   "depth": 0,
    
  462.                   "duration": 0.005,
    
  463.                   "lanes": "0b0000000000000000000000000001001",
    
  464.                   "timestamp": 0.006,
    
  465.                   "type": "render-idle",
    
  466.                 },
    
  467.                 {
    
  468.                   "batchUID": 0,
    
  469.                   "depth": 0,
    
  470.                   "duration": 0.001,
    
  471.                   "lanes": "0b0000000000000000000000000001001",
    
  472.                   "timestamp": 0.006,
    
  473.                   "type": "render",
    
  474.                 },
    
  475.                 {
    
  476.                   "batchUID": 0,
    
  477.                   "depth": 0,
    
  478.                   "duration": 0.003,
    
  479.                   "lanes": "0b0000000000000000000000000001001",
    
  480.                   "timestamp": 0.008,
    
  481.                   "type": "commit",
    
  482.                 },
    
  483.                 {
    
  484.                   "batchUID": 0,
    
  485.                   "depth": 1,
    
  486.                   "duration": 0.001,
    
  487.                   "lanes": "0b0000000000000000000000000001001",
    
  488.                   "timestamp": 0.009,
    
  489.                   "type": "layout-effects",
    
  490.                 },
    
  491.               ],
    
  492.             },
    
  493.             "componentMeasures": [],
    
  494.             "duration": 0.011,
    
  495.             "flamechart": [],
    
  496.             "internalModuleSourceToRanges": Map {},
    
  497.             "laneToLabelMap": Map {
    
  498.               0 => "Sync",
    
  499.               1 => "InputContinuousHydration",
    
  500.               2 => "InputContinuous",
    
  501.               3 => "DefaultHydration",
    
  502.               4 => "Default",
    
  503.               5 => "TransitionHydration",
    
  504.               6 => "Transition",
    
  505.               7 => "Transition",
    
  506.               8 => "Transition",
    
  507.               9 => "Transition",
    
  508.               10 => "Transition",
    
  509.               11 => "Transition",
    
  510.               12 => "Transition",
    
  511.               13 => "Transition",
    
  512.               14 => "Transition",
    
  513.               15 => "Transition",
    
  514.               16 => "Transition",
    
  515.               17 => "Transition",
    
  516.               18 => "Transition",
    
  517.               19 => "Transition",
    
  518.               20 => "Transition",
    
  519.               21 => "Transition",
    
  520.               22 => "Retry",
    
  521.               23 => "Retry",
    
  522.               24 => "Retry",
    
  523.               25 => "Retry",
    
  524.               26 => "Retry",
    
  525.               27 => "SelectiveHydration",
    
  526.               28 => "IdleHydration",
    
  527.               29 => "Idle",
    
  528.               30 => "Offscreen",
    
  529.             },
    
  530.             "laneToReactMeasureMap": Map {
    
  531.               0 => [],
    
  532.               1 => [],
    
  533.               2 => [],
    
  534.               3 => [],
    
  535.               4 => [],
    
  536.               5 => [],
    
  537.               6 => [],
    
  538.               7 => [],
    
  539.               8 => [],
    
  540.               9 => [
    
  541.                 {
    
  542.                   "batchUID": 0,
    
  543.                   "depth": 0,
    
  544.                   "duration": 0.005,
    
  545.                   "lanes": "0b0000000000000000000000000001001",
    
  546.                   "timestamp": 0.006,
    
  547.                   "type": "render-idle",
    
  548.                 },
    
  549.                 {
    
  550.                   "batchUID": 0,
    
  551.                   "depth": 0,
    
  552.                   "duration": 0.001,
    
  553.                   "lanes": "0b0000000000000000000000000001001",
    
  554.                   "timestamp": 0.006,
    
  555.                   "type": "render",
    
  556.                 },
    
  557.                 {
    
  558.                   "batchUID": 0,
    
  559.                   "depth": 0,
    
  560.                   "duration": 0.003,
    
  561.                   "lanes": "0b0000000000000000000000000001001",
    
  562.                   "timestamp": 0.008,
    
  563.                   "type": "commit",
    
  564.                 },
    
  565.                 {
    
  566.                   "batchUID": 0,
    
  567.                   "depth": 1,
    
  568.                   "duration": 0.001,
    
  569.                   "lanes": "0b0000000000000000000000000001001",
    
  570.                   "timestamp": 0.009,
    
  571.                   "type": "layout-effects",
    
  572.                 },
    
  573.               ],
    
  574.               10 => [],
    
  575.               11 => [],
    
  576.               12 => [],
    
  577.               13 => [],
    
  578.               14 => [],
    
  579.               15 => [],
    
  580.               16 => [],
    
  581.               17 => [],
    
  582.               18 => [],
    
  583.               19 => [],
    
  584.               20 => [],
    
  585.               21 => [],
    
  586.               22 => [],
    
  587.               23 => [],
    
  588.               24 => [],
    
  589.               25 => [],
    
  590.               26 => [],
    
  591.               27 => [],
    
  592.               28 => [],
    
  593.               29 => [],
    
  594.               30 => [],
    
  595.             },
    
  596.             "nativeEvents": [],
    
  597.             "networkMeasures": [],
    
  598.             "otherUserTimingMarks": [],
    
  599.             "reactVersion": "<filtered-version>",
    
  600.             "schedulingEvents": [
    
  601.               {
    
  602.                 "lanes": "0b0000000000000000000000000001001",
    
  603.                 "timestamp": 0.005,
    
  604.                 "type": "schedule-render",
    
  605.                 "warning": null,
    
  606.               },
    
  607.             ],
    
  608.             "snapshotHeight": 0,
    
  609.             "snapshots": [],
    
  610.             "startTime": 1,
    
  611.             "suspenseEvents": [],
    
  612.             "thrownErrors": [],
    
  613.           }
    
  614.         `);
    
  615.       });
    
  616. 
    
  617.       it('should process a sample legacy render sequence', async () => {
    
  618.         utils.legacyRender(<div />, document.createElement('div'));
    
  619. 
    
  620.         const data = await preprocessData([
    
  621.           ...createBoilerplateEntries(),
    
  622.           ...createUserTimingData(clearedMarks),
    
  623.         ]);
    
  624.         expect(data).toMatchInlineSnapshot(`
    
  625.           {
    
  626.             "batchUIDToMeasuresMap": Map {
    
  627.               0 => [
    
  628.                 {
    
  629.                   "batchUID": 0,
    
  630.                   "depth": 0,
    
  631.                   "duration": 0.01,
    
  632.                   "lanes": "0b0000000000000000000000000000001",
    
  633.                   "timestamp": 0.006,
    
  634.                   "type": "render-idle",
    
  635.                 },
    
  636.                 {
    
  637.                   "batchUID": 0,
    
  638.                   "depth": 0,
    
  639.                   "duration": 0.001,
    
  640.                   "lanes": "0b0000000000000000000000000000001",
    
  641.                   "timestamp": 0.006,
    
  642.                   "type": "render",
    
  643.                 },
    
  644.                 {
    
  645.                   "batchUID": 0,
    
  646.                   "depth": 0,
    
  647.                   "duration": 0.008,
    
  648.                   "lanes": "0b0000000000000000000000000000001",
    
  649.                   "timestamp": 0.008,
    
  650.                   "type": "commit",
    
  651.                 },
    
  652.                 {
    
  653.                   "batchUID": 0,
    
  654.                   "depth": 1,
    
  655.                   "duration": 0.001,
    
  656.                   "lanes": "0b0000000000000000000000000000001",
    
  657.                   "timestamp": 0.014,
    
  658.                   "type": "layout-effects",
    
  659.                 },
    
  660.               ],
    
  661.             },
    
  662.             "componentMeasures": [],
    
  663.             "duration": 0.016,
    
  664.             "flamechart": [],
    
  665.             "internalModuleSourceToRanges": Map {
    
  666.               undefined => [
    
  667.                 [
    
  668.                   {
    
  669.                     "columnNumber": 0,
    
  670.                     "functionName": "filtered",
    
  671.                     "lineNumber": 0,
    
  672.                     "source": "  at filtered (<anonymous>:0:0)",
    
  673.                   },
    
  674.                   {
    
  675.                     "columnNumber": 1,
    
  676.                     "functionName": "filtered",
    
  677.                     "lineNumber": 1,
    
  678.                     "source": "  at filtered (<anonymous>:1:1)",
    
  679.                   },
    
  680.                 ],
    
  681.               ],
    
  682.             },
    
  683.             "laneToLabelMap": Map {
    
  684.               0 => "Sync",
    
  685.               1 => "InputContinuousHydration",
    
  686.               2 => "InputContinuous",
    
  687.               3 => "DefaultHydration",
    
  688.               4 => "Default",
    
  689.               5 => "TransitionHydration",
    
  690.               6 => "Transition",
    
  691.               7 => "Transition",
    
  692.               8 => "Transition",
    
  693.               9 => "Transition",
    
  694.               10 => "Transition",
    
  695.               11 => "Transition",
    
  696.               12 => "Transition",
    
  697.               13 => "Transition",
    
  698.               14 => "Transition",
    
  699.               15 => "Transition",
    
  700.               16 => "Transition",
    
  701.               17 => "Transition",
    
  702.               18 => "Transition",
    
  703.               19 => "Transition",
    
  704.               20 => "Transition",
    
  705.               21 => "Transition",
    
  706.               22 => "Retry",
    
  707.               23 => "Retry",
    
  708.               24 => "Retry",
    
  709.               25 => "Retry",
    
  710.               26 => "Retry",
    
  711.               27 => "SelectiveHydration",
    
  712.               28 => "IdleHydration",
    
  713.               29 => "Idle",
    
  714.               30 => "Offscreen",
    
  715.             },
    
  716.             "laneToReactMeasureMap": Map {
    
  717.               0 => [],
    
  718.               1 => [
    
  719.                 {
    
  720.                   "batchUID": 0,
    
  721.                   "depth": 0,
    
  722.                   "duration": 0.01,
    
  723.                   "lanes": "0b0000000000000000000000000000001",
    
  724.                   "timestamp": 0.006,
    
  725.                   "type": "render-idle",
    
  726.                 },
    
  727.                 {
    
  728.                   "batchUID": 0,
    
  729.                   "depth": 0,
    
  730.                   "duration": 0.001,
    
  731.                   "lanes": "0b0000000000000000000000000000001",
    
  732.                   "timestamp": 0.006,
    
  733.                   "type": "render",
    
  734.                 },
    
  735.                 {
    
  736.                   "batchUID": 0,
    
  737.                   "depth": 0,
    
  738.                   "duration": 0.008,
    
  739.                   "lanes": "0b0000000000000000000000000000001",
    
  740.                   "timestamp": 0.008,
    
  741.                   "type": "commit",
    
  742.                 },
    
  743.                 {
    
  744.                   "batchUID": 0,
    
  745.                   "depth": 1,
    
  746.                   "duration": 0.001,
    
  747.                   "lanes": "0b0000000000000000000000000000001",
    
  748.                   "timestamp": 0.014,
    
  749.                   "type": "layout-effects",
    
  750.                 },
    
  751.               ],
    
  752.               2 => [],
    
  753.               3 => [],
    
  754.               4 => [],
    
  755.               5 => [],
    
  756.               6 => [],
    
  757.               7 => [],
    
  758.               8 => [],
    
  759.               9 => [],
    
  760.               10 => [],
    
  761.               11 => [],
    
  762.               12 => [],
    
  763.               13 => [],
    
  764.               14 => [],
    
  765.               15 => [],
    
  766.               16 => [],
    
  767.               17 => [],
    
  768.               18 => [],
    
  769.               19 => [],
    
  770.               20 => [],
    
  771.               21 => [],
    
  772.               22 => [],
    
  773.               23 => [],
    
  774.               24 => [],
    
  775.               25 => [],
    
  776.               26 => [],
    
  777.               27 => [],
    
  778.               28 => [],
    
  779.               29 => [],
    
  780.               30 => [],
    
  781.             },
    
  782.             "nativeEvents": [],
    
  783.             "networkMeasures": [],
    
  784.             "otherUserTimingMarks": [],
    
  785.             "reactVersion": "<filtered-version>",
    
  786.             "schedulingEvents": [
    
  787.               {
    
  788.                 "lanes": "0b0000000000000000000000000000001",
    
  789.                 "timestamp": 0.005,
    
  790.                 "type": "schedule-render",
    
  791.                 "warning": null,
    
  792.               },
    
  793.             ],
    
  794.             "snapshotHeight": 0,
    
  795.             "snapshots": [],
    
  796.             "startTime": 4,
    
  797.             "suspenseEvents": [],
    
  798.             "thrownErrors": [],
    
  799.           }
    
  800.         `);
    
  801.       });
    
  802. 
    
  803.       it('should process a sample createRoot render sequence', async () => {
    
  804.         function App() {
    
  805.           const [didMount, setDidMount] = React.useState(false);
    
  806.           React.useEffect(() => {
    
  807.             if (!didMount) {
    
  808.               setDidMount(true);
    
  809.             }
    
  810.           });
    
  811.           return true;
    
  812.         }
    
  813. 
    
  814.         const root = ReactDOMClient.createRoot(document.createElement('div'));
    
  815.         utils.act(() => root.render(<App />));
    
  816. 
    
  817.         const data = await preprocessData([
    
  818.           ...createBoilerplateEntries(),
    
  819.           ...createUserTimingData(clearedMarks),
    
  820.         ]);
    
  821.         expect(data).toMatchInlineSnapshot(`
    
  822.           {
    
  823.             "batchUIDToMeasuresMap": Map {
    
  824.               0 => [
    
  825.                 {
    
  826.                   "batchUID": 0,
    
  827.                   "depth": 0,
    
  828.                   "duration": 0.012,
    
  829.                   "lanes": "0b0000000000000000000000000000101",
    
  830.                   "timestamp": 0.006,
    
  831.                   "type": "render-idle",
    
  832.                 },
    
  833.                 {
    
  834.                   "batchUID": 0,
    
  835.                   "depth": 0,
    
  836.                   "duration": 0.003,
    
  837.                   "lanes": "0b0000000000000000000000000000101",
    
  838.                   "timestamp": 0.006,
    
  839.                   "type": "render",
    
  840.                 },
    
  841.                 {
    
  842.                   "batchUID": 0,
    
  843.                   "depth": 0,
    
  844.                   "duration": 0.008,
    
  845.                   "lanes": "0b0000000000000000000000000000101",
    
  846.                   "timestamp": 0.01,
    
  847.                   "type": "commit",
    
  848.                 },
    
  849.                 {
    
  850.                   "batchUID": 0,
    
  851.                   "depth": 1,
    
  852.                   "duration": 0.001,
    
  853.                   "lanes": "0b0000000000000000000000000000101",
    
  854.                   "timestamp": 0.016,
    
  855.                   "type": "layout-effects",
    
  856.                 },
    
  857.                 {
    
  858.                   "batchUID": 0,
    
  859.                   "depth": 0,
    
  860.                   "duration": 0.004,
    
  861.                   "lanes": "0b0000000000000000000000000000101",
    
  862.                   "timestamp": 0.019,
    
  863.                   "type": "passive-effects",
    
  864.                 },
    
  865.               ],
    
  866.               1 => [
    
  867.                 {
    
  868.                   "batchUID": 1,
    
  869.                   "depth": 0,
    
  870.                   "duration": 0.012,
    
  871.                   "lanes": "0b0000000000000000000000000000101",
    
  872.                   "timestamp": 0.024,
    
  873.                   "type": "render-idle",
    
  874.                 },
    
  875.                 {
    
  876.                   "batchUID": 1,
    
  877.                   "depth": 0,
    
  878.                   "duration": 0.003,
    
  879.                   "lanes": "0b0000000000000000000000000000101",
    
  880.                   "timestamp": 0.024,
    
  881.                   "type": "render",
    
  882.                 },
    
  883.                 {
    
  884.                   "batchUID": 1,
    
  885.                   "depth": 0,
    
  886.                   "duration": 0.008,
    
  887.                   "lanes": "0b0000000000000000000000000000101",
    
  888.                   "timestamp": 0.028,
    
  889.                   "type": "commit",
    
  890.                 },
    
  891.                 {
    
  892.                   "batchUID": 1,
    
  893.                   "depth": 1,
    
  894.                   "duration": 0.001,
    
  895.                   "lanes": "0b0000000000000000000000000000101",
    
  896.                   "timestamp": 0.034,
    
  897.                   "type": "layout-effects",
    
  898.                 },
    
  899.                 {
    
  900.                   "batchUID": 1,
    
  901.                   "depth": 0,
    
  902.                   "duration": 0.003,
    
  903.                   "lanes": "0b0000000000000000000000000000101",
    
  904.                   "timestamp": 0.037,
    
  905.                   "type": "passive-effects",
    
  906.                 },
    
  907.               ],
    
  908.             },
    
  909.             "componentMeasures": [
    
  910.               {
    
  911.                 "componentName": "App",
    
  912.                 "duration": 0.001,
    
  913.                 "timestamp": 0.007,
    
  914.                 "type": "render",
    
  915.                 "warning": null,
    
  916.               },
    
  917.               {
    
  918.                 "componentName": "App",
    
  919.                 "duration": 0.002,
    
  920.                 "timestamp": 0.02,
    
  921.                 "type": "passive-effect-mount",
    
  922.                 "warning": null,
    
  923.               },
    
  924.               {
    
  925.                 "componentName": "App",
    
  926.                 "duration": 0.001,
    
  927.                 "timestamp": 0.025,
    
  928.                 "type": "render",
    
  929.                 "warning": null,
    
  930.               },
    
  931.               {
    
  932.                 "componentName": "App",
    
  933.                 "duration": 0.001,
    
  934.                 "timestamp": 0.038,
    
  935.                 "type": "passive-effect-mount",
    
  936.                 "warning": null,
    
  937.               },
    
  938.             ],
    
  939.             "duration": 0.04,
    
  940.             "flamechart": [],
    
  941.             "internalModuleSourceToRanges": Map {
    
  942.               undefined => [
    
  943.                 [
    
  944.                   {
    
  945.                     "columnNumber": 0,
    
  946.                     "functionName": "filtered",
    
  947.                     "lineNumber": 0,
    
  948.                     "source": "  at filtered (<anonymous>:0:0)",
    
  949.                   },
    
  950.                   {
    
  951.                     "columnNumber": 1,
    
  952.                     "functionName": "filtered",
    
  953.                     "lineNumber": 1,
    
  954.                     "source": "  at filtered (<anonymous>:1:1)",
    
  955.                   },
    
  956.                 ],
    
  957.               ],
    
  958.             },
    
  959.             "laneToLabelMap": Map {
    
  960.               0 => "Sync",
    
  961.               1 => "InputContinuousHydration",
    
  962.               2 => "InputContinuous",
    
  963.               3 => "DefaultHydration",
    
  964.               4 => "Default",
    
  965.               5 => "TransitionHydration",
    
  966.               6 => "Transition",
    
  967.               7 => "Transition",
    
  968.               8 => "Transition",
    
  969.               9 => "Transition",
    
  970.               10 => "Transition",
    
  971.               11 => "Transition",
    
  972.               12 => "Transition",
    
  973.               13 => "Transition",
    
  974.               14 => "Transition",
    
  975.               15 => "Transition",
    
  976.               16 => "Transition",
    
  977.               17 => "Transition",
    
  978.               18 => "Transition",
    
  979.               19 => "Transition",
    
  980.               20 => "Transition",
    
  981.               21 => "Transition",
    
  982.               22 => "Retry",
    
  983.               23 => "Retry",
    
  984.               24 => "Retry",
    
  985.               25 => "Retry",
    
  986.               26 => "Retry",
    
  987.               27 => "SelectiveHydration",
    
  988.               28 => "IdleHydration",
    
  989.               29 => "Idle",
    
  990.               30 => "Offscreen",
    
  991.             },
    
  992.             "laneToReactMeasureMap": Map {
    
  993.               0 => [],
    
  994.               1 => [],
    
  995.               2 => [],
    
  996.               3 => [],
    
  997.               4 => [],
    
  998.               5 => [
    
  999.                 {
    
  1000.                   "batchUID": 0,
    
  1001.                   "depth": 0,
    
  1002.                   "duration": 0.012,
    
  1003.                   "lanes": "0b0000000000000000000000000000101",
    
  1004.                   "timestamp": 0.006,
    
  1005.                   "type": "render-idle",
    
  1006.                 },
    
  1007.                 {
    
  1008.                   "batchUID": 0,
    
  1009.                   "depth": 0,
    
  1010.                   "duration": 0.003,
    
  1011.                   "lanes": "0b0000000000000000000000000000101",
    
  1012.                   "timestamp": 0.006,
    
  1013.                   "type": "render",
    
  1014.                 },
    
  1015.                 {
    
  1016.                   "batchUID": 0,
    
  1017.                   "depth": 0,
    
  1018.                   "duration": 0.008,
    
  1019.                   "lanes": "0b0000000000000000000000000000101",
    
  1020.                   "timestamp": 0.01,
    
  1021.                   "type": "commit",
    
  1022.                 },
    
  1023.                 {
    
  1024.                   "batchUID": 0,
    
  1025.                   "depth": 1,
    
  1026.                   "duration": 0.001,
    
  1027.                   "lanes": "0b0000000000000000000000000000101",
    
  1028.                   "timestamp": 0.016,
    
  1029.                   "type": "layout-effects",
    
  1030.                 },
    
  1031.                 {
    
  1032.                   "batchUID": 0,
    
  1033.                   "depth": 0,
    
  1034.                   "duration": 0.004,
    
  1035.                   "lanes": "0b0000000000000000000000000000101",
    
  1036.                   "timestamp": 0.019,
    
  1037.                   "type": "passive-effects",
    
  1038.                 },
    
  1039.                 {
    
  1040.                   "batchUID": 1,
    
  1041.                   "depth": 0,
    
  1042.                   "duration": 0.012,
    
  1043.                   "lanes": "0b0000000000000000000000000000101",
    
  1044.                   "timestamp": 0.024,
    
  1045.                   "type": "render-idle",
    
  1046.                 },
    
  1047.                 {
    
  1048.                   "batchUID": 1,
    
  1049.                   "depth": 0,
    
  1050.                   "duration": 0.003,
    
  1051.                   "lanes": "0b0000000000000000000000000000101",
    
  1052.                   "timestamp": 0.024,
    
  1053.                   "type": "render",
    
  1054.                 },
    
  1055.                 {
    
  1056.                   "batchUID": 1,
    
  1057.                   "depth": 0,
    
  1058.                   "duration": 0.008,
    
  1059.                   "lanes": "0b0000000000000000000000000000101",
    
  1060.                   "timestamp": 0.028,
    
  1061.                   "type": "commit",
    
  1062.                 },
    
  1063.                 {
    
  1064.                   "batchUID": 1,
    
  1065.                   "depth": 1,
    
  1066.                   "duration": 0.001,
    
  1067.                   "lanes": "0b0000000000000000000000000000101",
    
  1068.                   "timestamp": 0.034,
    
  1069.                   "type": "layout-effects",
    
  1070.                 },
    
  1071.                 {
    
  1072.                   "batchUID": 1,
    
  1073.                   "depth": 0,
    
  1074.                   "duration": 0.003,
    
  1075.                   "lanes": "0b0000000000000000000000000000101",
    
  1076.                   "timestamp": 0.037,
    
  1077.                   "type": "passive-effects",
    
  1078.                 },
    
  1079.               ],
    
  1080.               6 => [],
    
  1081.               7 => [],
    
  1082.               8 => [],
    
  1083.               9 => [],
    
  1084.               10 => [],
    
  1085.               11 => [],
    
  1086.               12 => [],
    
  1087.               13 => [],
    
  1088.               14 => [],
    
  1089.               15 => [],
    
  1090.               16 => [],
    
  1091.               17 => [],
    
  1092.               18 => [],
    
  1093.               19 => [],
    
  1094.               20 => [],
    
  1095.               21 => [],
    
  1096.               22 => [],
    
  1097.               23 => [],
    
  1098.               24 => [],
    
  1099.               25 => [],
    
  1100.               26 => [],
    
  1101.               27 => [],
    
  1102.               28 => [],
    
  1103.               29 => [],
    
  1104.               30 => [],
    
  1105.             },
    
  1106.             "nativeEvents": [],
    
  1107.             "networkMeasures": [],
    
  1108.             "otherUserTimingMarks": [],
    
  1109.             "reactVersion": "<filtered-version>",
    
  1110.             "schedulingEvents": [
    
  1111.               {
    
  1112.                 "lanes": "0b0000000000000000000000000000101",
    
  1113.                 "timestamp": 0.005,
    
  1114.                 "type": "schedule-render",
    
  1115.                 "warning": null,
    
  1116.               },
    
  1117.               {
    
  1118.                 "componentName": "App",
    
  1119.                 "lanes": "0b0000000000000000000000000000101",
    
  1120.                 "timestamp": 0.021,
    
  1121.                 "type": "schedule-state-update",
    
  1122.                 "warning": null,
    
  1123.               },
    
  1124.             ],
    
  1125.             "snapshotHeight": 0,
    
  1126.             "snapshots": [],
    
  1127.             "startTime": 4,
    
  1128.             "suspenseEvents": [],
    
  1129.             "thrownErrors": [],
    
  1130.           }
    
  1131.         `);
    
  1132.       });
    
  1133. 
    
  1134.       // @reactVersion >= 18.0
    
  1135.       it('should error if events and measures are incomplete', async () => {
    
  1136.         const container = document.createElement('div');
    
  1137.         utils.legacyRender(<div />, container);
    
  1138. 
    
  1139.         const invalidMarks = clearedMarks.filter(
    
  1140.           mark => !mark.includes('render-stop'),
    
  1141.         );
    
  1142.         const invalidUserTimingData = createUserTimingData(invalidMarks);
    
  1143. 
    
  1144.         const error = jest.spyOn(console, 'error').mockImplementation(() => {});
    
  1145.         preprocessData([
    
  1146.           ...createBoilerplateEntries(),
    
  1147.           ...invalidUserTimingData,
    
  1148.         ]);
    
  1149.         expect(error).toHaveBeenCalled();
    
  1150.       });
    
  1151. 
    
  1152.       // @reactVersion >= 18.0
    
  1153.       it('should error if work is completed without being started', async () => {
    
  1154.         const container = document.createElement('div');
    
  1155.         utils.legacyRender(<div />, container);
    
  1156. 
    
  1157.         const invalidMarks = clearedMarks.filter(
    
  1158.           mark => !mark.includes('render-start'),
    
  1159.         );
    
  1160.         const invalidUserTimingData = createUserTimingData(invalidMarks);
    
  1161. 
    
  1162.         const error = jest.spyOn(console, 'error').mockImplementation(() => {});
    
  1163.         preprocessData([
    
  1164.           ...createBoilerplateEntries(),
    
  1165.           ...invalidUserTimingData,
    
  1166.         ]);
    
  1167.         expect(error).toHaveBeenCalled();
    
  1168.       });
    
  1169. 
    
  1170.       // @reactVersion >= 18.0
    
  1171.       it('should populate other user timing marks', async () => {
    
  1172.         const userTimingData = createUserTimingData([]);
    
  1173.         userTimingData.push(
    
  1174.           createUserTimingEntry({
    
  1175.             args: {},
    
  1176.             cat: 'blink.user_timing',
    
  1177.             id: '0xcdf75f7c',
    
  1178.             name: 'VCWithoutImage: root',
    
  1179.             ph: 'n',
    
  1180.             scope: 'blink.user_timing',
    
  1181.           }),
    
  1182.         );
    
  1183.         userTimingData.push(
    
  1184.           createUserTimingEntry({
    
  1185.             cat: 'blink.user_timing',
    
  1186.             name: '--a-mark-that-looks-like-one-of-ours',
    
  1187.             ph: 'R',
    
  1188.           }),
    
  1189.         );
    
  1190.         userTimingData.push(
    
  1191.           createUserTimingEntry({
    
  1192.             cat: 'blink.user_timing',
    
  1193.             name: 'Some other mark',
    
  1194.             ph: 'R',
    
  1195.           }),
    
  1196.         );
    
  1197. 
    
  1198.         const data = await preprocessData([
    
  1199.           ...createBoilerplateEntries(),
    
  1200.           ...userTimingData,
    
  1201.         ]);
    
  1202.         expect(data.otherUserTimingMarks).toMatchInlineSnapshot(`
    
  1203.                 [
    
  1204.                   {
    
  1205.                     "name": "VCWithoutImage: root",
    
  1206.                     "timestamp": 0.003,
    
  1207.                   },
    
  1208.                   {
    
  1209.                     "name": "--a-mark-that-looks-like-one-of-ours",
    
  1210.                     "timestamp": 0.004,
    
  1211.                   },
    
  1212.                   {
    
  1213.                     "name": "Some other mark",
    
  1214.                     "timestamp": 0.005,
    
  1215.                   },
    
  1216.                 ]
    
  1217.           `);
    
  1218.       });
    
  1219. 
    
  1220.       // @reactVersion >= 18.0
    
  1221.       it('should include a suspended resource "displayName" if one is set', async () => {
    
  1222.         let promise = null;
    
  1223.         let resolvedValue = null;
    
  1224.         function readValue(value) {
    
  1225.           if (resolvedValue !== null) {
    
  1226.             return resolvedValue;
    
  1227.           } else if (promise === null) {
    
  1228.             promise = Promise.resolve(true).then(() => {
    
  1229.               resolvedValue = value;
    
  1230.             });
    
  1231.             promise.displayName = 'Testing displayName';
    
  1232.           }
    
  1233.           throw promise;
    
  1234.         }
    
  1235. 
    
  1236.         function Component() {
    
  1237.           const value = readValue(123);
    
  1238.           return value;
    
  1239.         }
    
  1240. 
    
  1241.         const testMarks = [creactCpuProfilerSample()];
    
  1242. 
    
  1243.         const root = ReactDOMClient.createRoot(document.createElement('div'));
    
  1244.         utils.act(() =>
    
  1245.           root.render(
    
  1246.             <React.Suspense fallback="Loading...">
    
  1247.               <Component />
    
  1248.             </React.Suspense>,
    
  1249.           ),
    
  1250.         );
    
  1251. 
    
  1252.         testMarks.push(...createUserTimingData(clearedMarks));
    
  1253. 
    
  1254.         let data;
    
  1255.         await utils.actAsync(async () => {
    
  1256.           data = await preprocessData(testMarks);
    
  1257.         });
    
  1258.         expect(data.suspenseEvents).toHaveLength(1);
    
  1259.         expect(data.suspenseEvents[0].promiseName).toBe('Testing displayName');
    
  1260.       });
    
  1261. 
    
  1262.       describe('warnings', () => {
    
  1263.         describe('long event handlers', () => {
    
  1264.           // @reactVersion >= 18.0
    
  1265.           it('should not warn when React scedules a (sync) update inside of a short event handler', async () => {
    
  1266.             function App() {
    
  1267.               return null;
    
  1268.             }
    
  1269. 
    
  1270.             const testMarks = [
    
  1271.               creactCpuProfilerSample(),
    
  1272.               ...createBoilerplateEntries(),
    
  1273.               createNativeEventEntry('click', 5),
    
  1274.             ];
    
  1275. 
    
  1276.             clearPendingMarks();
    
  1277. 
    
  1278.             utils.legacyRender(<App />, document.createElement('div'));
    
  1279. 
    
  1280.             testMarks.push(...createUserTimingData(clearedMarks));
    
  1281. 
    
  1282.             const data = await preprocessData(testMarks);
    
  1283.             const event = data.nativeEvents.find(({type}) => type === 'click');
    
  1284.             expect(event.warning).toBe(null);
    
  1285.           });
    
  1286. 
    
  1287.           // @reactVersion >= 18.0
    
  1288.           it('should not warn about long events if the cause was non-React JavaScript', async () => {
    
  1289.             function App() {
    
  1290.               return null;
    
  1291.             }
    
  1292. 
    
  1293.             const testMarks = [
    
  1294.               creactCpuProfilerSample(),
    
  1295.               ...createBoilerplateEntries(),
    
  1296.               createNativeEventEntry('click', 25000),
    
  1297.             ];
    
  1298. 
    
  1299.             startTime += 2000;
    
  1300. 
    
  1301.             clearPendingMarks();
    
  1302. 
    
  1303.             utils.legacyRender(<App />, document.createElement('div'));
    
  1304. 
    
  1305.             testMarks.push(...createUserTimingData(clearedMarks));
    
  1306. 
    
  1307.             const data = await preprocessData(testMarks);
    
  1308.             const event = data.nativeEvents.find(({type}) => type === 'click');
    
  1309.             expect(event.warning).toBe(null);
    
  1310.           });
    
  1311. 
    
  1312.           // @reactVersion >= 18.0
    
  1313.           it('should warn when React scedules a long (sync) update inside of an event', async () => {
    
  1314.             function App() {
    
  1315.               return null;
    
  1316.             }
    
  1317. 
    
  1318.             const testMarks = [
    
  1319.               creactCpuProfilerSample(),
    
  1320.               ...createBoilerplateEntries(),
    
  1321.               createNativeEventEntry('click', 25000),
    
  1322.             ];
    
  1323. 
    
  1324.             clearPendingMarks();
    
  1325. 
    
  1326.             utils.legacyRender(<App />, document.createElement('div'));
    
  1327. 
    
  1328.             clearedMarks.forEach(markName => {
    
  1329.               if (markName === '--render-stop') {
    
  1330.                 // Fake a long running render
    
  1331.                 startTime += 20000;
    
  1332.               }
    
  1333. 
    
  1334.               testMarks.push({
    
  1335.                 pid: ++pid,
    
  1336.                 tid: ++tid,
    
  1337.                 ts: ++startTime,
    
  1338.                 args: {data: {}},
    
  1339.                 cat: 'blink.user_timing',
    
  1340.                 name: markName,
    
  1341.                 ph: 'R',
    
  1342.               });
    
  1343.             });
    
  1344. 
    
  1345.             const data = await preprocessData(testMarks);
    
  1346.             const event = data.nativeEvents.find(({type}) => type === 'click');
    
  1347.             expect(event.warning).toMatchInlineSnapshot(
    
  1348.               `"An event handler scheduled a big update with React. Consider using the Transition API to defer some of this work."`,
    
  1349.             );
    
  1350.           });
    
  1351. 
    
  1352.           // @reactVersion >= 18.2
    
  1353.           it('should not warn when React finishes a previously long (async) update with a short (sync) update inside of an event', async () => {
    
  1354.             function Yield({id, value}) {
    
  1355.               Scheduler.log(`${id}:${value}`);
    
  1356.               return null;
    
  1357.             }
    
  1358. 
    
  1359.             const testMarks = [
    
  1360.               creactCpuProfilerSample(),
    
  1361.               ...createBoilerplateEntries(),
    
  1362.             ];
    
  1363. 
    
  1364.             // Advance the clock by some arbitrary amount.
    
  1365.             startTime += 50000;
    
  1366. 
    
  1367.             const root = ReactDOMClient.createRoot(
    
  1368.               document.createElement('div'),
    
  1369.             );
    
  1370. 
    
  1371.             // Temporarily turn off the act environment, since we're intentionally using Scheduler instead.
    
  1372.             global.IS_REACT_ACT_ENVIRONMENT = false;
    
  1373.             React.startTransition(() => {
    
  1374.               // Start rendering an async update (but don't finish).
    
  1375.               root.render(
    
  1376.                 <>
    
  1377.                   <Yield id="A" value={1} />
    
  1378.                   <Yield id="B" value={1} />
    
  1379.                 </>,
    
  1380.               );
    
  1381.             });
    
  1382. 
    
  1383.             await waitFor(['A:1']);
    
  1384. 
    
  1385.             testMarks.push(...createUserTimingData(clearedMarks));
    
  1386.             clearPendingMarks();
    
  1387. 
    
  1388.             // Advance the clock some more to make the pending React update seem long.
    
  1389.             startTime += 20000;
    
  1390. 
    
  1391.             // Fake a long "click" event in the middle
    
  1392.             // and schedule a sync update that will also flush the previous work.
    
  1393.             testMarks.push(createNativeEventEntry('click', 25000));
    
  1394.             ReactDOM.flushSync(() => {
    
  1395.               root.render(
    
  1396.                 <>
    
  1397.                   <Yield id="A" value={2} />
    
  1398.                   <Yield id="B" value={2} />
    
  1399.                 </>,
    
  1400.               );
    
  1401.             });
    
  1402. 
    
  1403.             assertLog(['A:2', 'B:2']);
    
  1404. 
    
  1405.             testMarks.push(...createUserTimingData(clearedMarks));
    
  1406. 
    
  1407.             const data = await preprocessData(testMarks);
    
  1408.             const event = data.nativeEvents.find(({type}) => type === 'click');
    
  1409.             expect(event.warning).toBe(null);
    
  1410.           });
    
  1411.         });
    
  1412. 
    
  1413.         describe('nested updates', () => {
    
  1414.           // @reactVersion >= 18.2
    
  1415.           it('should not warn about short nested (state) updates during layout effects', async () => {
    
  1416.             function Component() {
    
  1417.               const [didMount, setDidMount] = React.useState(false);
    
  1418.               Scheduler.log(`Component ${didMount ? 'update' : 'mount'}`);
    
  1419.               React.useLayoutEffect(() => {
    
  1420.                 setDidMount(true);
    
  1421.               }, []);
    
  1422.               return didMount;
    
  1423.             }
    
  1424. 
    
  1425.             const root = ReactDOMClient.createRoot(
    
  1426.               document.createElement('div'),
    
  1427.             );
    
  1428.             utils.act(() => {
    
  1429.               root.render(<Component />);
    
  1430.             });
    
  1431. 
    
  1432.             assertLog(['Component mount', 'Component update']);
    
  1433. 
    
  1434.             const data = await preprocessData([
    
  1435.               ...createBoilerplateEntries(),
    
  1436.               ...createUserTimingData(clearedMarks),
    
  1437.             ]);
    
  1438. 
    
  1439.             const event = data.schedulingEvents.find(
    
  1440.               ({type}) => type === 'schedule-state-update',
    
  1441.             );
    
  1442.             expect(event.warning).toBe(null);
    
  1443.           });
    
  1444. 
    
  1445.           // @reactVersion >= 18.2
    
  1446.           it('should not warn about short (forced) updates during layout effects', async () => {
    
  1447.             class Component extends React.Component {
    
  1448.               _didMount: boolean = false;
    
  1449.               componentDidMount() {
    
  1450.                 this._didMount = true;
    
  1451.                 this.forceUpdate();
    
  1452.               }
    
  1453.               render() {
    
  1454.                 Scheduler.log(
    
  1455.                   `Component ${this._didMount ? 'update' : 'mount'}`,
    
  1456.                 );
    
  1457.                 return null;
    
  1458.               }
    
  1459.             }
    
  1460. 
    
  1461.             const root = ReactDOMClient.createRoot(
    
  1462.               document.createElement('div'),
    
  1463.             );
    
  1464.             utils.act(() => {
    
  1465.               root.render(<Component />);
    
  1466.             });
    
  1467. 
    
  1468.             assertLog(['Component mount', 'Component update']);
    
  1469. 
    
  1470.             const data = await preprocessData([
    
  1471.               ...createBoilerplateEntries(),
    
  1472.               ...createUserTimingData(clearedMarks),
    
  1473.             ]);
    
  1474. 
    
  1475.             const event = data.schedulingEvents.find(
    
  1476.               ({type}) => type === 'schedule-force-update',
    
  1477.             );
    
  1478.             expect(event.warning).toBe(null);
    
  1479.           });
    
  1480. 
    
  1481.           // This is temporarily disabled because the warning doesn't work
    
  1482.           // with useDeferredValue
    
  1483.           it.skip('should warn about long nested (state) updates during layout effects', async () => {
    
  1484.             function Component() {
    
  1485.               const [didMount, setDidMount] = React.useState(false);
    
  1486.               Scheduler.log(`Component ${didMount ? 'update' : 'mount'}`);
    
  1487.               // Fake a long render
    
  1488.               startTime += 20000;
    
  1489.               React.useLayoutEffect(() => {
    
  1490.                 setDidMount(true);
    
  1491.               }, []);
    
  1492.               return didMount;
    
  1493.             }
    
  1494. 
    
  1495.             const cpuProfilerSample = creactCpuProfilerSample();
    
  1496. 
    
  1497.             const root = ReactDOMClient.createRoot(
    
  1498.               document.createElement('div'),
    
  1499.             );
    
  1500.             utils.act(() => {
    
  1501.               root.render(<Component />);
    
  1502.             });
    
  1503. 
    
  1504.             assertLog(['Component mount', 'Component update']);
    
  1505. 
    
  1506.             const testMarks = [];
    
  1507.             clearedMarks.forEach(markName => {
    
  1508.               if (markName === '--component-render-start-Component') {
    
  1509.                 // Fake a long running render
    
  1510.                 startTime += 20000;
    
  1511.               }
    
  1512. 
    
  1513.               testMarks.push({
    
  1514.                 pid: ++pid,
    
  1515.                 tid: ++tid,
    
  1516.                 ts: ++startTime,
    
  1517.                 args: {data: {}},
    
  1518.                 cat: 'blink.user_timing',
    
  1519.                 name: markName,
    
  1520.                 ph: 'R',
    
  1521.               });
    
  1522.             });
    
  1523. 
    
  1524.             const data = await preprocessData([
    
  1525.               cpuProfilerSample,
    
  1526.               ...createBoilerplateEntries(),
    
  1527.               ...testMarks,
    
  1528.             ]);
    
  1529. 
    
  1530.             const event = data.schedulingEvents.find(
    
  1531.               ({type}) => type === 'schedule-state-update',
    
  1532.             );
    
  1533.             expect(event.warning).toMatchInlineSnapshot(
    
  1534.               `"A big nested update was scheduled during layout. Nested updates require React to re-render synchronously before the browser can paint. Consider delaying this update by moving it to a passive effect (useEffect)."`,
    
  1535.             );
    
  1536.           });
    
  1537. 
    
  1538.           // This is temporarily disabled because the warning doesn't work
    
  1539.           // with useDeferredValue
    
  1540.           it.skip('should warn about long nested (forced) updates during layout effects', async () => {
    
  1541.             class Component extends React.Component {
    
  1542.               _didMount: boolean = false;
    
  1543.               componentDidMount() {
    
  1544.                 this._didMount = true;
    
  1545.                 this.forceUpdate();
    
  1546.               }
    
  1547.               render() {
    
  1548.                 Scheduler.log(
    
  1549.                   `Component ${this._didMount ? 'update' : 'mount'}`,
    
  1550.                 );
    
  1551.                 return null;
    
  1552.               }
    
  1553.             }
    
  1554. 
    
  1555.             const cpuProfilerSample = creactCpuProfilerSample();
    
  1556. 
    
  1557.             const root = ReactDOMClient.createRoot(
    
  1558.               document.createElement('div'),
    
  1559.             );
    
  1560.             utils.act(() => {
    
  1561.               root.render(<Component />);
    
  1562.             });
    
  1563. 
    
  1564.             assertLog(['Component mount', 'Component update']);
    
  1565. 
    
  1566.             const testMarks = [];
    
  1567.             clearedMarks.forEach(markName => {
    
  1568.               if (markName === '--component-render-start-Component') {
    
  1569.                 // Fake a long running render
    
  1570.                 startTime += 20000;
    
  1571.               }
    
  1572. 
    
  1573.               testMarks.push({
    
  1574.                 pid: ++pid,
    
  1575.                 tid: ++tid,
    
  1576.                 ts: ++startTime,
    
  1577.                 args: {data: {}},
    
  1578.                 cat: 'blink.user_timing',
    
  1579.                 name: markName,
    
  1580.                 ph: 'R',
    
  1581.               });
    
  1582.             });
    
  1583. 
    
  1584.             const data = await preprocessData([
    
  1585.               cpuProfilerSample,
    
  1586.               ...createBoilerplateEntries(),
    
  1587.               ...testMarks,
    
  1588.             ]);
    
  1589. 
    
  1590.             const event = data.schedulingEvents.find(
    
  1591.               ({type}) => type === 'schedule-force-update',
    
  1592.             );
    
  1593.             expect(event.warning).toMatchInlineSnapshot(
    
  1594.               `"A big nested update was scheduled during layout. Nested updates require React to re-render synchronously before the browser can paint. Consider delaying this update by moving it to a passive effect (useEffect)."`,
    
  1595.             );
    
  1596.           });
    
  1597. 
    
  1598.           // @reactVersion >= 18.2
    
  1599.           it('should not warn about transition updates scheduled during commit phase', async () => {
    
  1600.             function Component() {
    
  1601.               const [value, setValue] = React.useState(0);
    
  1602.               // eslint-disable-next-line no-unused-vars
    
  1603.               const [isPending, startTransition] = React.useTransition();
    
  1604. 
    
  1605.               Scheduler.log(`Component rendered with value ${value}`);
    
  1606. 
    
  1607.               // Fake a long render
    
  1608.               if (value !== 0) {
    
  1609.                 Scheduler.log('Long render');
    
  1610.                 startTime += 20000;
    
  1611.               }
    
  1612. 
    
  1613.               React.useLayoutEffect(() => {
    
  1614.                 startTransition(() => {
    
  1615.                   setValue(1);
    
  1616.                 });
    
  1617.               }, []);
    
  1618. 
    
  1619.               return value;
    
  1620.             }
    
  1621. 
    
  1622.             const cpuProfilerSample = creactCpuProfilerSample();
    
  1623. 
    
  1624.             const root = ReactDOMClient.createRoot(
    
  1625.               document.createElement('div'),
    
  1626.             );
    
  1627.             utils.act(() => {
    
  1628.               root.render(<Component />);
    
  1629.             });
    
  1630. 
    
  1631.             assertLog([
    
  1632.               'Component rendered with value 0',
    
  1633.               'Component rendered with value 0',
    
  1634.               'Component rendered with value 1',
    
  1635.               'Long render',
    
  1636.             ]);
    
  1637. 
    
  1638.             const testMarks = [];
    
  1639.             clearedMarks.forEach(markName => {
    
  1640.               if (markName === '--component-render-start-Component') {
    
  1641.                 // Fake a long running render
    
  1642.                 startTime += 20000;
    
  1643.               }
    
  1644. 
    
  1645.               testMarks.push({
    
  1646.                 pid: ++pid,
    
  1647.                 tid: ++tid,
    
  1648.                 ts: ++startTime,
    
  1649.                 args: {data: {}},
    
  1650.                 cat: 'blink.user_timing',
    
  1651.                 name: markName,
    
  1652.                 ph: 'R',
    
  1653.               });
    
  1654.             });
    
  1655. 
    
  1656.             const data = await preprocessData([
    
  1657.               cpuProfilerSample,
    
  1658.               ...createBoilerplateEntries(),
    
  1659.               ...testMarks,
    
  1660.             ]);
    
  1661. 
    
  1662.             data.schedulingEvents.forEach(event => {
    
  1663.               expect(event.warning).toBeNull();
    
  1664.             });
    
  1665.           });
    
  1666. 
    
  1667.           // This is temporarily disabled because the warning doesn't work
    
  1668.           // with useDeferredValue
    
  1669.           it.skip('should not warn about deferred value updates scheduled during commit phase', async () => {
    
  1670.             function Component() {
    
  1671.               const [value, setValue] = React.useState(0);
    
  1672.               const deferredValue = React.useDeferredValue(value);
    
  1673. 
    
  1674.               Scheduler.log(
    
  1675.                 `Component rendered with value ${value} and deferredValue ${deferredValue}`,
    
  1676.               );
    
  1677. 
    
  1678.               // Fake a long render
    
  1679.               if (deferredValue !== 0) {
    
  1680.                 Scheduler.log('Long render');
    
  1681.                 startTime += 20000;
    
  1682.               }
    
  1683. 
    
  1684.               React.useLayoutEffect(() => {
    
  1685.                 setValue(1);
    
  1686.               }, []);
    
  1687. 
    
  1688.               return value + deferredValue;
    
  1689.             }
    
  1690. 
    
  1691.             const cpuProfilerSample = creactCpuProfilerSample();
    
  1692. 
    
  1693.             const root = ReactDOMClient.createRoot(
    
  1694.               document.createElement('div'),
    
  1695.             );
    
  1696.             utils.act(() => {
    
  1697.               root.render(<Component />);
    
  1698.             });
    
  1699. 
    
  1700.             assertLog([
    
  1701.               'Component rendered with value 0 and deferredValue 0',
    
  1702.               'Component rendered with value 1 and deferredValue 0',
    
  1703.               'Component rendered with value 1 and deferredValue 1',
    
  1704.               'Long render',
    
  1705.             ]);
    
  1706. 
    
  1707.             const testMarks = [];
    
  1708.             clearedMarks.forEach(markName => {
    
  1709.               if (markName === '--component-render-start-Component') {
    
  1710.                 // Fake a long running render
    
  1711.                 startTime += 20000;
    
  1712.               }
    
  1713. 
    
  1714.               testMarks.push({
    
  1715.                 pid: ++pid,
    
  1716.                 tid: ++tid,
    
  1717.                 ts: ++startTime,
    
  1718.                 args: {data: {}},
    
  1719.                 cat: 'blink.user_timing',
    
  1720.                 name: markName,
    
  1721.                 ph: 'R',
    
  1722.               });
    
  1723.             });
    
  1724. 
    
  1725.             const data = await preprocessData([
    
  1726.               cpuProfilerSample,
    
  1727.               ...createBoilerplateEntries(),
    
  1728.               ...testMarks,
    
  1729.             ]);
    
  1730. 
    
  1731.             data.schedulingEvents.forEach(event => {
    
  1732.               expect(event.warning).toBeNull();
    
  1733.             });
    
  1734.           });
    
  1735.         });
    
  1736. 
    
  1737.         describe('errors thrown while rendering', () => {
    
  1738.           // @reactVersion >= 18.0
    
  1739.           it('shoult parse Errors thrown during render', async () => {
    
  1740.             jest.spyOn(console, 'error');
    
  1741. 
    
  1742.             class ErrorBoundary extends React.Component {
    
  1743.               state = {error: null};
    
  1744.               componentDidCatch(error) {
    
  1745.                 this.setState({error});
    
  1746.               }
    
  1747.               render() {
    
  1748.                 if (this.state.error) {
    
  1749.                   return null;
    
  1750.                 }
    
  1751.                 return this.props.children;
    
  1752.               }
    
  1753.             }
    
  1754. 
    
  1755.             function ExampleThatThrows() {
    
  1756.               throw Error('Expected error');
    
  1757.             }
    
  1758. 
    
  1759.             const testMarks = [creactCpuProfilerSample()];
    
  1760. 
    
  1761.             // Mount and commit the app
    
  1762.             const root = ReactDOMClient.createRoot(
    
  1763.               document.createElement('div'),
    
  1764.             );
    
  1765.             utils.act(() =>
    
  1766.               root.render(
    
  1767.                 <ErrorBoundary>
    
  1768.                   <ExampleThatThrows />
    
  1769.                 </ErrorBoundary>,
    
  1770.               ),
    
  1771.             );
    
  1772. 
    
  1773.             testMarks.push(...createUserTimingData(clearedMarks));
    
  1774. 
    
  1775.             const data = await preprocessData(testMarks);
    
  1776.             expect(data.thrownErrors).toHaveLength(2);
    
  1777.             expect(data.thrownErrors[0].message).toMatchInlineSnapshot(
    
  1778.               '"Expected error"',
    
  1779.             );
    
  1780.           });
    
  1781.         });
    
  1782. 
    
  1783.         describe('suspend during an update', () => {
    
  1784.           // This also tests an edge case where a component suspends while profiling
    
  1785.           // before the first commit is logged (so the lane-to-labels map will not yet exist).
    
  1786.           // @reactVersion >= 18.2
    
  1787.           it('should warn about suspending during an update', async () => {
    
  1788.             let promise = null;
    
  1789.             let resolvedValue = null;
    
  1790.             function readValue(value) {
    
  1791.               if (resolvedValue !== null) {
    
  1792.                 return resolvedValue;
    
  1793.               } else if (promise === null) {
    
  1794.                 promise = Promise.resolve(true).then(() => {
    
  1795.                   resolvedValue = value;
    
  1796.                 });
    
  1797.               }
    
  1798.               throw promise;
    
  1799.             }
    
  1800. 
    
  1801.             function Component({shouldSuspend}) {
    
  1802.               Scheduler.log(`Component ${shouldSuspend}`);
    
  1803.               if (shouldSuspend) {
    
  1804.                 readValue(123);
    
  1805.               }
    
  1806.               return null;
    
  1807.             }
    
  1808. 
    
  1809.             // Mount and commit the app
    
  1810.             const root = ReactDOMClient.createRoot(
    
  1811.               document.createElement('div'),
    
  1812.             );
    
  1813.             utils.act(() =>
    
  1814.               root.render(
    
  1815.                 <React.Suspense fallback="Loading...">
    
  1816.                   <Component shouldSuspend={false} />
    
  1817.                 </React.Suspense>,
    
  1818.               ),
    
  1819.             );
    
  1820. 
    
  1821.             const testMarks = [creactCpuProfilerSample()];
    
  1822. 
    
  1823.             // Start profiling and suspend during a render.
    
  1824.             utils.act(() =>
    
  1825.               root.render(
    
  1826.                 <React.Suspense fallback="Loading...">
    
  1827.                   <Component shouldSuspend={true} />
    
  1828.                 </React.Suspense>,
    
  1829.               ),
    
  1830.             );
    
  1831. 
    
  1832.             testMarks.push(...createUserTimingData(clearedMarks));
    
  1833. 
    
  1834.             let data;
    
  1835.             await utils.actAsync(async () => {
    
  1836.               data = await preprocessData(testMarks);
    
  1837.             });
    
  1838.             expect(data.suspenseEvents).toHaveLength(1);
    
  1839.             expect(data.suspenseEvents[0].warning).toMatchInlineSnapshot(
    
  1840.               `"A component suspended during an update which caused a fallback to be shown. Consider using the Transition API to avoid hiding components after they've been mounted."`,
    
  1841.             );
    
  1842.           });
    
  1843. 
    
  1844.           // @reactVersion >= 18.2
    
  1845.           it('should not warn about suspending during an transition', async () => {
    
  1846.             let promise = null;
    
  1847.             let resolvedValue = null;
    
  1848.             function readValue(value) {
    
  1849.               if (resolvedValue !== null) {
    
  1850.                 return resolvedValue;
    
  1851.               } else if (promise === null) {
    
  1852.                 promise = Promise.resolve(true).then(() => {
    
  1853.                   resolvedValue = value;
    
  1854.                 });
    
  1855.               }
    
  1856.               throw promise;
    
  1857.             }
    
  1858. 
    
  1859.             function Component({shouldSuspend}) {
    
  1860.               Scheduler.log(`Component ${shouldSuspend}`);
    
  1861.               if (shouldSuspend) {
    
  1862.                 readValue(123);
    
  1863.               }
    
  1864.               return null;
    
  1865.             }
    
  1866. 
    
  1867.             // Mount and commit the app
    
  1868.             const root = ReactDOMClient.createRoot(
    
  1869.               document.createElement('div'),
    
  1870.             );
    
  1871.             utils.act(() =>
    
  1872.               root.render(
    
  1873.                 <React.Suspense fallback="Loading...">
    
  1874.                   <Component shouldSuspend={false} />
    
  1875.                 </React.Suspense>,
    
  1876.               ),
    
  1877.             );
    
  1878. 
    
  1879.             const testMarks = [creactCpuProfilerSample()];
    
  1880. 
    
  1881.             // Start profiling and suspend during a render.
    
  1882.             await utils.actAsync(async () =>
    
  1883.               React.startTransition(() =>
    
  1884.                 root.render(
    
  1885.                   <React.Suspense fallback="Loading...">
    
  1886.                     <Component shouldSuspend={true} />
    
  1887.                   </React.Suspense>,
    
  1888.                 ),
    
  1889.               ),
    
  1890.             );
    
  1891. 
    
  1892.             testMarks.push(...createUserTimingData(clearedMarks));
    
  1893. 
    
  1894.             let data;
    
  1895.             await utils.actAsync(async () => {
    
  1896.               data = await preprocessData(testMarks);
    
  1897.             });
    
  1898.             expect(data.suspenseEvents).toHaveLength(1);
    
  1899.             expect(data.suspenseEvents[0].warning).toBe(null);
    
  1900.           });
    
  1901.         });
    
  1902.       });
    
  1903. 
    
  1904.       // TODO: Add test for snapshot base64 parsing
    
  1905. 
    
  1906.       // TODO: Add test for flamechart parsing
    
  1907.     });
    
  1908.   });
    
  1909. 
    
  1910.   // Note the in-memory tests vary slightly (e.g. timestamp values, lane numbers) from the above tests.
    
  1911.   // That's okay; the important thing is the lane-to-label matches the subsequent events/measures.
    
  1912.   describe('DevTools hook (in memory)', () => {
    
  1913.     let store;
    
  1914. 
    
  1915.     beforeEach(() => {
    
  1916.       utils = require('./utils');
    
  1917.       utils.beforeEachProfiling();
    
  1918. 
    
  1919.       React = require('react');
    
  1920.       ReactDOM = require('react-dom');
    
  1921.       ReactDOMClient = require('react-dom/client');
    
  1922.       Scheduler = require('scheduler');
    
  1923. 
    
  1924.       store = global.store;
    
  1925. 
    
  1926.       // Start profiling so that data will actually be recorded.
    
  1927.       utils.act(() => store.profilerStore.startProfiling());
    
  1928. 
    
  1929.       global.IS_REACT_ACT_ENVIRONMENT = true;
    
  1930.     });
    
  1931. 
    
  1932.     it('should process a sample legacy render sequence', async () => {
    
  1933.       utils.legacyRender(<div />, document.createElement('div'));
    
  1934.       utils.act(() => store.profilerStore.stopProfiling());
    
  1935. 
    
  1936.       const data = store.profilerStore.profilingData?.timelineData;
    
  1937.       expect(data).toHaveLength(1);
    
  1938.       const timelineData = data[0];
    
  1939.       expect(timelineData).toMatchInlineSnapshot(`
    
  1940.         {
    
  1941.           "batchUIDToMeasuresMap": Map {
    
  1942.             1 => [
    
  1943.               {
    
  1944.                 "batchUID": 1,
    
  1945.                 "depth": 0,
    
  1946.                 "duration": 0,
    
  1947.                 "lanes": "0b0000000000000000000000000000010",
    
  1948.                 "timestamp": 10,
    
  1949.                 "type": "render-idle",
    
  1950.               },
    
  1951.               {
    
  1952.                 "batchUID": 1,
    
  1953.                 "depth": 0,
    
  1954.                 "duration": 0,
    
  1955.                 "lanes": "0b0000000000000000000000000000010",
    
  1956.                 "timestamp": 10,
    
  1957.                 "type": "render",
    
  1958.               },
    
  1959.               {
    
  1960.                 "batchUID": 1,
    
  1961.                 "depth": 0,
    
  1962.                 "duration": 0,
    
  1963.                 "lanes": "0b0000000000000000000000000000010",
    
  1964.                 "timestamp": 10,
    
  1965.                 "type": "commit",
    
  1966.               },
    
  1967.               {
    
  1968.                 "batchUID": 1,
    
  1969.                 "depth": 1,
    
  1970.                 "duration": 0,
    
  1971.                 "lanes": "0b0000000000000000000000000000010",
    
  1972.                 "timestamp": 10,
    
  1973.                 "type": "layout-effects",
    
  1974.               },
    
  1975.             ],
    
  1976.           },
    
  1977.           "componentMeasures": [],
    
  1978.           "duration": 20,
    
  1979.           "flamechart": [],
    
  1980.           "internalModuleSourceToRanges": Map {},
    
  1981.           "laneToLabelMap": Map {
    
  1982.             1 => "SyncHydrationLane",
    
  1983.             2 => "Sync",
    
  1984.             4 => "InputContinuousHydration",
    
  1985.             8 => "InputContinuous",
    
  1986.             16 => "DefaultHydration",
    
  1987.             32 => "Default",
    
  1988.             64 => "TransitionHydration",
    
  1989.             128 => "Transition",
    
  1990.             256 => "Transition",
    
  1991.             512 => "Transition",
    
  1992.             1024 => "Transition",
    
  1993.             2048 => "Transition",
    
  1994.             4096 => "Transition",
    
  1995.             8192 => "Transition",
    
  1996.             16384 => "Transition",
    
  1997.             32768 => "Transition",
    
  1998.             65536 => "Transition",
    
  1999.             131072 => "Transition",
    
  2000.             262144 => "Transition",
    
  2001.             524288 => "Transition",
    
  2002.             1048576 => "Transition",
    
  2003.             2097152 => "Transition",
    
  2004.             4194304 => "Retry",
    
  2005.             8388608 => "Retry",
    
  2006.             16777216 => "Retry",
    
  2007.             33554432 => "Retry",
    
  2008.             67108864 => "SelectiveHydration",
    
  2009.             134217728 => "IdleHydration",
    
  2010.             268435456 => "Idle",
    
  2011.             536870912 => "Offscreen",
    
  2012.             1073741824 => "Deferred",
    
  2013.           },
    
  2014.           "laneToReactMeasureMap": Map {
    
  2015.             1 => [],
    
  2016.             2 => [
    
  2017.               {
    
  2018.                 "batchUID": 1,
    
  2019.                 "depth": 0,
    
  2020.                 "duration": 0,
    
  2021.                 "lanes": "0b0000000000000000000000000000010",
    
  2022.                 "timestamp": 10,
    
  2023.                 "type": "render-idle",
    
  2024.               },
    
  2025.               {
    
  2026.                 "batchUID": 1,
    
  2027.                 "depth": 0,
    
  2028.                 "duration": 0,
    
  2029.                 "lanes": "0b0000000000000000000000000000010",
    
  2030.                 "timestamp": 10,
    
  2031.                 "type": "render",
    
  2032.               },
    
  2033.               {
    
  2034.                 "batchUID": 1,
    
  2035.                 "depth": 0,
    
  2036.                 "duration": 0,
    
  2037.                 "lanes": "0b0000000000000000000000000000010",
    
  2038.                 "timestamp": 10,
    
  2039.                 "type": "commit",
    
  2040.               },
    
  2041.               {
    
  2042.                 "batchUID": 1,
    
  2043.                 "depth": 1,
    
  2044.                 "duration": 0,
    
  2045.                 "lanes": "0b0000000000000000000000000000010",
    
  2046.                 "timestamp": 10,
    
  2047.                 "type": "layout-effects",
    
  2048.               },
    
  2049.             ],
    
  2050.             4 => [],
    
  2051.             8 => [],
    
  2052.             16 => [],
    
  2053.             32 => [],
    
  2054.             64 => [],
    
  2055.             128 => [],
    
  2056.             256 => [],
    
  2057.             512 => [],
    
  2058.             1024 => [],
    
  2059.             2048 => [],
    
  2060.             4096 => [],
    
  2061.             8192 => [],
    
  2062.             16384 => [],
    
  2063.             32768 => [],
    
  2064.             65536 => [],
    
  2065.             131072 => [],
    
  2066.             262144 => [],
    
  2067.             524288 => [],
    
  2068.             1048576 => [],
    
  2069.             2097152 => [],
    
  2070.             4194304 => [],
    
  2071.             8388608 => [],
    
  2072.             16777216 => [],
    
  2073.             33554432 => [],
    
  2074.             67108864 => [],
    
  2075.             134217728 => [],
    
  2076.             268435456 => [],
    
  2077.             536870912 => [],
    
  2078.             1073741824 => [],
    
  2079.           },
    
  2080.           "nativeEvents": [],
    
  2081.           "networkMeasures": [],
    
  2082.           "otherUserTimingMarks": [],
    
  2083.           "reactVersion": "<filtered-version>",
    
  2084.           "schedulingEvents": [
    
  2085.             {
    
  2086.               "lanes": "0b0000000000000000000000000000010",
    
  2087.               "timestamp": 10,
    
  2088.               "type": "schedule-render",
    
  2089.               "warning": null,
    
  2090.             },
    
  2091.           ],
    
  2092.           "snapshotHeight": 0,
    
  2093.           "snapshots": [],
    
  2094.           "startTime": -10,
    
  2095.           "suspenseEvents": [],
    
  2096.           "thrownErrors": [],
    
  2097.         }
    
  2098.       `);
    
  2099.     });
    
  2100. 
    
  2101.     it('should process a sample createRoot render sequence', async () => {
    
  2102.       function App() {
    
  2103.         const [didMount, setDidMount] = React.useState(false);
    
  2104.         React.useEffect(() => {
    
  2105.           if (!didMount) {
    
  2106.             setDidMount(true);
    
  2107.           }
    
  2108.         });
    
  2109.         return true;
    
  2110.       }
    
  2111. 
    
  2112.       const root = ReactDOMClient.createRoot(document.createElement('div'));
    
  2113.       utils.act(() => root.render(<App />));
    
  2114.       utils.act(() => store.profilerStore.stopProfiling());
    
  2115. 
    
  2116.       const data = store.profilerStore.profilingData?.timelineData;
    
  2117.       expect(data).toHaveLength(1);
    
  2118.       const timelineData = data[0];
    
  2119. 
    
  2120.       // normalize the location for component stack source
    
  2121.       // for snapshot testing
    
  2122.       timelineData.schedulingEvents.forEach(event => {
    
  2123.         if (event.componentStack) {
    
  2124.           event.componentStack = normalizeCodeLocInfo(event.componentStack);
    
  2125.         }
    
  2126.       });
    
  2127. 
    
  2128.       expect(timelineData).toMatchInlineSnapshot(`
    
  2129.         {
    
  2130.           "batchUIDToMeasuresMap": Map {
    
  2131.             1 => [
    
  2132.               {
    
  2133.                 "batchUID": 1,
    
  2134.                 "depth": 0,
    
  2135.                 "duration": 0,
    
  2136.                 "lanes": "0b0000000000000000000000000100000",
    
  2137.                 "timestamp": 10,
    
  2138.                 "type": "render-idle",
    
  2139.               },
    
  2140.               {
    
  2141.                 "batchUID": 1,
    
  2142.                 "depth": 0,
    
  2143.                 "duration": 0,
    
  2144.                 "lanes": "0b0000000000000000000000000100000",
    
  2145.                 "timestamp": 10,
    
  2146.                 "type": "render",
    
  2147.               },
    
  2148.               {
    
  2149.                 "batchUID": 1,
    
  2150.                 "depth": 0,
    
  2151.                 "duration": 0,
    
  2152.                 "lanes": "0b0000000000000000000000000100000",
    
  2153.                 "timestamp": 10,
    
  2154.                 "type": "commit",
    
  2155.               },
    
  2156.               {
    
  2157.                 "batchUID": 1,
    
  2158.                 "depth": 1,
    
  2159.                 "duration": 0,
    
  2160.                 "lanes": "0b0000000000000000000000000100000",
    
  2161.                 "timestamp": 10,
    
  2162.                 "type": "layout-effects",
    
  2163.               },
    
  2164.               {
    
  2165.                 "batchUID": 1,
    
  2166.                 "depth": 0,
    
  2167.                 "duration": 0,
    
  2168.                 "lanes": "0b0000000000000000000000000100000",
    
  2169.                 "timestamp": 10,
    
  2170.                 "type": "passive-effects",
    
  2171.               },
    
  2172.             ],
    
  2173.             2 => [
    
  2174.               {
    
  2175.                 "batchUID": 2,
    
  2176.                 "depth": 0,
    
  2177.                 "duration": 0,
    
  2178.                 "lanes": "0b0000000000000000000000000100000",
    
  2179.                 "timestamp": 10,
    
  2180.                 "type": "render-idle",
    
  2181.               },
    
  2182.               {
    
  2183.                 "batchUID": 2,
    
  2184.                 "depth": 0,
    
  2185.                 "duration": 0,
    
  2186.                 "lanes": "0b0000000000000000000000000100000",
    
  2187.                 "timestamp": 10,
    
  2188.                 "type": "render",
    
  2189.               },
    
  2190.               {
    
  2191.                 "batchUID": 2,
    
  2192.                 "depth": 0,
    
  2193.                 "duration": 0,
    
  2194.                 "lanes": "0b0000000000000000000000000100000",
    
  2195.                 "timestamp": 10,
    
  2196.                 "type": "commit",
    
  2197.               },
    
  2198.               {
    
  2199.                 "batchUID": 2,
    
  2200.                 "depth": 1,
    
  2201.                 "duration": 0,
    
  2202.                 "lanes": "0b0000000000000000000000000100000",
    
  2203.                 "timestamp": 10,
    
  2204.                 "type": "layout-effects",
    
  2205.               },
    
  2206.               {
    
  2207.                 "batchUID": 2,
    
  2208.                 "depth": 0,
    
  2209.                 "duration": 0,
    
  2210.                 "lanes": "0b0000000000000000000000000100000",
    
  2211.                 "timestamp": 10,
    
  2212.                 "type": "passive-effects",
    
  2213.               },
    
  2214.             ],
    
  2215.           },
    
  2216.           "componentMeasures": [
    
  2217.             {
    
  2218.               "componentName": "App",
    
  2219.               "duration": 0,
    
  2220.               "timestamp": 10,
    
  2221.               "type": "render",
    
  2222.               "warning": null,
    
  2223.             },
    
  2224.             {
    
  2225.               "componentName": "App",
    
  2226.               "duration": 0,
    
  2227.               "timestamp": 10,
    
  2228.               "type": "passive-effect-mount",
    
  2229.               "warning": null,
    
  2230.             },
    
  2231.             {
    
  2232.               "componentName": "App",
    
  2233.               "duration": 0,
    
  2234.               "timestamp": 10,
    
  2235.               "type": "render",
    
  2236.               "warning": null,
    
  2237.             },
    
  2238.             {
    
  2239.               "componentName": "App",
    
  2240.               "duration": 0,
    
  2241.               "timestamp": 10,
    
  2242.               "type": "passive-effect-mount",
    
  2243.               "warning": null,
    
  2244.             },
    
  2245.           ],
    
  2246.           "duration": 20,
    
  2247.           "flamechart": [],
    
  2248.           "internalModuleSourceToRanges": Map {},
    
  2249.           "laneToLabelMap": Map {
    
  2250.             1 => "SyncHydrationLane",
    
  2251.             2 => "Sync",
    
  2252.             4 => "InputContinuousHydration",
    
  2253.             8 => "InputContinuous",
    
  2254.             16 => "DefaultHydration",
    
  2255.             32 => "Default",
    
  2256.             64 => "TransitionHydration",
    
  2257.             128 => "Transition",
    
  2258.             256 => "Transition",
    
  2259.             512 => "Transition",
    
  2260.             1024 => "Transition",
    
  2261.             2048 => "Transition",
    
  2262.             4096 => "Transition",
    
  2263.             8192 => "Transition",
    
  2264.             16384 => "Transition",
    
  2265.             32768 => "Transition",
    
  2266.             65536 => "Transition",
    
  2267.             131072 => "Transition",
    
  2268.             262144 => "Transition",
    
  2269.             524288 => "Transition",
    
  2270.             1048576 => "Transition",
    
  2271.             2097152 => "Transition",
    
  2272.             4194304 => "Retry",
    
  2273.             8388608 => "Retry",
    
  2274.             16777216 => "Retry",
    
  2275.             33554432 => "Retry",
    
  2276.             67108864 => "SelectiveHydration",
    
  2277.             134217728 => "IdleHydration",
    
  2278.             268435456 => "Idle",
    
  2279.             536870912 => "Offscreen",
    
  2280.             1073741824 => "Deferred",
    
  2281.           },
    
  2282.           "laneToReactMeasureMap": Map {
    
  2283.             1 => [],
    
  2284.             2 => [],
    
  2285.             4 => [],
    
  2286.             8 => [],
    
  2287.             16 => [],
    
  2288.             32 => [
    
  2289.               {
    
  2290.                 "batchUID": 1,
    
  2291.                 "depth": 0,
    
  2292.                 "duration": 0,
    
  2293.                 "lanes": "0b0000000000000000000000000100000",
    
  2294.                 "timestamp": 10,
    
  2295.                 "type": "render-idle",
    
  2296.               },
    
  2297.               {
    
  2298.                 "batchUID": 1,
    
  2299.                 "depth": 0,
    
  2300.                 "duration": 0,
    
  2301.                 "lanes": "0b0000000000000000000000000100000",
    
  2302.                 "timestamp": 10,
    
  2303.                 "type": "render",
    
  2304.               },
    
  2305.               {
    
  2306.                 "batchUID": 1,
    
  2307.                 "depth": 0,
    
  2308.                 "duration": 0,
    
  2309.                 "lanes": "0b0000000000000000000000000100000",
    
  2310.                 "timestamp": 10,
    
  2311.                 "type": "commit",
    
  2312.               },
    
  2313.               {
    
  2314.                 "batchUID": 1,
    
  2315.                 "depth": 1,
    
  2316.                 "duration": 0,
    
  2317.                 "lanes": "0b0000000000000000000000000100000",
    
  2318.                 "timestamp": 10,
    
  2319.                 "type": "layout-effects",
    
  2320.               },
    
  2321.               {
    
  2322.                 "batchUID": 1,
    
  2323.                 "depth": 0,
    
  2324.                 "duration": 0,
    
  2325.                 "lanes": "0b0000000000000000000000000100000",
    
  2326.                 "timestamp": 10,
    
  2327.                 "type": "passive-effects",
    
  2328.               },
    
  2329.               {
    
  2330.                 "batchUID": 2,
    
  2331.                 "depth": 0,
    
  2332.                 "duration": 0,
    
  2333.                 "lanes": "0b0000000000000000000000000100000",
    
  2334.                 "timestamp": 10,
    
  2335.                 "type": "render-idle",
    
  2336.               },
    
  2337.               {
    
  2338.                 "batchUID": 2,
    
  2339.                 "depth": 0,
    
  2340.                 "duration": 0,
    
  2341.                 "lanes": "0b0000000000000000000000000100000",
    
  2342.                 "timestamp": 10,
    
  2343.                 "type": "render",
    
  2344.               },
    
  2345.               {
    
  2346.                 "batchUID": 2,
    
  2347.                 "depth": 0,
    
  2348.                 "duration": 0,
    
  2349.                 "lanes": "0b0000000000000000000000000100000",
    
  2350.                 "timestamp": 10,
    
  2351.                 "type": "commit",
    
  2352.               },
    
  2353.               {
    
  2354.                 "batchUID": 2,
    
  2355.                 "depth": 1,
    
  2356.                 "duration": 0,
    
  2357.                 "lanes": "0b0000000000000000000000000100000",
    
  2358.                 "timestamp": 10,
    
  2359.                 "type": "layout-effects",
    
  2360.               },
    
  2361.               {
    
  2362.                 "batchUID": 2,
    
  2363.                 "depth": 0,
    
  2364.                 "duration": 0,
    
  2365.                 "lanes": "0b0000000000000000000000000100000",
    
  2366.                 "timestamp": 10,
    
  2367.                 "type": "passive-effects",
    
  2368.               },
    
  2369.             ],
    
  2370.             64 => [],
    
  2371.             128 => [],
    
  2372.             256 => [],
    
  2373.             512 => [],
    
  2374.             1024 => [],
    
  2375.             2048 => [],
    
  2376.             4096 => [],
    
  2377.             8192 => [],
    
  2378.             16384 => [],
    
  2379.             32768 => [],
    
  2380.             65536 => [],
    
  2381.             131072 => [],
    
  2382.             262144 => [],
    
  2383.             524288 => [],
    
  2384.             1048576 => [],
    
  2385.             2097152 => [],
    
  2386.             4194304 => [],
    
  2387.             8388608 => [],
    
  2388.             16777216 => [],
    
  2389.             33554432 => [],
    
  2390.             67108864 => [],
    
  2391.             134217728 => [],
    
  2392.             268435456 => [],
    
  2393.             536870912 => [],
    
  2394.             1073741824 => [],
    
  2395.           },
    
  2396.           "nativeEvents": [],
    
  2397.           "networkMeasures": [],
    
  2398.           "otherUserTimingMarks": [],
    
  2399.           "reactVersion": "<filtered-version>",
    
  2400.           "schedulingEvents": [
    
  2401.             {
    
  2402.               "lanes": "0b0000000000000000000000000100000",
    
  2403.               "timestamp": 10,
    
  2404.               "type": "schedule-render",
    
  2405.               "warning": null,
    
  2406.             },
    
  2407.             {
    
  2408.               "componentName": "App",
    
  2409.               "componentStack": "
    
  2410.             in App (at **)",
    
  2411.               "lanes": "0b0000000000000000000000000100000",
    
  2412.               "timestamp": 10,
    
  2413.               "type": "schedule-state-update",
    
  2414.               "warning": null,
    
  2415.             },
    
  2416.           ],
    
  2417.           "snapshotHeight": 0,
    
  2418.           "snapshots": [],
    
  2419.           "startTime": -10,
    
  2420.           "suspenseEvents": [],
    
  2421.           "thrownErrors": [],
    
  2422.         }
    
  2423.       `);
    
  2424.     });
    
  2425.   });
    
  2426. });