UNPKG

chrome-devtools-frontend

Version:
105 lines (92 loc) 4.94 kB
// Copyright 2023 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import * as Trace from '../../../models/trace/trace.js'; import {describeWithEnvironment} from '../../../testing/EnvironmentHelpers.js'; import {TraceLoader} from '../../../testing/TraceLoader.js'; import * as PerfUI from '../../../ui/legacy/components/perf_ui/perf_ui.js'; import * as Timeline from '../timeline.js'; function initTrackAppender( flameChartData: PerfUI.FlameChart.FlameChartTimelineData, parsedTrace: Trace.Handlers.Types.ParsedTrace, entryData: Trace.Types.Events.Event[], entryTypeByLevel: Timeline.TimelineFlameChartDataProvider.EntryType[]): Timeline.LayoutShiftsTrackAppender.LayoutShiftsTrackAppender { const entityMapper = new Timeline.Utils.EntityMapper.EntityMapper(parsedTrace); const compatibilityTracksAppender = new Timeline.CompatibilityTracksAppender.CompatibilityTracksAppender( flameChartData, parsedTrace, entryData, entryTypeByLevel, entityMapper); return compatibilityTracksAppender.layoutShiftsTrackAppender(); } describeWithEnvironment('LayoutShiftsTrackAppender', function() { async function renderTrackAppender(context: Mocha.Context|Mocha.Suite, trace: string): Promise<{ entryTypeByLevel: Timeline.TimelineFlameChartDataProvider.EntryType[], flameChartData: PerfUI.FlameChart.FlameChartTimelineData, layoutShiftsTrackAppender: Timeline.LayoutShiftsTrackAppender.LayoutShiftsTrackAppender, entryData: Trace.Types.Events.Event[], parsedTrace: Readonly<Trace.Handlers.Types.ParsedTrace>, }> { const entryTypeByLevel: Timeline.TimelineFlameChartDataProvider.EntryType[] = []; const entryData: Trace.Types.Events.Event[] = []; const flameChartData = PerfUI.FlameChart.FlameChartTimelineData.createEmpty(); const {parsedTrace} = await TraceLoader.traceEngine(context, trace); const layoutShiftsTrackAppender = initTrackAppender(flameChartData, parsedTrace, entryData, entryTypeByLevel); layoutShiftsTrackAppender.appendTrackAtLevel(0); return { entryTypeByLevel, parsedTrace, flameChartData, layoutShiftsTrackAppender, entryData, }; } it('marks all levels used by the track with the TrackAppender type', async function() { const {entryTypeByLevel} = await renderTrackAppender(this, 'cls-single-frame.json.gz'); // Only one row of layout shifts. assert.lengthOf(entryTypeByLevel, 1); assert.deepEqual(entryTypeByLevel, [ Timeline.TimelineFlameChartDataProvider.EntryType.TRACK_APPENDER, ]); }); it('does not append anything if there are no layout shifts', async function() { // No layout shifts. const {entryTypeByLevel} = await renderTrackAppender(this, 'animation.json.gz'); assert.lengthOf(entryTypeByLevel, 0); }); it('creates a flamechart group', async function() { const {flameChartData} = await renderTrackAppender(this, 'cls-single-frame.json.gz'); assert.lengthOf(flameChartData.groups, 1); assert.strictEqual(flameChartData.groups[0].name, 'Layout shifts'); }); it('adds all layout shifts with the correct start times', async function() { const {flameChartData, parsedTrace, entryData} = await renderTrackAppender(this, 'cls-single-frame.json.gz'); const events = parsedTrace.LayoutShifts.clusters.flatMap(c => c.events); for (const event of events) { const markerIndex = entryData.indexOf(event); assert.exists(markerIndex); assert.strictEqual(flameChartData.entryStartTimes[markerIndex], Trace.Helpers.Timing.microToMilli(event.ts)); } }); it('does not define any title for a layout shift or a cluster', async () => { const {layoutShiftsTrackAppender, parsedTrace} = await renderTrackAppender(this, 'cls-no-nav.json.gz'); const cluster = parsedTrace.LayoutShifts.clusters.at(0); assert.isOk(cluster); const shift = cluster.events.at(0); assert.isOk(shift); assert.strictEqual(layoutShiftsTrackAppender.titleForEvent(cluster), ''); assert.strictEqual(layoutShiftsTrackAppender.titleForEvent(shift), ''); }); it('shows "Layout shift" tooltip on hover', async function() { const {layoutShiftsTrackAppender, parsedTrace} = await renderTrackAppender(this, 'cls-no-nav.json.gz'); const shifts = parsedTrace.LayoutShifts.clusters.flatMap(c => c.events); await layoutShiftsTrackAppender.preloadScreenshots(shifts); const info: Timeline.CompatibilityTracksAppender.PopoverInfo = { title: 'title', formattedTime: 'time', warningElements: [], additionalElements: [], url: null, }; layoutShiftsTrackAppender.setPopoverInfo(shifts[3], info); assert.strictEqual(info.title, 'Layout shift'); assert.strictEqual(info.formattedTime, '0.0197'); assert.strictEqual(info.additionalElements?.at(0)?.nodeName, 'DIV'); }); });