chrome-devtools-frontend
Version:
Chrome DevTools UI
107 lines (93 loc) • 5.86 kB
text/typescript
// Copyright 2024 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 {describeWithEnvironment} from '../../../testing/EnvironmentHelpers.js';
import {
createContextForNavigation,
getFirstOrError,
getInsightOrError,
processTrace,
} from '../../../testing/InsightHelpers.js';
import {TraceLoader} from '../../../testing/TraceLoader.js';
import * as Trace from '../trace.js';
import * as Types from '../types/types.js';
describeWithEnvironment('DocumentLatency', function() {
it('reports savings for main document with redirects', async () => {
const {data, insights} = await processTrace(this, 'lantern/redirect/trace.json.gz');
const insight =
getInsightOrError('DocumentLatency', insights, getFirstOrError(data.Meta.navigationsByNavigationId.values()));
assert.strictEqual(insight.data?.redirectDuration, 1779);
assert.deepEqual(insight.metricSavings, {FCP: 1779, LCP: 1779} as Trace.Insights.Types.MetricSavings);
});
it('reports no savings for server with fast server response time', async () => {
const {data, insights} = await processTrace(this, 'lantern/paul/trace.json.gz');
const insight =
getInsightOrError('DocumentLatency', insights, getFirstOrError(data.Meta.navigationsByNavigationId.values()));
assert.strictEqual(insight.data?.serverResponseTime, 43);
assert.isTrue(insight.data?.checklist.serverResponseIsFast.value);
assert.deepEqual(insight.metricSavings, {FCP: 0, LCP: 0} as Trace.Insights.Types.MetricSavings);
});
it('reports savings for server with slow server response time', async function() {
const traceEvents = [...await TraceLoader.rawEvents(this, 'lantern/paul/trace.json.gz')];
const processor = Trace.Processor.TraceProcessor.createWithAllHandlers();
const mainRequestEventIndex = traceEvents.findIndex(e => e.name === 'ResourceReceiveResponse');
const mainRequestEvent = structuredClone(traceEvents[mainRequestEventIndex]);
assert(Types.Events.isResourceReceiveResponse(mainRequestEvent));
assert.strictEqual(mainRequestEvent.args.data.requestId, '1000C0FDC0A75327167272FC7438E999');
if (!mainRequestEvent.args.data.timing) {
throw new Error('missing timing field');
}
mainRequestEvent.args.data.timing.receiveHeadersEnd =
Types.Timing.Milli(mainRequestEvent.args.data.timing.receiveHeadersEnd + 1000);
traceEvents[mainRequestEventIndex] = mainRequestEvent;
await processor.parse(traceEvents, {isCPUProfile: false, isFreshRecording: true});
const data = processor.parsedTrace;
if (!data) {
throw new Error('missing parsedTrace');
}
const navigation = getFirstOrError(data.Meta.navigationsByNavigationId.values());
const context = createContextForNavigation(data, navigation, data.Meta.mainFrameId);
const insight = Trace.Insights.Models.DocumentLatency.generateInsight(data, context);
assert.strictEqual(insight.data?.serverResponseTime, 1043);
assert.isFalse(insight.data?.checklist.serverResponseIsFast.value);
assert.deepEqual(insight.metricSavings, {FCP: 943, LCP: 943} as Trace.Insights.Types.MetricSavings);
});
it('reports no compression savings for compressed text', async () => {
const {data, insights} = await processTrace(this, 'lantern/paul/trace.json.gz');
const insight =
getInsightOrError('DocumentLatency', insights, getFirstOrError(data.Meta.navigationsByNavigationId.values()));
assert.strictEqual(insight.data?.uncompressedResponseBytes, 0);
assert.deepEqual(insight.metricSavings, {FCP: 0, LCP: 0} as Trace.Insights.Types.MetricSavings);
});
it('reports compression savings for uncompressed text', async function() {
const traceEvents = [...await TraceLoader.rawEvents(this, 'lantern/paul/trace.json.gz')];
const processor = Trace.Processor.TraceProcessor.createWithAllHandlers();
const mainRequestEventIndex = traceEvents.findIndex(e => e.name === 'ResourceReceiveResponse');
const mainRequestEvent = structuredClone(traceEvents[mainRequestEventIndex]);
assert(Types.Events.isResourceReceiveResponse(mainRequestEvent));
assert.strictEqual(mainRequestEvent.args.data.requestId, '1000C0FDC0A75327167272FC7438E999');
// Delete content-encoding header.
mainRequestEvent.args.data.headers = mainRequestEvent.args.data.headers?.filter(h => h.name !== 'content-encoding');
traceEvents[mainRequestEventIndex] = mainRequestEvent;
await processor.parse(traceEvents, {isCPUProfile: false, isFreshRecording: true});
const data = processor.parsedTrace;
if (!data) {
throw new Error('missing parsedTrace');
}
const navigation = getFirstOrError(data.Meta.navigationsByNavigationId.values());
const context = createContextForNavigation(data, navigation, data.Meta.mainFrameId);
const insight = Trace.Insights.Models.DocumentLatency.generateInsight(data, context);
assert.strictEqual(insight.data?.uncompressedResponseBytes, 39799);
assert.deepEqual(insight.metricSavings, {FCP: 0, LCP: 0} as Trace.Insights.Types.MetricSavings);
});
it('reports savings for main document with many issues, many redirects', async () => {
const {data, insights} = await processTrace(this, 'many-redirects.json.gz');
const insight =
getInsightOrError('DocumentLatency', insights, getFirstOrError(data.Meta.navigationsByNavigationId.values()));
assert.strictEqual(insight.data?.redirectDuration, 6059);
assert.strictEqual(insight.data?.uncompressedResponseBytes, 111506);
assert.strictEqual(insight.data?.serverResponseTime, 2008);
assert.isFalse(insight.data?.checklist.serverResponseIsFast.value);
assert.deepEqual(insight.metricSavings, {FCP: 7967, LCP: 7967} as Trace.Insights.Types.MetricSavings);
});
});