"use strict";
// 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.
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.DevToolsFrontendTab = void 0;
exports.loadEmptyPageAndWaitForContent = loadEmptyPageAndWaitForContent;
const fs = __importStar(require("node:fs"));
const path = __importStar(require("node:path"));
const events_js_1 = require("./events.js");
const paths_js_1 = require("./paths.js");
// When loading DevTools with target.goto, we wait for it to be fully loaded using these events.
const DEVTOOLS_WAITUNTIL_EVENTS = ['networkidle2', 'domcontentloaded'];
// When loading an empty page (including within the devtools window), we wait for it to be loaded using these events.
const EMPTY_PAGE_WAITUNTIL_EVENTS = ['domcontentloaded'];
const EMPTY_PAGE = 'data:text/html,<!DOCTYPE html>';
/**
 * Wrapper class around `puppeteer.Page` that helps with setting up and
 * managing a DevTools frontend tab.
 */
class DevToolsFrontendTab {
    page;
    #frontendUrl;
    static DEFAULT_TAB = {
        name: 'elements',
        selector: '.elements',
    };
    // We use the counter to give each tab a unique origin.
    static tabCounter = 0;
    constructor(page, frontendUrl) {
        this.page = page;
        this.#frontendUrl = frontendUrl;
    }
    static async create({ browser, testServerPort, targetId }) {
        // TODO(pfaffe): Remove the distinction once it's uniform in chrome-branded builds
        let devToolsAppURL = 'devtools_app.html';
        if (!fs.existsSync(path.join(paths_js_1.BUILD_ROOT, 'gen', devToolsAppURL))) {
            devToolsAppURL = 'front_end/devtools_app.html';
        }
        // We load the DevTools frontend on a unique origin. Otherwise we would share 'localhost' with
        // target pages. This could cause difficult to debug problems as things like window.localStorage
        // would be shared and requests would be "same-origin".
        // We also use a unique ID per DevTools frontend instance, to avoid the same issue with other
        // frontend instances.
        const id = DevToolsFrontendTab.tabCounter++;
        const frontendUrl = `https://i${id}.devtools-frontend.test:${testServerPort}/${devToolsAppURL}?ws=localhost:${getDebugPort(browser)}/devtools/page/${targetId}&targetType=tab`;
        const frontend = await browser.newPage();
        (0, events_js_1.installPageErrorHandlers)(frontend);
        const devToolsVeLogging = { enabled: true, testing: true };
        await frontend.evaluateOnNewDocument(`globalThis.hostConfigForTesting = ${JSON.stringify({ devToolsVeLogging })};`);
        await frontend.goto(frontendUrl, { waitUntil: DEVTOOLS_WAITUNTIL_EVENTS });
        const tab = new DevToolsFrontendTab(frontend, frontendUrl);
        return tab;
    }
    /** Same as `reload` but also clears out experiments and settings (window.localStorage really) */
    async reset() {
        // Clear any local storage settings.
        await this.page.evaluate(() => {
            localStorage.clear();
            // Test logging needs debug event logging,
            // which is controlled via localStorage, hence we need to restart test logging here
            // This can be called after a page fails to load DevTools so make it conditional
            // @ts-expect-error
            globalThis?.setVeDebugLoggingEnabled?.(true, 'Test');
        });
        await this.reload();
    }
    async reload(options = {}) {
        // For the unspecified case wait for loading, then wait for the elements panel.
        const { selectedPanel = DevToolsFrontendTab.DEFAULT_TAB, canDock = false, queryParams = {}, drawerShown = false } = options;
        if (selectedPanel.name !== DevToolsFrontendTab.DEFAULT_TAB.name) {
            await this.page.evaluate(name => {
                globalThis.localStorage.setItem('panel-selected-tab', `"${name}"`);
            }, selectedPanel.name);
        }
        if (drawerShown) {
            await this.page.evaluate(() => {
                globalThis.localStorage.setItem('inspector.drawer-split-view-state', '{"horizontal" : {"showMode": "Both"}}');
            });
        }
        // Reload the DevTools frontend and await the elements panel.
        await loadEmptyPageAndWaitForContent(this.page);
        // omit "can_dock=" when it's false because appending "can_dock=false"
        // will make getElementPosition in shared helpers unhappy
        let url = canDock ? `${this.#frontendUrl}&can_dock=true` : this.#frontendUrl;
        if (queryParams.panel) {
            url += `&panel=${queryParams.panel}`;
        }
        await this.page.goto(url, { waitUntil: DEVTOOLS_WAITUNTIL_EVENTS });
        if (!queryParams.panel && selectedPanel.selector) {
            await this.page.waitForSelector(selectedPanel.selector);
        }
    }
    /**
     * Returns the current hostname of this frontend tab. This might not be
     * consistent with the intial URL in case the page was navigated to
     * a different origin.
     */
    hostname() {
        const url = new URL(this.page.url());
        return url.hostname;
    }
}
exports.DevToolsFrontendTab = DevToolsFrontendTab;
async function loadEmptyPageAndWaitForContent(target) {
    await target.goto(EMPTY_PAGE, { waitUntil: EMPTY_PAGE_WAITUNTIL_EVENTS });
}
function getDebugPort(browser) {
    const websocketUrl = browser.wsEndpoint();
    const url = new URL(websocketUrl);
    if (url.port) {
        return url.port;
    }
    throw new Error(`Unable to find debug port: ${websocketUrl}`);
}
//# sourceMappingURL=frontend_tab.js.map