Preprocessdata Test
Preprocessdata Test
'use strict';
function createUserTimingPolyfill() {
featureDetectionMarkName = null;
clearedMarks = [];
marks = [];
clearedMarks.push(markName);
marks = marks.filter(mark => mark !== markName);
},
mark(markName, markOptions) {
markName = filterMarkData(markName);
marks.push(markName);
if (markOptions != null) {
// This is triggers the feature detection.
markOptions.startTime++;
}
},
};
}
function clearPendingMarks() {
clearedMarks.splice(0);
}
beforeEach(() => {
utils = require('./utils');
utils.beforeEachProfiling();
React = require('react');
ReactDOM = require('react-dom');
ReactDOMClient = require('react-dom/client');
Scheduler = require('scheduler');
setPerformanceMock =
require('react-devtools-shared/src/backend/profilingHooks').setPerformanceMock_ONLY
_FOR_TESTING;
setPerformanceMock(createUserTimingPolyfill());
global.IS_REACT_ACT_ENVIRONMENT = true;
});
afterEach(() => {
// Verify all logged marks also get cleared.
expect(marks).toHaveLength(0);
setPerformanceMock(null);
});
describe('getLanesFromTransportDecimalBitmask', () => {
let getLanesFromTransportDecimalBitmask;
beforeEach(() => {
getLanesFromTransportDecimalBitmask =
require('react-devtools-timeline/src/import-worker/preprocessData').getLanesFromTra
nsportDecimalBitmask;
});
// Sanity check; this test may need to be updated when the no. of fiber
lanes are changed.
expect(REACT_TOTAL_NUM_LANES).toBe(31);
expect(
getLanesFromTransportDecimalBitmask(
'4294967297', // 2^32 + 1
),
).toEqual([0]);
});
});
describe('preprocessData', () => {
let preprocessData;
beforeEach(() => {
preprocessData =
require('react-devtools-timeline/src/import-worker/preprocessData').default;
});
function createUserTimingEntry(data) {
return {
pid: ++pid,
tid: ++tid,
ts: ++startTime,
...data,
};
}
function createProfilerVersionEntry() {
const SCHEDULING_PROFILER_VERSION =
require('react-devtools-timeline/src/constants').SCHEDULING_PROFILER_VERSION;
return createUserTimingEntry({
cat: 'blink.user_timing',
name: '--profiler-version-' + SCHEDULING_PROFILER_VERSION,
});
}
function createReactVersionEntry() {
return createUserTimingEntry({
cat: 'blink.user_timing',
name: '--react-version-<filtered-version>',
});
}
function createLaneLabelsEntry() {
return createUserTimingEntry({
cat: 'blink.user_timing',
name: '--react-lane-labels-
Sync,InputContinuousHydration,InputContinuous,DefaultHydration,Default,TransitionHy
dration,Transition,Transition,Transition,Transition,Transition,Transition,Transitio
n,Transition,Transition,Transition,Transition,Transition,Transition,Transition,Tran
sition,Transition,Retry,Retry,Retry,Retry,Retry,SelectiveHydration,IdleHydration,Id
le,Offscreen',
});
}
function creactCpuProfilerSample() {
return createUserTimingEntry({
args: {data: {startTime: ++startTime}},
cat: 'disabled-by-default-v8.cpu_profiler',
id: '0x1',
name: 'Profile',
ph: 'P',
});
}
function createBoilerplateEntries() {
return [
createProfilerVersionEntry(),
createReactVersionEntry(),
createLaneLabelsEntry(),
];
}
function createUserTimingData(sampleMarks) {
const cpuProfilerSample = creactCpuProfilerSample();
sampleMarks.forEach(markName => {
userTimingData.push({
pid: ++pid,
tid: ++tid,
ts: ++startTime,
args: {data: {}},
cat: 'blink.user_timing',
name: markName,
ph: 'R',
});
});
return userTimingData;
}
beforeEach(() => {
tid = 0;
pid = 0;
startTime = 0;
});
await expect(
async () => await preprocessData([cpuProfilerSample]),
).rejects.toThrow(
'Please provide profiling data from an React application',
);
});
function Component() {
const value = readValue(123);
return value;
}
testMarks.push(...createUserTimingData(clearedMarks));
let data;
await utils.actAsync(async () => {
data = await preprocessData(testMarks);
});
expect(data.suspenseEvents).toHaveLength(1);
expect(data.suspenseEvents[0].promiseName).toBe('Testing displayName');
});
describe('warnings', () => {
describe('long event handlers', () => {
// @reactVersion >= 18.0
it('should not warn when React scedules a (sync) update inside of a short
event handler', async () => {
function App() {
return null;
}
const testMarks = [
creactCpuProfilerSample(),
...createBoilerplateEntries(),
createNativeEventEntry('click', 5),
];
clearPendingMarks();
utils.legacyRender(<App />, document.createElement('div'));
testMarks.push(...createUserTimingData(clearedMarks));
const testMarks = [
creactCpuProfilerSample(),
...createBoilerplateEntries(),
createNativeEventEntry('click', 25000),
];
startTime += 2000;
clearPendingMarks();
testMarks.push(...createUserTimingData(clearedMarks));
const testMarks = [
creactCpuProfilerSample(),
...createBoilerplateEntries(),
createNativeEventEntry('click', 25000),
];
clearPendingMarks();
clearedMarks.forEach(markName => {
if (markName === '--render-stop') {
// Fake a long running render
startTime += 20000;
}
testMarks.push({
pid: ++pid,
tid: ++tid,
ts: ++startTime,
args: {data: {}},
cat: 'blink.user_timing',
name: markName,
ph: 'R',
});
});
const testMarks = [
creactCpuProfilerSample(),
...createBoilerplateEntries(),
];
await waitFor(['A:1']);
testMarks.push(...createUserTimingData(clearedMarks));
clearPendingMarks();
// Advance the clock some more to make the pending React update seem
long.
startTime += 20000;
assertLog(['A:2', 'B:2']);
testMarks.push(...createUserTimingData(clearedMarks));
testMarks.push({
pid: ++pid,
tid: ++tid,
ts: ++startTime,
args: {data: {}},
cat: 'blink.user_timing',
name: markName,
ph: 'R',
});
});
testMarks.push({
pid: ++pid,
tid: ++tid,
ts: ++startTime,
args: {data: {}},
cat: 'blink.user_timing',
name: markName,
ph: 'R',
});
});
React.useLayoutEffect(() => {
startTransition(() => {
setValue(1);
});
}, []);
return value;
}
assertLog([
'Component rendered with value 0',
'Component rendered with value 0',
'Component rendered with value 1',
'Long render',
]);
testMarks.push({
pid: ++pid,
tid: ++tid,
ts: ++startTime,
args: {data: {}},
cat: 'blink.user_timing',
name: markName,
ph: 'R',
});
});
data.schedulingEvents.forEach(event => {
expect(event.warning).toBeNull();
});
});
React.useLayoutEffect(() => {
setValue(1);
}, []);
assertLog([
'Component rendered with value 0 and deferredValue 0',
'Component rendered with value 1 and deferredValue 0',
'Component rendered with value 1 and deferredValue 1',
'Long render',
]);
testMarks.push({
pid: ++pid,
tid: ++tid,
ts: ++startTime,
args: {data: {}},
cat: 'blink.user_timing',
name: markName,
ph: 'R',
});
});
data.schedulingEvents.forEach(event => {
expect(event.warning).toBeNull();
});
});
});
function ExampleThatThrows() {
throw Error('Expected error');
}
testMarks.push(...createUserTimingData(clearedMarks));
function Component({shouldSuspend}) {
Scheduler.log(`Component ${shouldSuspend}`);
if (shouldSuspend) {
readValue(123);
}
return null;
}
testMarks.push(...createUserTimingData(clearedMarks));
let data;
await utils.actAsync(async () => {
data = await preprocessData(testMarks);
});
expect(data.suspenseEvents).toHaveLength(1);
expect(data.suspenseEvents[0].warning).toMatchInlineSnapshot(
`"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."`,
);
});
function Component({shouldSuspend}) {
Scheduler.log(`Component ${shouldSuspend}`);
if (shouldSuspend) {
readValue(123);
}
return null;
}
testMarks.push(...createUserTimingData(clearedMarks));
let data;
await utils.actAsync(async () => {
data = await preprocessData(testMarks);
});
expect(data.suspenseEvents).toHaveLength(1);
expect(data.suspenseEvents[0].warning).toBe(null);
});
});
});
// Note the in-memory tests vary slightly (e.g. timestamp values, lane numbers)
from the above tests.
// That's okay; the important thing is the lane-to-label matches the subsequent
events/measures.
describe('DevTools hook (in memory)', () => {
let store;
beforeEach(() => {
utils = require('./utils');
utils.beforeEachProfiling();
React = require('react');
ReactDOM = require('react-dom');
ReactDOMClient = require('react-dom/client');
Scheduler = require('scheduler');
store = global.store;
global.IS_REACT_ACT_ENVIRONMENT = true;
});
expect(timelineData).toMatchInlineSnapshot(`
{
"batchUIDToMeasuresMap": Map {
1 => [
{
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "render-idle",
},
{
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "render",
},
{
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "commit",
},
{
"batchUID": 1,
"depth": 1,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "layout-effects",
},
{
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "passive-effects",
},
],
2 => [
{
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "render-idle",
},
{
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "render",
},
{
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "commit",
},
{
"batchUID": 2,
"depth": 1,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "layout-effects",
},
{
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "passive-effects",
},
],
},
"componentMeasures": [
{
"componentName": "App",
"duration": 0,
"timestamp": 10,
"type": "render",
"warning": null,
},
{
"componentName": "App",
"duration": 0,
"timestamp": 10,
"type": "passive-effect-mount",
"warning": null,
},
{
"componentName": "App",
"duration": 0,
"timestamp": 10,
"type": "render",
"warning": null,
},
{
"componentName": "App",
"duration": 0,
"timestamp": 10,
"type": "passive-effect-mount",
"warning": null,
},
],
"duration": 20,
"flamechart": [],
"internalModuleSourceToRanges": Map {},
"laneToLabelMap": Map {
1 => "SyncHydrationLane",
2 => "Sync",
4 => "InputContinuousHydration",
8 => "InputContinuous",
16 => "DefaultHydration",
32 => "Default",
64 => "TransitionHydration",
128 => "Transition",
256 => "Transition",
512 => "Transition",
1024 => "Transition",
2048 => "Transition",
4096 => "Transition",
8192 => "Transition",
16384 => "Transition",
32768 => "Transition",
65536 => "Transition",
131072 => "Transition",
262144 => "Transition",
524288 => "Transition",
1048576 => "Transition",
2097152 => "Transition",
4194304 => "Retry",
8388608 => "Retry",
16777216 => "Retry",
33554432 => "Retry",
67108864 => "SelectiveHydration",
134217728 => "IdleHydration",
268435456 => "Idle",
536870912 => "Offscreen",
1073741824 => "Deferred",
},
"laneToReactMeasureMap": Map {
1 => [],
2 => [],
4 => [],
8 => [],
16 => [],
32 => [
{
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "render-idle",
},
{
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "render",
},
{
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "commit",
},
{
"batchUID": 1,
"depth": 1,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "layout-effects",
},
{
"batchUID": 1,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "passive-effects",
},
{
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "render-idle",
},
{
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "render",
},
{
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "commit",
},
{
"batchUID": 2,
"depth": 1,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "layout-effects",
},
{
"batchUID": 2,
"depth": 0,
"duration": 0,
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "passive-effects",
},
],
64 => [],
128 => [],
256 => [],
512 => [],
1024 => [],
2048 => [],
4096 => [],
8192 => [],
16384 => [],
32768 => [],
65536 => [],
131072 => [],
262144 => [],
524288 => [],
1048576 => [],
2097152 => [],
4194304 => [],
8388608 => [],
16777216 => [],
33554432 => [],
67108864 => [],
134217728 => [],
268435456 => [],
536870912 => [],
1073741824 => [],
},
"nativeEvents": [],
"networkMeasures": [],
"otherUserTimingMarks": [],
"reactVersion": "<filtered-version>",
"schedulingEvents": [
{
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "schedule-render",
"warning": null,
},
{
"componentName": "App",
"componentStack": "
in App (at **)",
"lanes": "0b0000000000000000000000000100000",
"timestamp": 10,
"type": "schedule-state-update",
"warning": null,
},
],
"snapshotHeight": 0,
"snapshots": [],
"startTime": -10,
"suspenseEvents": [],
"thrownErrors": [],
}
`);
});
});
});