// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { assert } from 'chai';
import { describeWithEnvironment } from '../../../testing/EnvironmentHelpers.js';
import { createContextForNavigation, getFirstOrError, getInsightOrError, processTrace, } from '../../../testing/InsightHelpers.js';
import { TraceLoader } from '../../../testing/TraceLoader.js';
import * as Helpers from '../helpers/helpers.js';
import * as Trace from '../trace.js';
import * as Types from '../types/types.js';
describeWithEnvironment('LCPBreakdown', function () {
    it('calculates text lcp breakdown', async function () {
        const { data, insights } = await processTrace(this, 'lcp-web-font.json.gz');
        const firstNav = getFirstOrError(data.Meta.navigationsByNavigationId.values());
        const insight = getInsightOrError('LCPBreakdown', insights, firstNav);
        assert.strictEqual(insight.lcpMs, 106.482);
        const wantTtfb = Types.Timing.Micro(6115);
        const wantRenderDelay = Types.Timing.Micro(100367);
        assert.exists(insight.subparts);
        const actual = Object.fromEntries(Object.entries(insight.subparts).map(([key, value]) => [key, value.range]));
        assert.deepEqual(actual, { ttfb: wantTtfb, renderDelay: wantRenderDelay });
    });
    it('calculates text lcp breakdown (doc missing receiveHeadersStart)', async function () {
        const { data, insights } = await processTrace(this, 'web-dev.json.gz');
        const firstNav = getFirstOrError(data.Meta.navigationsByNavigationId.values());
        const insight = getInsightOrError('LCPBreakdown', insights, firstNav);
        assert.strictEqual(insight.lcpMs, 118.437);
        const wantTtfb = Types.Timing.Micro(31343);
        const wantRenderDelay = Types.Timing.Micro(87094);
        assert.exists(insight.subparts);
        const actual = Object.fromEntries(Object.entries(insight.subparts).map(([key, value]) => [key, value.range]));
        assert.deepEqual(actual, { ttfb: wantTtfb, renderDelay: wantRenderDelay });
    });
    it('calculates image lcp breakdown', async function () {
        const { data, insights } = await processTrace(this, 'lcp-images.json.gz');
        const firstNav = getFirstOrError(data.Meta.navigationsByNavigationId.values());
        const insight = getInsightOrError('LCPBreakdown', insights, firstNav);
        assert.strictEqual(insight.lcpMs, 109.623);
        if (!insight.subparts) {
            throw new Error('No LCP subparts');
        }
        const subparts = {
            ttfb: Helpers.Timing.microToMilli(insight.subparts.ttfb?.range).toFixed(2),
            loadTime: Helpers.Timing.microToMilli(insight.subparts.loadDuration?.range).toFixed(2),
            loadDelay: Helpers.Timing.microToMilli(insight.subparts.loadDelay?.range).toFixed(2),
            renderDelay: Helpers.Timing.microToMilli(insight.subparts.renderDelay?.range).toFixed(2),
        };
        assert.deepEqual(subparts, { ttfb: '6.94', loadTime: '12.10', loadDelay: '33.74', renderDelay: '56.85' });
    });
    it('calculates image lcp breakdown (doc missing receiveHeadersStart)', async function () {
        const { data, insights } = await processTrace(this, 'multiple-navigations.json.gz');
        const firstNav = getFirstOrError(data.Meta.navigationsByNavigationId.values());
        const insight = getInsightOrError('LCPBreakdown', insights, firstNav);
        assert.strictEqual(insight.lcpMs, 118.677);
        if (!insight.subparts) {
            throw new Error('No LCP subparts');
        }
        const subparts = {
            ttfb: Helpers.Timing.microToMilli(insight.subparts.ttfb?.range).toFixed(2),
            loadTime: Helpers.Timing.microToMilli(insight.subparts.loadDuration?.range).toFixed(2),
            loadDelay: Helpers.Timing.microToMilli(insight.subparts.loadDelay?.range).toFixed(2),
            renderDelay: Helpers.Timing.microToMilli(insight.subparts.renderDelay?.range).toFixed(2),
        };
        assert.deepEqual(subparts, { ttfb: '61.47', loadTime: '0.19', loadDelay: '47.74', renderDelay: '9.28' });
    });
    describe('Lightrider', () => {
        before(() => {
            // @ts-expect-error
            globalThis.isLightrider = true;
        });
        after(() => {
            // @ts-expect-error
            delete globalThis.isLightrider;
        });
        it('calculates lcp breakdown', 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 mainRequestEvent.args.data.timing;
            mainRequestEvent.args.data.headers = [
                { name: 'X-ResponseMs', value: '1234' },
            ];
            traceEvents[mainRequestEventIndex] = mainRequestEvent;
            await processor.parse(traceEvents, { isCPUProfile: false, isFreshRecording: true });
            const data = processor.data;
            if (!data) {
                throw new Error('missing data');
            }
            const navigation = getFirstOrError(data.Meta.navigationsByNavigationId.values());
            const context = createContextForNavigation(data, navigation, data.Meta.mainFrameId);
            const insight = Trace.Insights.Models.LCPBreakdown.generateInsight(data, context);
            if (!insight.subparts) {
                throw new Error('No LCP subparts');
            }
            const subparts = {
                ttfb: Helpers.Timing.microToMilli(insight.subparts.ttfb?.range).toFixed(2),
            };
            assert.deepEqual(subparts, { ttfb: '1234.81' });
        });
    });
    describe('warnings', function () {
        it('warns when there is no lcp', async function () {
            const { data, insights } = await processTrace(this, 'user-timings.json.gz');
            const firstNav = getFirstOrError(data.Meta.navigationsByNavigationId.values());
            const insight = getInsightOrError('LCPBreakdown', insights, firstNav);
            assert.isUndefined(insight.lcpMs);
            assert.isUndefined(insight.subparts);
            assert.strictEqual(insight.warnings?.[0], 'NO_LCP');
        });
        it('no main document url', async function () {
            const { data, insights } = await processTrace(this, 'about-blank-first.json.gz');
            const firstNav = getFirstOrError(data.Meta.navigationsByNavigationId.values());
            const insight = getInsightOrError('LCPBreakdown', insights, firstNav);
            assert.strictEqual(insight.lcpMs, 204.909);
            assert.isUndefined(insight.subparts);
            assert.strictEqual(insight.warnings?.[0], 'NO_DOCUMENT_REQUEST');
        });
    });
});
//# sourceMappingURL=LCPBreakdown.test.js.map