chrome-devtools-frontend
Version:
Chrome DevTools UI
138 lines (115 loc) • 6.75 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 {getInsightOrError, processTrace} from '../../../testing/InsightHelpers.js';
import * as Trace from '../../trace/trace.js';
describeWithEnvironment('RenderBlocking', function() {
it('finds render blocking requests', async () => {
const {data, insights} = await processTrace(this, 'load-simple.json.gz');
assert.deepEqual([...insights.keys()], [Trace.Types.Events.NO_NAVIGATION, '0BCFC23BC7D7BEDC9F93E912DCCEC1DA']);
const insight =
getInsightOrError('RenderBlocking', insights, data.Meta.navigationsByNavigationId.values().next().value);
assert.lengthOf(insight.renderBlockingRequests, 2);
assert.deepEqual(insight.renderBlockingRequests.map(r => r.args.data.url), [
'https://fonts.googleapis.com/css2?family=Orelega+One&display=swap',
'http://localhost:8080/styles.css',
]);
});
it('returns a warning if navigation does not have a first paint event', async () => {
const {data, insights} = await processTrace(this, 'user-timings.json.gz');
assert.strictEqual(insights.size, 1);
const insight =
getInsightOrError('RenderBlocking', insights, data.Meta.navigationsByNavigationId.values().next().value);
assert.lengthOf(insight.renderBlockingRequests, 0);
assert.strictEqual(insight.warnings?.length, 1);
assert.strictEqual(insight.warnings?.[0], 'NO_FP');
});
it('considers only the navigation specified by the context', async () => {
const {data, insights} = await processTrace(this, 'multiple-navigations-render-blocking.json.gz');
assert.deepEqual(
[...insights.keys()],
[Trace.Types.Events.NO_NAVIGATION, '8671F33ECE0C8DBAEFBC2F9A2D1D6107', '1AE2016BBCC48AA090FDAE2CBBA01900']);
const navigations = Array.from(data.Meta.navigationsByNavigationId.values());
const insight = getInsightOrError('RenderBlocking', insights, navigations[0]);
assert(insight.renderBlockingRequests.length > 0, 'no render blocking requests found');
assert(
insight.renderBlockingRequests.every(r => r.args.data.syntheticData.sendStartTime > navigations[0].ts),
'a result is not contained by the nav bounds');
assert(
insight.renderBlockingRequests.every(r => r.args.data.syntheticData.finishTime < navigations[1].ts),
'a result is not contained by the nav bounds');
});
it('considers navigations separately', async () => {
const {data, insights} = await processTrace(this, 'multiple-navigations-render-blocking.json.gz');
assert.strictEqual(insights.size, 3);
const navigations = Array.from(data.Meta.navigationsByNavigationId.values());
const insightOne = getInsightOrError('RenderBlocking', insights);
const insightTwo = getInsightOrError('RenderBlocking', insights, navigations[0]);
const insightThree = getInsightOrError('RenderBlocking', insights, navigations[1]);
assert.deepEqual(insightOne.renderBlockingRequests.map(r => r.args.data.requestId), []);
assert.deepEqual(insightTwo.renderBlockingRequests.map(r => r.args.data.requestId), ['99116.2']);
assert.deepEqual(insightThree.renderBlockingRequests.map(r => r.args.data.requestId), ['99116.5']);
});
it('considers only the frame specified by the context', async () => {
const {data, insights} = await processTrace(this, 'render-blocking-in-iframe.json.gz');
assert.strictEqual(insights.size, 1);
const navigations = Array.from(data.Meta.navigationsByNavigationId.values());
const insight = getInsightOrError('RenderBlocking', insights, navigations[0]);
assert(insight.renderBlockingRequests.length > 0, 'no render blocking requests found');
assert(
insight.renderBlockingRequests.every(r => r.args.data.frame === data.Meta.mainFrameId),
'a result is not from the main frame');
});
it('ignores blocking request after first paint', async () => {
const {data, insights} = await processTrace(this, 'parser-blocking-after-paint.json.gz');
assert.strictEqual(insights.size, 1);
const insight =
getInsightOrError('RenderBlocking', insights, data.Meta.navigationsByNavigationId.values().next().value);
assert.lengthOf(insight.renderBlockingRequests, 0);
});
it('correctly handles body parser blocking requests', async () => {
const {data, insights} = await processTrace(this, 'render-blocking-body.json.gz');
assert.strictEqual(insights.size, 1);
const insight =
getInsightOrError('RenderBlocking', insights, data.Meta.navigationsByNavigationId.values().next().value);
assert.deepEqual(insight.renderBlockingRequests.map(r => r.args.data.url), [
'http://localhost:8080/render-blocking/style.css',
'http://localhost:8080/render-blocking/script.js?beforeImage',
]);
});
// TODO(crbug.com/372674229): when swapping to 'provided' instead of 'simulated', all these test traces give
// uninteresting results. must get new traces.
it('estimates savings with Lantern (image LCP)', async () => {
const {data, insights} = await processTrace(this, 'lantern/render-blocking/trace.json.gz');
assert.strictEqual(insights.size, 1);
const insight =
getInsightOrError('RenderBlocking', insights, data.Meta.navigationsByNavigationId.values().next().value);
assert.deepEqual(insight.metricSavings, {
FCP: 0,
LCP: 0,
} as Trace.Insights.Types.MetricSavings);
assert.exists(insight.requestIdToWastedMs);
const urlToWastedMs = [...insight.requestIdToWastedMs].map(([requestId, wastedMs]) => {
const url = insight.renderBlockingRequests.find(r => r.args.data.requestId === requestId)?.args.data.url;
return [url, wastedMs];
});
assert.deepEqual(urlToWastedMs, []);
});
it('estimates savings with Lantern (text LCP)', async () => {
const {data, insights} = await processTrace(this, 'lantern/typescript-angular/trace.json.gz');
assert.strictEqual(insights.size, 1);
const insight =
getInsightOrError('RenderBlocking', insights, data.Meta.navigationsByNavigationId.values().next().value);
assert.deepEqual(insight.metricSavings, {
FCP: 0,
LCP: 0,
} as Trace.Insights.Types.MetricSavings);
assert.exists(insight.requestIdToWastedMs);
const urlToWastedMs = [...insight.requestIdToWastedMs].map(([requestId, wastedMs]) => {
const url = insight.renderBlockingRequests.find(r => r.args.data.requestId === requestId)?.args.data.url;
return [url, wastedMs];
});
assert.deepEqual(urlToWastedMs, []);
});
});