// Copyright 2022 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 sinon from 'sinon';
import * as Platform from '../../core/platform/platform.js';
import * as SDK from '../../core/sdk/sdk.js';
import { createTarget } from '../../testing/EnvironmentHelpers.js';
import { describeWithMockConnection } from '../../testing/MockConnection.js';
import { getMainFrame, navigate } from '../../testing/ResourceTreeHelpers.js';
import * as Security from './security.js';
const { urlString } = Platform.DevToolsPath;
describeWithMockConnection('SecurityPanelSidebarTree', () => {
    describe('updateOrigin', () => {
        it('correctly updates the URL scheme highlighting', () => {
            const origin = urlString `https://foo.bar`;
            const securityPanel = Security.SecurityPanel.SecurityPanel.instance({ forceNew: true });
            securityPanel.sidebar.addOrigin(origin, "unknown" /* Protocol.Security.SecurityState.Unknown */);
            assert.notExists(securityPanel.sidebar.sidebarTree.contentElement.querySelector('.highlighted-url > .url-scheme-secure'));
            assert.exists(securityPanel.sidebar.sidebarTree.contentElement.querySelector('.highlighted-url > .url-scheme-unknown'));
            securityPanel.sidebar.updateOrigin(origin, "secure" /* Protocol.Security.SecurityState.Secure */);
            assert.exists(securityPanel.sidebar.sidebarTree.contentElement.querySelector('.highlighted-url > .url-scheme-secure'));
            assert.notExists(securityPanel.sidebar.sidebarTree.contentElement.querySelector('.highlighted-url > .url-scheme-unknown'));
        });
    });
});
describeWithMockConnection('SecurityPanel', () => {
    let target;
    let prerenderTarget;
    beforeEach(() => {
        const tabTarget = createTarget({ type: SDK.Target.Type.TAB });
        prerenderTarget = createTarget({ parentTarget: tabTarget, subtype: 'prerender' });
        target = createTarget({ parentTarget: tabTarget });
    });
    it('updates when security state changes', async () => {
        const securityPanel = Security.SecurityPanel.SecurityPanel.instance({ forceNew: true });
        const securityModel = target.model(Security.SecurityModel.SecurityModel);
        assert.exists(securityModel);
        const visibleSecurityState = {
            securityState: "insecure" /* Protocol.Security.SecurityState.Insecure */,
            securityStateIssueIds: [],
            certificateSecurityState: null,
        };
        securityModel.dispatchEventToListeners(Security.SecurityModel.Events.VisibleSecurityStateChanged, visibleSecurityState);
        assert.isTrue(securityPanel.mainView.contentElement.querySelector('.security-summary')
            ?.classList.contains('security-summary-insecure'));
        visibleSecurityState.securityState = "secure" /* Protocol.Security.SecurityState.Secure */;
        securityModel.dispatchEventToListeners(Security.SecurityModel.Events.VisibleSecurityStateChanged, visibleSecurityState);
        assert.isFalse(securityPanel.mainView.contentElement.querySelector('.security-summary')
            ?.classList.contains('security-summary-insecure'));
        assert.isTrue(securityPanel.mainView.contentElement.querySelector('.security-summary')
            ?.classList.contains('security-summary-secure'));
    });
    it('can switch to a different SecurityModel', async () => {
        const mainSecurityModel = target.model(Security.SecurityModel.SecurityModel);
        assert.exists(mainSecurityModel);
        const securityPanel = Security.SecurityPanel.SecurityPanel.instance({ forceNew: true });
        // Add the main target to the security panel.
        securityPanel.modelAdded(mainSecurityModel);
        const visibleSecurityState = {
            securityState: "insecure" /* Protocol.Security.SecurityState.Insecure */,
            securityStateIssueIds: [],
            certificateSecurityState: null,
        };
        mainSecurityModel.dispatchEventToListeners(Security.SecurityModel.Events.VisibleSecurityStateChanged, visibleSecurityState);
        assert.isTrue(securityPanel.mainView.contentElement.querySelector('.security-summary')
            ?.classList.contains('security-summary-insecure'));
        // Switch to the prerender target.
        const prerenderSecurityModel = prerenderTarget.model(Security.SecurityModel.SecurityModel);
        assert.exists(prerenderSecurityModel);
        securityPanel.modelAdded(prerenderSecurityModel);
        securityPanel.modelRemoved(mainSecurityModel);
        // Check that the security panel does not listen to events from the previous target.
        visibleSecurityState.securityState = "secure" /* Protocol.Security.SecurityState.Secure */;
        mainSecurityModel.dispatchEventToListeners(Security.SecurityModel.Events.VisibleSecurityStateChanged, visibleSecurityState);
        assert.isTrue(securityPanel.mainView.contentElement.querySelector('.security-summary')
            ?.classList.contains('security-summary-insecure'));
        // Check that the security panel listens to events from the current target.
        prerenderSecurityModel.dispatchEventToListeners(Security.SecurityModel.Events.VisibleSecurityStateChanged, visibleSecurityState);
        assert.isTrue(securityPanel.mainView.contentElement.querySelector('.security-summary')
            ?.classList.contains('security-summary-secure'));
        // Check that the SecurityPanel listens to any PrimaryPageChanged event
        const sidebarTreeClearSpy = sinon.spy(securityPanel.sidebar, 'clearOrigins');
        navigate(getMainFrame(target));
        sinon.assert.calledOnce(sidebarTreeClearSpy);
    });
    it('shows \'reload page\' message when no data is available', async () => {
        const securityModel = target.model(Security.SecurityModel.SecurityModel);
        assert.exists(securityModel);
        const securityPanel = Security.SecurityPanel.SecurityPanel.instance({ forceNew: true });
        // Check that reload message is visible initially.
        const reloadMessage = securityPanel.sidebar.sidebarTree.shadowRoot.querySelector('.security-main-view-reload-message');
        assert.instanceOf(reloadMessage, HTMLLIElement);
        assert.isFalse(reloadMessage.classList.contains('hidden'));
        // Check that reload message is hidden when there is data to display.
        const networkManager = securityModel.networkManager();
        const request = {
            wasBlocked: () => false,
            url: () => 'https://www.example.com',
            securityState: () => "secure" /* Protocol.Security.SecurityState.Secure */,
            securityDetails: () => null,
            cached: () => false,
        };
        networkManager.dispatchEventToListeners(SDK.NetworkManager.Events.RequestFinished, request);
        assert.isTrue(reloadMessage.classList.contains('hidden'));
        // Check that reload message is hidden after clearing data.
        navigate(getMainFrame(target));
        assert.isFalse(reloadMessage.classList.contains('hidden'));
    });
    it('shows origins with blockable and optionally blockable resources in the sidebar', async () => {
        const securityPanel = Security.SecurityPanel.SecurityPanel.instance({ forceNew: true });
        const sidebarTreeClearSpy = sinon.spy(securityPanel.sidebar, 'addOrigin');
        const pageVisibleSecurityState = new Security.SecurityModel.PageVisibleSecurityState("neutral" /* Protocol.Security.SecurityState.Neutral */, null, null, ['displayed-mixed-content', 'ran-mixed-content']);
        const securityModel = target.model(Security.SecurityModel.SecurityModel);
        assert.exists(securityModel);
        securityModel.dispatchEventToListeners(Security.SecurityModel.Events.VisibleSecurityStateChanged, pageVisibleSecurityState);
        const passive = SDK.NetworkRequest.NetworkRequest.create('0', urlString `http://foo.test`, urlString `https://foo.test`, '0', '0', null);
        passive.mixedContentType = "optionally-blockable" /* Protocol.Security.MixedContentType.OptionallyBlockable */;
        const networkManager = securityModel.networkManager();
        networkManager.dispatchEventToListeners(SDK.NetworkManager.Events.RequestFinished, passive);
        assert.isTrue(sidebarTreeClearSpy.calledOnceWith(urlString `http://foo.test`, "insecure" /* Protocol.Security.SecurityState.Insecure */));
        sidebarTreeClearSpy.resetHistory();
        const active = SDK.NetworkRequest.NetworkRequest.create('0', urlString `http://bar.test`, urlString `https://bar.test`, '0', '0', null);
        active.mixedContentType = "blockable" /* Protocol.Security.MixedContentType.Blockable */;
        networkManager.dispatchEventToListeners(SDK.NetworkManager.Events.RequestFinished, active);
        assert.isTrue(sidebarTreeClearSpy.calledOnceWith(urlString `http://bar.test`, "insecure" /* Protocol.Security.SecurityState.Insecure */));
    });
    it('hides and shows the sidebar origin list when an interstitial is shown or hidden', async () => {
        const securityPanel = Security.SecurityPanel.SecurityPanel.instance({ forceNew: true });
        const toggleSidebarSpy = sinon.spy(securityPanel.sidebar, 'toggleOriginsList');
        const resourceTreeModel = target.model(SDK.ResourceTreeModel.ResourceTreeModel);
        assert.exists(resourceTreeModel);
        const networkManager = target.model(SDK.NetworkManager.NetworkManager);
        assert.exists(networkManager);
        const request1 = SDK.NetworkRequest.NetworkRequest.create('0', urlString `https://foo.test/`, urlString `https://foo.test`, '0', '0', null);
        request1.setSecurityState("secure" /* Protocol.Security.SecurityState.Secure */);
        networkManager.dispatchEventToListeners(SDK.NetworkManager.Events.RequestFinished, request1);
        const request2 = SDK.NetworkRequest.NetworkRequest.create('0', urlString `https://bar.test/foo.jpg`, urlString `https://bar.test`, '0', '0', null);
        request2.setSecurityState("secure" /* Protocol.Security.SecurityState.Secure */);
        networkManager.dispatchEventToListeners(SDK.NetworkManager.Events.RequestFinished, request2);
        resourceTreeModel.dispatchEventToListeners(SDK.ResourceTreeModel.Events.InterstitialShown);
        // Simulate a request finishing after the interstitial is shown, to make sure that doesn't show up in the sidebar.
        const request3 = SDK.NetworkRequest.NetworkRequest.create('0', urlString `https://bar.test/foo.jpg`, urlString `https://bar.test`, '0', '0', null);
        request3.setSecurityState("unknown" /* Protocol.Security.SecurityState.Unknown */);
        networkManager.dispatchEventToListeners(SDK.NetworkManager.Events.RequestFinished, request3);
        assert.isTrue(toggleSidebarSpy.calledOnceWith(true));
        toggleSidebarSpy.resetHistory();
        // Test that the sidebar is shown again when the interstitial is hidden. https://crbug.com/559150
        resourceTreeModel.dispatchEventToListeners(SDK.ResourceTreeModel.Events.InterstitialHidden);
        assert.isTrue(toggleSidebarSpy.calledOnceWith(false));
    });
});
//# sourceMappingURL=SecurityPanel.test.js.map