"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getComputedStylesForDomNode = exports.removePseudoState = exports.forcePseudoState = exports.showForceState = exports.findElementById = exports.expandSelectedNodeRecursively = exports.getPropertyFromComputedPane = exports.getAllPropertiesFromComputedPane = exports.waitForComputedPaneChange = exports.getContentOfComputedPane = exports.waitForElementsComputedSection = exports.toggleDOMBreakpointCheckbox = exports.setDOMBreakpointOnSelectedNode = exports.isDOMBreakpointEnabled = exports.waitForElementsDOMBreakpointsSection = exports.waitForElementsStyleSection = exports.navigateToSidePane = exports.focusElementsTree = exports.clickNthChildOfSelectedElementNode = exports.clickTreeElementWithPartialText = exports.elementWithPartialText = exports.waitForElementWithPartialText = exports.waitForAndClickTreeElementWithPartialText = exports.waitForChildrenOfSelectedElementNode = exports.waitForSelectedTreeElementSelectorWhichIncludesText = exports.waitForSelectedTreeElementSelectorWithTextcontent = exports.assertSelectedElementsNodeTextIncludes = exports.waitForSelectedNodeChange = exports.getContentOfSelectedNode = exports.waitForPartialContentOfSelectedElementsNode = exports.waitForContentOfSelectedElementsNode = exports.waitForSomeGridsInLayoutPane = exports.getGridsInLayoutPane = exports.toggleElementCheckboxInLayoutPane = exports.waitForNoAdornersOnSelectedNode = exports.waitForSpecificAdornerOnSelectedNode = exports.waitForAdornerOnSelectedNode = exports.waitForSelectedNodeToBeExpanded = exports.toggleAdornerSetting = exports.waitForAdorners = exports.openLayoutPane = exports.EMULATE_FOCUSED_PAGE = exports.SEARCH_BOX_SELECTOR = exports.STYLE_PROPERTIES_SELECTOR = exports.ACTIVE_STARTING_STYLE_ADORNER_SELECTOR = exports.INACTIVE_STARTING_STYLE_ADORNER_SELECTOR = exports.ACTIVE_GRID_ADORNER_SELECTOR = exports.INACTIVE_GRID_ADORNER_SELECTOR = exports.SECTION_SUBTITLE_SELECTOR = exports.ELEMENTS_PANEL_SELECTOR = void 0;
exports.getMultilineGhostElements = exports.getGhostText = exports.getGhostTextInCurrentTextPrompt = exports.getLastAidaRequest = exports.mockAidaCodeComplete = exports.GHOST_ROW_SELECTOR = exports.GHOST_VALUE_PREDICTION_SELECTOR = exports.TEXT_PROMPT_GHOST_TEXT_SELECTOR = exports.checkStyleAttributes = exports.goToResourceAndWaitForStyleSection = exports.assertSearchResultMatchesText = exports.summonAndWaitForSearchBox = exports.getPropertiesWithHints = exports.toggleAccessibilityTree = exports.toggleAccessibilityPane = exports.assertSelectedNodeClasses = exports.uncheckStylesPaneCheckbox = exports.toggleClassesPaneCheckbox = exports.typeInClassesPaneInput = exports.toggleClassesPane = exports.clickOnFirstLinkInStylesPanel = exports.navigateToElementsTab = exports.getSelectedBreadcrumbTextContent = exports.getBreadcrumbsTextContent = exports.focusCSSPropertyValue = exports.getCSSPropertyInRule = exports.getStyleSectionSubtitles = exports.shiftClickColorSwatch = exports.getColorSwatchColor = exports.getColorSwatch = exports.getStyleRuleWithSourcePosition = exports.getStyleRule = exports.getDisplayedCSSPropertyNames = exports.getDisplayedCSSPropertyData = exports.getDisplayedStyleRules = exports.getDisplayedStyleRulesCompact = exports.getDisplayedCSSDeclarations = exports.getComputedStyleProperties = exports.waitForStyleRule = exports.waitForExactStyleRule = exports.getStyleRuleSelector = exports.assertGutterDecorationForDomNodeExists = exports.waitForDomNodeToBeHidden = exports.waitForDomNodeToBeVisible = exports.toggleShowAllComputedProperties = exports.filterComputedProperties = exports.getComputedPanel = exports.waitForNumberOfComputedProperties = void 0;
exports.getDOMBreakpoints = getDOMBreakpoints;
exports.editCSSProperty = editCSSProperty;
exports.editQueryRuleText = editQueryRuleText;
exports.waitForCSSPropertyValue = waitForCSSPropertyValue;
exports.waitForPropertyToHighlight = waitForPropertyToHighlight;
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
const chai_1 = require("chai");
const async_scope_js_1 = require("../../conductor/async-scope.js");
const helper_js_1 = require("../../shared/helper.js");
const context_menu_helpers_js_1 = require("./context-menu-helpers.js");
const visual_logging_helpers_js_1 = require("./visual-logging-helpers.js");
const SELECTED_TREE_ELEMENT_SELECTOR = '.selected[role="treeitem"]';
const CSS_PROPERTY_NAME_SELECTOR = '.webkit-css-property';
const CSS_PROPERTY_VALUE_SELECTOR = '.value';
const CSS_DECLARATION_SELECTOR = `[role="treeitem"]:has(${CSS_PROPERTY_NAME_SELECTOR}):has(${CSS_PROPERTY_VALUE_SELECTOR})`;
const COLOR_SWATCH_SELECTOR = '.color-swatch-inner';
const CSS_STYLE_RULE_SELECTOR = '[aria-label*="css selector"]';
const COMPUTED_PROPERTY_SELECTOR = 'devtools-computed-style-property';
const COMPUTED_STYLES_PANEL_SELECTOR = '[aria-label="Computed panel"]';
const COMPUTED_STYLES_SHOW_ALL_SELECTOR = '[title="Show all"]';
exports.ELEMENTS_PANEL_SELECTOR = '.panel[aria-label="elements"]';
exports.SECTION_SUBTITLE_SELECTOR = '.styles-section-subtitle';
const CLS_PANE_SELECTOR = '.styles-sidebar-toolbar-pane';
const CLS_BUTTON_SELECTOR = '[aria-label="Element Classes"]';
const CLS_INPUT_SELECTOR = '[aria-placeholder="Add new class"]';
const LAYOUT_PANE_TAB_SELECTOR = '[aria-label="Layout"]';
const LAYOUT_PANE_TABPANEL_SELECTOR = '[aria-label="Layout panel"]';
const ADORNER_SELECTOR = 'devtools-adorner';
exports.INACTIVE_GRID_ADORNER_SELECTOR = '[aria-label="Enable grid mode"]';
exports.ACTIVE_GRID_ADORNER_SELECTOR = '[aria-label="Disable grid mode"]';
exports.INACTIVE_STARTING_STYLE_ADORNER_SELECTOR = '[aria-label="Enable @starting-style mode"]';
exports.ACTIVE_STARTING_STYLE_ADORNER_SELECTOR = '[aria-label="Disable @starting-style mode"]';
const ELEMENT_CHECKBOX_IN_LAYOUT_PANE_SELECTOR = `${LAYOUT_PANE_TABPANEL_SELECTOR} .elements devtools-checkbox`;
const STYLE_QUERY_RULE_TEXT_SELECTOR = '.query-text';
exports.STYLE_PROPERTIES_SELECTOR = '.tree-outline-disclosure [role="treeitem"]';
const CSS_AUTHORING_HINTS_ICON_SELECTOR = '.hint';
exports.SEARCH_BOX_SELECTOR = '.search-bar';
const SEARCH_RESULTS_MATCHES = '.search-results-matches';
exports.EMULATE_FOCUSED_PAGE = 'Emulate a focused page';
const DOM_BREAKPOINTS_SECTION_SELECTOR = '[aria-label="DOM Breakpoints"]';
const DOM_BREAKPOINTS_LIST_SELECTOR = '[aria-label="DOM Breakpoints list"]';
const TOGGLE_COMMON_RENDERING_EMULATIONS_SELECTOR = '[aria-label="Toggle common rendering emulations"]';
const openLayoutPane = async (devToolsPage) => {
    await devToolsPage.click(LAYOUT_PANE_TAB_SELECTOR);
    const panel = await devToolsPage.waitFor(LAYOUT_PANE_TABPANEL_SELECTOR);
    await devToolsPage.waitFor('.elements', panel);
    await (0, visual_logging_helpers_js_1.expectVeEvents)([
        (0, visual_logging_helpers_js_1.veClick)('Panel: elements > Toolbar: sidebar > PanelTabHeader: elements.layout'),
        (0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements', [(0, visual_logging_helpers_js_1.veImpression)('Pane', 'layout', [
                (0, visual_logging_helpers_js_1.veImpression)('SectionHeader', 'grid-settings'),
                (0, visual_logging_helpers_js_1.veImpression)('Section', 'grid-settings', [
                    (0, visual_logging_helpers_js_1.veImpression)('DropDown', 'show-grid-line-labels'),
                    (0, visual_logging_helpers_js_1.veImpression)('Toggle', 'extend-grid-lines'),
                    (0, visual_logging_helpers_js_1.veImpression)('Toggle', 'show-grid-areas'),
                    (0, visual_logging_helpers_js_1.veImpression)('Toggle', 'show-grid-track-sizes'),
                ]),
                (0, visual_logging_helpers_js_1.veImpression)('Section', 'grid-overlays', [(0, visual_logging_helpers_js_1.veImpression)('Item', undefined, [
                        (0, visual_logging_helpers_js_1.veImpression)('Action', 'elements.select-element'),
                        (0, visual_logging_helpers_js_1.veImpression)('ShowStyleEditor', 'color'),
                        (0, visual_logging_helpers_js_1.veImpression)('Toggle'),
                    ])]),
            ])]),
    ], undefined, devToolsPage);
};
exports.openLayoutPane = openLayoutPane;
const waitForAdorners = async (expectedAdorners, devToolsPage, activeSelector = exports.ACTIVE_GRID_ADORNER_SELECTOR) => {
    await devToolsPage.waitForFunction(async () => {
        const actualAdorners = await devToolsPage.$$(ADORNER_SELECTOR);
        const actualAdornersStates = await Promise.all(actualAdorners.map(n => {
            return n.evaluate((node, activeSelector) => {
                return { textContent: node.textContent, isActive: node.matches(activeSelector) };
            }, activeSelector);
        }));
        if (actualAdornersStates.length !== expectedAdorners.length) {
            return false;
        }
        for (let i = 0; i < actualAdornersStates.length; i++) {
            const index = expectedAdorners.findIndex(expected => {
                const actual = actualAdornersStates[i];
                return expected.textContent === actual.textContent && expected.isActive === actual.isActive;
            });
            if (index !== -1) {
                expectedAdorners.splice(index, 1);
            }
        }
        return expectedAdorners.length === 0;
    });
    if (expectedAdorners.length) {
        await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements >  Tree: elements > TreeItem', [(0, visual_logging_helpers_js_1.veImpression)('Adorner', 'grid')])], undefined, devToolsPage);
    }
};
exports.waitForAdorners = waitForAdorners;
const toggleAdornerSetting = async (type, devToolsPage) => {
    await (0, context_menu_helpers_js_1.openSubMenu)(SELECTED_TREE_ELEMENT_SELECTOR, 'Badge settings', devToolsPage);
    const adornerToggle = await Promise.any([
        devToolsPage.waitFor(`[aria-label="${type}, unchecked"]`), devToolsPage.waitFor(`[aria-label="${type}, checked"]`)
    ]);
    await adornerToggle.click();
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veClick)(`Menu > Toggle: ${type}`)], undefined, devToolsPage);
};
exports.toggleAdornerSetting = toggleAdornerSetting;
const waitForSelectedNodeToBeExpanded = async (devToolsPage) => {
    await devToolsPage.waitFor(`${SELECTED_TREE_ELEMENT_SELECTOR}[aria-expanded="true"]`);
};
exports.waitForSelectedNodeToBeExpanded = waitForSelectedNodeToBeExpanded;
const waitForAdornerOnSelectedNode = async (expectedAdornerText, devToolsPage) => {
    await devToolsPage.waitForFunction(async () => {
        const selectedNode = await devToolsPage.waitFor(SELECTED_TREE_ELEMENT_SELECTOR);
        const adorner = await devToolsPage.waitFor(ADORNER_SELECTOR, selectedNode);
        return expectedAdornerText === await adorner.evaluate(node => node.textContent);
    });
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements > Tree: elements > TreeItem', [(0, visual_logging_helpers_js_1.veImpression)('Adorner', expectedAdornerText)])], undefined, devToolsPage);
};
exports.waitForAdornerOnSelectedNode = waitForAdornerOnSelectedNode;
const waitForSpecificAdornerOnSelectedNode = async (selector, devToolsPage) => {
    await devToolsPage.waitForFunction(async () => {
        const selectedNode = await devToolsPage.waitFor(SELECTED_TREE_ELEMENT_SELECTOR);
        const adorner = await devToolsPage.waitFor(selector, selectedNode);
        return !!adorner;
    });
};
exports.waitForSpecificAdornerOnSelectedNode = waitForSpecificAdornerOnSelectedNode;
const waitForNoAdornersOnSelectedNode = async (devToolsPage) => {
    const selectedNode = await devToolsPage.waitFor(SELECTED_TREE_ELEMENT_SELECTOR);
    await devToolsPage.waitForNone(ADORNER_SELECTOR, selectedNode);
};
exports.waitForNoAdornersOnSelectedNode = waitForNoAdornersOnSelectedNode;
const toggleElementCheckboxInLayoutPane = async (devToolsPage) => {
    await devToolsPage.click(ELEMENT_CHECKBOX_IN_LAYOUT_PANE_SELECTOR);
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veClick)('Panel: elements > Pane: layout > Section: grid-overlays > Item > Toggle')], undefined, devToolsPage);
};
exports.toggleElementCheckboxInLayoutPane = toggleElementCheckboxInLayoutPane;
const getGridsInLayoutPane = async (devToolsPage) => {
    const panel = await devToolsPage.waitFor(LAYOUT_PANE_TABPANEL_SELECTOR);
    return await devToolsPage.$$('.elements .element', panel);
};
exports.getGridsInLayoutPane = getGridsInLayoutPane;
const waitForSomeGridsInLayoutPane = async (minimumGridCount, devToolsPage) => {
    await devToolsPage.waitForFunction(async () => {
        const grids = await (0, exports.getGridsInLayoutPane)(devToolsPage);
        return grids.length >= minimumGridCount;
    });
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements > Pane: layout > Section: grid-overlays', [(0, visual_logging_helpers_js_1.veImpression)('Item', undefined, [
                (0, visual_logging_helpers_js_1.veImpression)('Action', 'elements.select-element'),
                (0, visual_logging_helpers_js_1.veImpression)('ShowStyleEditor', 'color'),
                (0, visual_logging_helpers_js_1.veImpression)('Toggle'),
            ])])], undefined, devToolsPage);
};
exports.waitForSomeGridsInLayoutPane = waitForSomeGridsInLayoutPane;
const waitForContentOfSelectedElementsNode = async (expectedTextContent, devToolsPage) => {
    await devToolsPage.waitForFunction(async () => {
        const selectedTextContent = await (0, exports.getContentOfSelectedNode)(devToolsPage);
        return selectedTextContent === expectedTextContent;
    });
};
exports.waitForContentOfSelectedElementsNode = waitForContentOfSelectedElementsNode;
const waitForPartialContentOfSelectedElementsNode = async (expectedPartialTextContent, devToolsPage) => {
    await devToolsPage.waitForFunction(async () => {
        const selectedTextContent = await (0, exports.getContentOfSelectedNode)(devToolsPage);
        return selectedTextContent.includes(expectedPartialTextContent);
    });
};
exports.waitForPartialContentOfSelectedElementsNode = waitForPartialContentOfSelectedElementsNode;
/**
 * Gets the text content of the currently selected element.
 */
const getContentOfSelectedNode = async (devToolsPage) => {
    const selectedNode = await devToolsPage.waitFor(SELECTED_TREE_ELEMENT_SELECTOR);
    return await selectedNode.evaluate(node => node.textContent);
};
exports.getContentOfSelectedNode = getContentOfSelectedNode;
const waitForSelectedNodeChange = async (initialValue, devToolsPage, asyncScope = new async_scope_js_1.AsyncScope()) => {
    await devToolsPage.waitForFunction(async () => {
        const currentContent = await (0, exports.getContentOfSelectedNode)(devToolsPage);
        return currentContent !== initialValue;
    }, asyncScope);
};
exports.waitForSelectedNodeChange = waitForSelectedNodeChange;
const assertSelectedElementsNodeTextIncludes = async (expectedTextContent, devtoolsPage) => {
    const selectedNode = await devtoolsPage.waitFor(SELECTED_TREE_ELEMENT_SELECTOR);
    const selectedTextContent = await selectedNode.evaluate(node => node.textContent);
    chai_1.assert.include(selectedTextContent, expectedTextContent);
};
exports.assertSelectedElementsNodeTextIncludes = assertSelectedElementsNodeTextIncludes;
const waitForSelectedTreeElementSelectorWithTextcontent = async (expectedTextContent, devToolsPage) => {
    await devToolsPage.waitForFunction(async () => {
        const selectedNode = await devToolsPage.waitFor(SELECTED_TREE_ELEMENT_SELECTOR);
        const selectedTextContent = await selectedNode.evaluate(node => node.textContent);
        return selectedTextContent === expectedTextContent;
    });
};
exports.waitForSelectedTreeElementSelectorWithTextcontent = waitForSelectedTreeElementSelectorWithTextcontent;
const waitForSelectedTreeElementSelectorWhichIncludesText = async (expectedTextContent, devToolsPage) => {
    await devToolsPage.waitForFunction(async () => {
        const selectedNode = await devToolsPage.waitFor(SELECTED_TREE_ELEMENT_SELECTOR);
        const selectedTextContent = await selectedNode.evaluate(node => node.textContent);
        return selectedTextContent?.includes(expectedTextContent);
    });
};
exports.waitForSelectedTreeElementSelectorWhichIncludesText = waitForSelectedTreeElementSelectorWhichIncludesText;
const waitForChildrenOfSelectedElementNode = async (devToolsPage, partialTexts) => {
    return await devToolsPage.waitForFunction(async () => {
        const childrenContainer = await devToolsPage.waitFor(SELECTED_TREE_ELEMENT_SELECTOR + ' + ol');
        const children = await devToolsPage.$$('[role="treeitem"]', childrenContainer, 'aria');
        if (!partialTexts) {
            return children.length > 0;
        }
        if (children.length) {
            // Remove the close tag
            --children.length;
        }
        if (children.length !== partialTexts.length) {
            return false;
        }
        for (let i = 0; i < children.length; i++) {
            const match = await children[i].evaluate((element, text) => element.textContent?.includes(text), partialTexts[i]);
            if (!match) {
                return false;
            }
        }
        return true;
    });
};
exports.waitForChildrenOfSelectedElementNode = waitForChildrenOfSelectedElementNode;
const waitForAndClickTreeElementWithPartialText = async (text, devToolsPage) => {
    await devToolsPage.waitForFunction(async () => await (0, exports.clickTreeElementWithPartialText)(text, devToolsPage));
};
exports.waitForAndClickTreeElementWithPartialText = waitForAndClickTreeElementWithPartialText;
const waitForElementWithPartialText = async (text, devToolsPage) => {
    return await devToolsPage.waitForFunction(async () => await (0, exports.elementWithPartialText)(text, devToolsPage));
};
exports.waitForElementWithPartialText = waitForElementWithPartialText;
const elementWithPartialText = async (text, devToolsPage) => {
    const tree = await devToolsPage.waitFor('Page DOM[role="tree"]', undefined, undefined, 'aria');
    const elements = await devToolsPage.$$('[role="treeitem"]', tree, 'aria');
    for (const handle of elements) {
        const match = await handle.evaluate((element, text) => element.textContent?.includes(text), text);
        if (match) {
            return handle;
        }
    }
    return null;
};
exports.elementWithPartialText = elementWithPartialText;
const clickTreeElementWithPartialText = async (text, devToolsPage) => {
    const handle = await (0, exports.elementWithPartialText)(text, devToolsPage);
    if (handle) {
        await devToolsPage.clickElement(handle);
        await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veClick)('Panel: elements > Tree: elements > TreeItem')], undefined, devToolsPage);
        return true;
    }
    return false;
};
exports.clickTreeElementWithPartialText = clickTreeElementWithPartialText;
const clickNthChildOfSelectedElementNode = async (childIndex, devToolsPage) => {
    (0, chai_1.assert)(childIndex > 0, 'CSS :nth-child() selector indices are 1-based.');
    await devToolsPage.click(`${SELECTED_TREE_ELEMENT_SELECTOR} + ol > li:nth-child(${childIndex})`);
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veClick)('Panel: elements > Tree: elements > TreeItem')], undefined, devToolsPage);
};
exports.clickNthChildOfSelectedElementNode = clickNthChildOfSelectedElementNode;
const focusElementsTree = async (devToolsPage) => {
    await devToolsPage.click(SELECTED_TREE_ELEMENT_SELECTOR);
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veClick)('Panel: elements > Tree: elements > TreeItem')], undefined, devToolsPage);
};
exports.focusElementsTree = focusElementsTree;
const navigateToSidePane = async (paneName, devToolsPage) => {
    if ((await devToolsPage.$$(`[aria-label="${paneName} panel"]`)).length) {
        return;
    }
    await devToolsPage.click(`[aria-label="${paneName}"]`);
    await devToolsPage.waitFor(`[aria-label="${paneName} panel"]`);
    const jslogContext = paneName.toLowerCase();
    await (0, visual_logging_helpers_js_1.expectVeEvents)([
        (0, visual_logging_helpers_js_1.veClick)(`Panel: elements > Toolbar: sidebar > PanelTabHeader: ${jslogContext}`),
        (0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements', [(0, visual_logging_helpers_js_1.veImpression)('Pane', jslogContext)]),
    ], undefined, devToolsPage);
};
exports.navigateToSidePane = navigateToSidePane;
const waitForElementsStyleSection = async (expectedNodeText = '<body', devToolsPage) => {
    // Wait for the file to be loaded and selectors to be shown
    await devToolsPage.waitFor('.styles-selector');
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements', [(0, visual_logging_helpers_js_1.veImpression)('Pane', 'styles')])], undefined, devToolsPage);
    // Check to make sure we have the correct node selected after opening a file.
    if (expectedNodeText) {
        await (0, exports.waitForPartialContentOfSelectedElementsNode)(expectedNodeText, devToolsPage);
    }
};
exports.waitForElementsStyleSection = waitForElementsStyleSection;
const waitForElementsDOMBreakpointsSection = async (devToolsPage) => {
    let domBreakpointsPane = await devToolsPage.$('DOM Breakpoints', undefined, 'aria');
    if (!domBreakpointsPane) {
        const elementsPanel = await devToolsPage.waitForAria('Elements panel');
        await devToolsPage.clickMoreTabsButton(elementsPanel);
        domBreakpointsPane = await devToolsPage.waitForAria('DOM Breakpoints');
    }
    await devToolsPage.click(DOM_BREAKPOINTS_SECTION_SELECTOR);
    await devToolsPage.waitFor(DOM_BREAKPOINTS_LIST_SELECTOR);
};
exports.waitForElementsDOMBreakpointsSection = waitForElementsDOMBreakpointsSection;
async function getDOMBreakpoints(devToolsPage) {
    return await devToolsPage.$('.breakpoint-entry');
}
const isDOMBreakpointEnabled = async (breakpoint, devToolsPage) => {
    const checkbox = await devToolsPage.waitFor('input[type="checkbox"]', breakpoint);
    return await checkbox.evaluate(node => node.checked);
};
exports.isDOMBreakpointEnabled = isDOMBreakpointEnabled;
const setDOMBreakpointOnSelectedNode = async (type, devToolsPage) => {
    await (0, context_menu_helpers_js_1.openSubMenu)(SELECTED_TREE_ELEMENT_SELECTOR, 'Break on', devToolsPage);
    const breakpointToggle = await devToolsPage.waitFor(`[aria-label="${type}, unchecked"]`);
    await breakpointToggle.click();
};
exports.setDOMBreakpointOnSelectedNode = setDOMBreakpointOnSelectedNode;
const toggleDOMBreakpointCheckbox = async (breakpoint, wantChecked, devToolsPage) => {
    const checkbox = await devToolsPage.waitFor('input[type="checkbox"]', breakpoint);
    const checked = await checkbox.evaluate(box => box.checked);
    if (checked !== wantChecked) {
        await checkbox.click();
    }
    chai_1.assert.strictEqual(await checkbox.evaluate(box => box.checked), wantChecked);
};
exports.toggleDOMBreakpointCheckbox = toggleDOMBreakpointCheckbox;
const waitForElementsComputedSection = async (devToolsPage) => {
    await devToolsPage.waitFor(COMPUTED_PROPERTY_SELECTOR);
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements', [(0, visual_logging_helpers_js_1.veImpression)('Pane', 'computed')])], undefined, devToolsPage);
};
exports.waitForElementsComputedSection = waitForElementsComputedSection;
const getContentOfComputedPane = async (devToolsPage) => {
    const pane = await devToolsPage.waitFor('Computed panel', undefined, undefined, 'aria');
    const tree = await devToolsPage.waitFor('[role="tree"]', pane, undefined, 'aria');
    return await tree.evaluate(node => node.textContent);
};
exports.getContentOfComputedPane = getContentOfComputedPane;
const waitForComputedPaneChange = async (initialValue, devToolsPage) => {
    await devToolsPage.waitForFunction(async () => {
        const value = await (0, exports.getContentOfComputedPane)(devToolsPage);
        return value !== initialValue;
    });
};
exports.waitForComputedPaneChange = waitForComputedPaneChange;
const getAllPropertiesFromComputedPane = async (devToolsPage) => {
    const properties = await devToolsPage.$$(COMPUTED_PROPERTY_SELECTOR);
    return (await Promise.all(properties.map(elem => elem.evaluate(async (node) => {
        const nameSlot = node.shadowRoot?.querySelector('.property-name slot');
        const valueSlot = node.shadowRoot?.querySelector('.property-value slot');
        const name = nameSlot?.assignedElements().at(0);
        const value = valueSlot?.assignedElements().at(0);
        return (!name || !value) ? null : {
            name: name.textContent ? name.textContent.trim().replace(/:$/, '') : '',
            value: value.textContent ? value.textContent.trim().replace(/;$/, '') : '',
        };
    }))))
        .filter(prop => !!prop);
};
exports.getAllPropertiesFromComputedPane = getAllPropertiesFromComputedPane;
const getPropertyFromComputedPane = async (name, devToolsPage) => {
    const properties = await devToolsPage.$$(COMPUTED_PROPERTY_SELECTOR);
    for (const property of properties) {
        const matchingProperty = await property.evaluate((node, name) => {
            const nameSlot = node.shadowRoot?.querySelector('.property-name slot');
            const nameEl = nameSlot?.assignedElements().at(0);
            return nameEl?.textContent?.trim().replace(/:$/, '') === name;
        }, name);
        // Note that evaluateHandle always returns a handle, even if it points to an undefined remote object, so we need to
        // check it's defined here or continue iterating.
        if (matchingProperty) {
            return property;
        }
    }
    return undefined;
};
exports.getPropertyFromComputedPane = getPropertyFromComputedPane;
const expandSelectedNodeRecursively = async (devToolsPage) => {
    const EXPAND_RECURSIVELY = '[aria-label="Expand recursively"]';
    // Find the selected node, right click.
    await devToolsPage.click(SELECTED_TREE_ELEMENT_SELECTOR, { clickOptions: { button: 'right' } });
    // Wait for the 'expand recursively' option, and click it.
    await devToolsPage.click(EXPAND_RECURSIVELY);
    await (0, visual_logging_helpers_js_1.expectVeEvents)([
        (0, visual_logging_helpers_js_1.veClick)('Panel: elements > Tree: elements > TreeItem'),
        veImpressionForSelectedNodeMenu(await (0, exports.getContentOfSelectedNode)(devToolsPage)),
        (0, visual_logging_helpers_js_1.veClick)('Panel: elements > Tree: elements > TreeItem > Menu > Action: expand-recursively'),
    ], undefined, devToolsPage);
};
exports.expandSelectedNodeRecursively = expandSelectedNodeRecursively;
const findElementById = async (id, devToolsPage) => {
    await devToolsPage.pressKey('f', { control: true });
    await devToolsPage.waitFor('.search-bar:not(.hidden)');
    await devToolsPage.typeText('#' + id);
    await devToolsPage.pressKey('Enter');
    await devToolsPage.waitFor(`.highlight > .webkit-html-tag[aria-label*="\\"${id}\\"`);
    await devToolsPage.pressKey('Escape');
    await devToolsPage.waitFor('.search-bar.hidden');
};
exports.findElementById = findElementById;
function veImpressionForSelectedNodeMenu(content) {
    const isPseudoElement = content.startsWith('::');
    if (isPseudoElement) {
        return (0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements > Tree: elements > TreeItem', [(0, visual_logging_helpers_js_1.veImpression)('Menu', undefined, [
                (0, visual_logging_helpers_js_1.veImpression)('Action', 'expand-recursively'),
                (0, visual_logging_helpers_js_1.veImpression)('Action', 'scroll-into-view'),
                (0, visual_logging_helpers_js_1.veImpression)('Item', 'show-adorner-settings'),
                (0, visual_logging_helpers_js_1.veImpression)('Action', 'store-as-global-variable'),
            ])]);
    }
    return (0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements > Tree: elements > TreeItem', [(0, visual_logging_helpers_js_1.veImpression)('Menu', undefined, [
            (0, visual_logging_helpers_js_1.veImpression)('Action', 'add-attribute'),
            (0, visual_logging_helpers_js_1.veImpression)('Action', 'collapse-children'),
            (0, visual_logging_helpers_js_1.veImpression)('Action', 'cut'),
            (0, visual_logging_helpers_js_1.veImpression)('Action', 'delete-element'),
            (0, visual_logging_helpers_js_1.veImpression)('Action', 'elements.duplicate-element'),
            (0, visual_logging_helpers_js_1.veImpression)('Action', 'elements.edit-as-html'),
            (0, visual_logging_helpers_js_1.veImpression)('Action', 'emulation.capture-node-screenshot'),
            (0, visual_logging_helpers_js_1.veImpression)('Action', 'expand-recursively'),
            (0, visual_logging_helpers_js_1.veImpression)('Action', 'focus'),
            (0, visual_logging_helpers_js_1.veImpression)('Action', 'paste'),
            (0, visual_logging_helpers_js_1.veImpression)('Action', 'scroll-into-view'),
            (0, visual_logging_helpers_js_1.veImpression)('Item', 'show-adorner-settings'),
            (0, visual_logging_helpers_js_1.veImpression)('Action', 'store-as-global-variable'),
            (0, visual_logging_helpers_js_1.veImpression)('Item', 'break-on'),
            (0, visual_logging_helpers_js_1.veImpression)('Item', 'copy'),
            (0, visual_logging_helpers_js_1.veImpression)('Item', 'force-state'),
            (0, visual_logging_helpers_js_1.veImpression)('Toggle', 'elements.hide-element'),
        ])]);
}
const showForceState = async (specificStates = false, devToolsPage) => {
    // Check if it is already visible
    if (!(await devToolsPage.$(exports.EMULATE_FOCUSED_PAGE, undefined, 'aria'))) {
        await devToolsPage.click('[aria-label="Toggle Element State"]');
        await devToolsPage.waitForAria(exports.EMULATE_FOCUSED_PAGE);
    }
    if (specificStates) {
        const specificStatesPane = await devToolsPage.waitFor('.specific-pseudo-states');
        if (!(await specificStatesPane.evaluate(node => node.checkVisibility()))) {
            await devToolsPage.click('.force-specific-element-header');
            await devToolsPage.waitForVisible('.specific-pseudo-states');
        }
    }
};
exports.showForceState = showForceState;
const forcePseudoState = async (pseudoState, specificStates = false, devToolsPage) => {
    // Open element & page state pane and wait for it to be loaded asynchronously
    await (0, exports.showForceState)(specificStates, devToolsPage);
    const stateEl = await devToolsPage.waitForAria(pseudoState);
    await stateEl.click();
    await (0, visual_logging_helpers_js_1.expectVeEvents)([
        (0, visual_logging_helpers_js_1.veClick)('Panel: elements > Pane: styles > ToggleSubpane: element-states'),
        (0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements > Pane: styles', [(0, visual_logging_helpers_js_1.veImpression)('Pane', 'element-states', [
                (0, visual_logging_helpers_js_1.veImpression)('Action: learn-more'),
                (0, visual_logging_helpers_js_1.veImpression)('Toggle: active'),
                (0, visual_logging_helpers_js_1.veImpression)('Toggle: focus'),
                (0, visual_logging_helpers_js_1.veImpression)('Toggle: focus-visible'),
                (0, visual_logging_helpers_js_1.veImpression)('Toggle: focus-within'),
                (0, visual_logging_helpers_js_1.veImpression)('Toggle: hover'),
                (0, visual_logging_helpers_js_1.veImpression)('Toggle: target'),
            ])]),
        (0, visual_logging_helpers_js_1.veChange)(`Panel: elements > Pane: styles > Pane: element-states > Toggle: ${pseudoState === exports.EMULATE_FOCUSED_PAGE ? 'emulate-page-focus' : pseudoState.substr(1)}`),
    ], undefined, devToolsPage);
};
exports.forcePseudoState = forcePseudoState;
const removePseudoState = async (pseudoState, devToolsPage) => {
    const stateEl = await devToolsPage.waitForAria(pseudoState);
    await stateEl.click();
    await (0, visual_logging_helpers_js_1.expectVeEvents)([
        (0, visual_logging_helpers_js_1.veChange)(`Panel: elements > Pane: styles > Pane: element-states > Toggle: ${pseudoState === exports.EMULATE_FOCUSED_PAGE ? 'emulate-page-focus' : pseudoState.substr(1)}`),
    ], undefined, devToolsPage);
};
exports.removePseudoState = removePseudoState;
const getComputedStylesForDomNode = async (elementSelector, styleAttribute, inspectedPage) => {
    return await inspectedPage.evaluate((elementSelector, styleAttribute) => {
        const element = document.querySelector(elementSelector);
        if (!element) {
            throw new Error(`${elementSelector} could not be found`);
        }
        return getComputedStyle(element)[styleAttribute];
    }, elementSelector, styleAttribute);
};
exports.getComputedStylesForDomNode = getComputedStylesForDomNode;
const waitForNumberOfComputedProperties = async (numberToWaitFor, devToolsPage) => {
    const computedPane = await (0, exports.getComputedPanel)(devToolsPage);
    return await devToolsPage.waitForFunction(async () => numberToWaitFor ===
        await computedPane.$$eval('pierce/' + COMPUTED_PROPERTY_SELECTOR, properties => properties.length));
};
exports.waitForNumberOfComputedProperties = waitForNumberOfComputedProperties;
const getComputedPanel = async (devToolsPage) => {
    return await devToolsPage.waitFor(COMPUTED_STYLES_PANEL_SELECTOR);
};
exports.getComputedPanel = getComputedPanel;
const filterComputedProperties = async (filterString, devToolsPage) => {
    const initialContent = await (0, exports.getContentOfComputedPane)(devToolsPage);
    const computedPanel = await devToolsPage.waitFor(COMPUTED_STYLES_PANEL_SELECTOR);
    await devToolsPage.click('[aria-label="Filter"]', {
        root: computedPanel,
    });
    await devToolsPage.typeText(filterString);
    await (0, exports.waitForComputedPaneChange)(initialContent, devToolsPage);
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veChange)('Panel: elements > Pane: computed > TextField: filter')], undefined, devToolsPage);
};
exports.filterComputedProperties = filterComputedProperties;
const toggleShowAllComputedProperties = async (devToolsPage) => {
    const initialContent = await (0, exports.getContentOfComputedPane)(devToolsPage);
    const computedPanel = await devToolsPage.waitFor(COMPUTED_STYLES_PANEL_SELECTOR);
    await devToolsPage.click(COMPUTED_STYLES_SHOW_ALL_SELECTOR, { root: computedPanel });
    await (0, exports.waitForComputedPaneChange)(initialContent, devToolsPage);
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veChange)('Panel: elements > Pane: computed > Toggle: show-inherited-computed-style-properties')], undefined, devToolsPage);
};
exports.toggleShowAllComputedProperties = toggleShowAllComputedProperties;
const waitForDomNodeToBeVisible = async (elementSelector, inspectedPage) => {
    // DevTools will force Blink to make the hover shown, so we have
    // to wait for the element to be DOM-visible (e.g. no `display: none;`)
    await inspectedPage.waitForSelector(elementSelector, { visible: true });
};
exports.waitForDomNodeToBeVisible = waitForDomNodeToBeVisible;
const waitForDomNodeToBeHidden = async (elementSelector, inspectedPage) => {
    await inspectedPage.waitForSelector(elementSelector, { hidden: true });
};
exports.waitForDomNodeToBeHidden = waitForDomNodeToBeHidden;
const assertGutterDecorationForDomNodeExists = async (devToolsPage) => {
    await devToolsPage.waitFor('.elements-gutter-decoration');
};
exports.assertGutterDecorationForDomNodeExists = assertGutterDecorationForDomNodeExists;
const getStyleRuleSelector = (selector) => `[aria-label="${selector}, css selector"]`;
exports.getStyleRuleSelector = getStyleRuleSelector;
const waitForExactStyleRule = async (expectedSelector, devToolsPage) => {
    await devToolsPage.waitForFunction(async () => {
        const rules = await (0, exports.getDisplayedStyleRules)(devToolsPage);
        return rules.find(rule => rule.selectorText === expectedSelector);
    });
};
exports.waitForExactStyleRule = waitForExactStyleRule;
const waitForStyleRule = async (expectedSelector, devToolsPage) => {
    await devToolsPage.waitForFunction(async () => {
        const rules = await (0, exports.getDisplayedStyleRules)(devToolsPage);
        return rules.map(rule => rule.selectorText).includes(expectedSelector);
    });
};
exports.waitForStyleRule = waitForStyleRule;
const getComputedStyleProperties = async (devToolsPage) => {
    const computedPanel = await (0, exports.getComputedPanel)(devToolsPage);
    const allProperties = await computedPanel.$$('pierce/[role="treeitem"][aria-level="1"]');
    const properties = [];
    for (const prop of allProperties) {
        const name = await prop.$eval('pierce/' + CSS_PROPERTY_NAME_SELECTOR, element => element.textContent);
        const value = await prop.$eval('pierce/' + CSS_PROPERTY_VALUE_SELECTOR, element => element.textContent);
        const traceElements = await prop.$$('pierce/devtools-computed-style-trace');
        const trace = await Promise.all(traceElements.map(async (element) => {
            const value = await element.$eval('pierce/.value', element => element.textContent);
            const selector = await element.$eval('pierce/.trace-selector', element => element.textContent);
            const link = await element.$eval('pierce/.trace-link', element => element.textContent);
            return { value, selector, link };
        }));
        properties.push({ name, value, trace });
    }
    return properties;
};
exports.getComputedStyleProperties = getComputedStyleProperties;
const getDisplayedCSSDeclarations = async (devtoolsPage) => {
    const cssDeclarations = await devtoolsPage.$$(CSS_DECLARATION_SELECTOR);
    return await Promise.all(cssDeclarations.map(async (node) => await node.evaluate(n => n.textContent?.trim())));
};
exports.getDisplayedCSSDeclarations = getDisplayedCSSDeclarations;
const getDisplayedStyleRulesCompact = async (devToolsPage) => {
    const compactRules = [];
    for (const rule of await (0, exports.getDisplayedStyleRules)(devToolsPage)) {
        compactRules.push({ selectorText: rule.selectorText, propertyNames: rule.propertyData.map(data => data.propertyName) });
    }
    return compactRules;
};
exports.getDisplayedStyleRulesCompact = getDisplayedStyleRulesCompact;
const getDisplayedStyleRules = async (devToolsPage) => {
    const allRuleSelectors = await devToolsPage.$$(CSS_STYLE_RULE_SELECTOR);
    const rules = [];
    for (const ruleSelector of allRuleSelectors) {
        const propertyData = await (0, exports.getDisplayedCSSPropertyData)(ruleSelector, devToolsPage);
        const selectorText = await ruleSelector.evaluate(node => {
            const attribute = node.getAttribute('aria-label') || '';
            return attribute.substring(0, attribute.lastIndexOf(', css selector'));
        });
        rules.push({ selectorText, propertyData });
    }
    return rules;
};
exports.getDisplayedStyleRules = getDisplayedStyleRules;
/**
 * @param propertiesSection The element containing this properties section.
 * @returns an array with an entry for each property in the section. Each entry has:
 * - propertyName: The name of this property.
 * - isOverloaded: True if this is an inherited properties section, and this property is overloaded by a child node.
 *                 The property will be shown as crossed out in the style pane.
 * - isInherited: True if this is an inherited properties section, and this property is a non-inherited CSS property.
 *                The property will be shown as grayed-out in the style pane.
 */
const getDisplayedCSSPropertyData = async (propertiesSection, devToolsPage) => {
    const cssPropertyNames = await devToolsPage.$$(CSS_PROPERTY_NAME_SELECTOR, propertiesSection);
    const propertyNamesData = (await Promise.all(cssPropertyNames.map(async (node) => {
        return {
            propertyName: await node.evaluate(n => n.textContent),
            isOverLoaded: await node.evaluate(n => n.parentElement?.matches('.overloaded')),
            isInherited: await node.evaluate(n => n.parentElement?.matches('.inherited')),
        };
    })))
        .filter(c => !!c.propertyName);
    return propertyNamesData;
};
exports.getDisplayedCSSPropertyData = getDisplayedCSSPropertyData;
const getDisplayedCSSPropertyNames = async (propertiesSection, devToolsPage) => {
    const cssPropertyNames = await devToolsPage.$$(CSS_PROPERTY_NAME_SELECTOR, propertiesSection);
    const propertyNamesText = (await Promise.all(cssPropertyNames.map(node => node.evaluate(n => n.textContent))))
        .filter(c => !!c);
    return propertyNamesText;
};
exports.getDisplayedCSSPropertyNames = getDisplayedCSSPropertyNames;
const getStyleRule = (selector, devToolsPage) => {
    return devToolsPage.waitFor((0, exports.getStyleRuleSelector)(selector));
};
exports.getStyleRule = getStyleRule;
const getStyleRuleWithSourcePosition = (styleSelector, sourcePosition, devToolsPage) => {
    if (!sourcePosition) {
        return (0, exports.getStyleRule)(styleSelector, devToolsPage);
    }
    const selector = (0, exports.getStyleRuleSelector)(styleSelector);
    return devToolsPage.waitForFunction(async () => {
        const candidate = await devToolsPage.waitFor(selector);
        if (candidate) {
            const sourcePositionElement = await candidate.$('.styles-section-subtitle .devtools-link');
            const text = await sourcePositionElement?.evaluate(node => node.textContent);
            if (text === sourcePosition) {
                return candidate;
            }
        }
        return undefined;
    });
};
exports.getStyleRuleWithSourcePosition = getStyleRuleWithSourcePosition;
const getColorSwatch = async (parent, index, devToolsPage) => {
    const swatches = await devToolsPage.$$(COLOR_SWATCH_SELECTOR, parent);
    return swatches[index];
};
exports.getColorSwatch = getColorSwatch;
const getColorSwatchColor = async (parent, index, devToolsPage) => {
    const swatch = await devToolsPage.waitForFunction(() => (0, exports.getColorSwatch)(parent, index, devToolsPage));
    return await swatch.evaluate(node => node.style.backgroundColor);
};
exports.getColorSwatchColor = getColorSwatchColor;
const shiftClickColorSwatch = async (parent, index, parentVe, devToolsPage) => {
    const swatch = await (0, exports.getColorSwatch)(parent, index, devToolsPage);
    await devToolsPage.clickElement(swatch, { modifiers: { shift: true } });
    await (0, visual_logging_helpers_js_1.expectVeEvents)([
        (0, visual_logging_helpers_js_1.veClick)(`${parentVe} > ShowStyleEditor: color`),
        (0, visual_logging_helpers_js_1.veImpressionsUnder)(`${parentVe} > ShowStyleEditor: color`, [(0, visual_logging_helpers_js_1.veImpression)('Menu', undefined, [(0, visual_logging_helpers_js_1.veImpression)('Action', 'clipped-color'), (0, visual_logging_helpers_js_1.veImpression)('Item', 'color')])]),
    ], undefined, devToolsPage);
};
exports.shiftClickColorSwatch = shiftClickColorSwatch;
const getStyleSectionSubtitles = async (devToolsPage) => {
    const subtitles = await devToolsPage.$$(exports.SECTION_SUBTITLE_SELECTOR);
    return await Promise.all(subtitles.map(node => node.evaluate(n => n.textContent)));
};
exports.getStyleSectionSubtitles = getStyleSectionSubtitles;
const getCSSPropertyInRule = async (ruleSection, name, sourcePosition = undefined, devToolsPage) => {
    if (typeof ruleSection === 'string') {
        ruleSection = await (0, exports.getStyleRuleWithSourcePosition)(ruleSection, sourcePosition, devToolsPage);
    }
    const propertyNames = await devToolsPage.$$(CSS_PROPERTY_NAME_SELECTOR, ruleSection);
    for (const node of propertyNames) {
        const parent = (await node.evaluateHandle((node, name) => (name === node.textContent) ? node.parentNode : undefined, name))
            .asElement();
        if (parent) {
            return parent;
        }
    }
    return undefined;
};
exports.getCSSPropertyInRule = getCSSPropertyInRule;
const focusCSSPropertyValue = async (selector, propertyName, devToolsPage) => {
    await (0, exports.waitForStyleRule)(selector, devToolsPage);
    await devToolsPage.timeout(100);
    let property = await (0, exports.getCSSPropertyInRule)(selector, propertyName, undefined, devToolsPage);
    chai_1.assert.isOk(property, `Could not find property ${propertyName} in rule ${selector}`);
    // Clicking on the semicolon element to make sure we don't hit the swatch or other
    // non-editable elements.
    await devToolsPage.click(CSS_PROPERTY_VALUE_SELECTOR + ' + .styles-semicolon', { root: property });
    await devToolsPage.waitForFunction(async () => {
        property = await (0, exports.getCSSPropertyInRule)(selector, propertyName, undefined, devToolsPage);
        const value = property ? await devToolsPage.$(CSS_PROPERTY_VALUE_SELECTOR, property) : null;
        chai_1.assert.isOk(value, `Could not find property ${propertyName} in rule ${selector}`);
        return await value.evaluate(node => {
            return node.classList.contains('text-prompt') && node.hasAttribute('contenteditable');
        });
    });
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veClick)(`Panel: elements > Pane: styles > Section: style-properties > Tree > TreeItem: ${propertyName.startsWith('--') ? 'custom-property' : propertyName}`)], undefined, devToolsPage);
};
exports.focusCSSPropertyValue = focusCSSPropertyValue;
/**
 * Edit a CSS property value in a given rule
 * @param selector The selector of the rule to be updated. Note that because of the way the Styles populates, it is
 * important to provide a rule selector that is unique here, to avoid editing a property in the wrong rule.
 * @param propertyName The name of the property to be found and edited. If several properties have the same names, the
 * first one is edited.
 * @param newValue The new value to be used.
 */
async function editCSSProperty(selector, propertyName, newValue, devToolsPage) {
    await (0, exports.focusCSSPropertyValue)(selector, propertyName, devToolsPage);
    await devToolsPage.typeText(newValue, { delay: 100 });
    await devToolsPage.pressKey('Enter');
    await devToolsPage.waitForFunction(async () => {
        // Wait until the value element is not a text-prompt anymore.
        const property = await (0, exports.getCSSPropertyInRule)(selector, propertyName, undefined, devToolsPage);
        const value = property ? await devToolsPage.$(CSS_PROPERTY_VALUE_SELECTOR, property) : null;
        chai_1.assert.isOk(value, `Could not find property ${propertyName} in rule ${selector}`);
        return await value.evaluate(node => {
            return !node.classList.contains('text-prompt') && !node.hasAttribute('contenteditable');
        });
    });
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veChange)(`Panel: elements > Pane: styles > Section: style-properties > Tree > TreeItem: ${propertyName.startsWith('--') ? 'custom-property' : propertyName} > Value`)], undefined, devToolsPage);
}
/** Edit a media or container query rule text for the given styles section **/
async function editQueryRuleText(queryStylesSections, newQueryText, devToolsPage, willDelete = false) {
    await devToolsPage.click(STYLE_QUERY_RULE_TEXT_SELECTOR, { root: queryStylesSections });
    // TODO: it should actually wait for rendering to finish.
    await devToolsPage.drainTaskQueue();
    await devToolsPage.waitForFunction(async () => {
        // Wait until the value element has been marked as a text-prompt.
        const queryText = await devToolsPage.$(STYLE_QUERY_RULE_TEXT_SELECTOR, queryStylesSections);
        chai_1.assert.isOk(queryText, 'Could not find any query in the given styles section');
        const check = await queryText.evaluate(node => {
            return node.classList.contains('being-edited') && node.hasAttribute('contenteditable');
        });
        return check;
    });
    await devToolsPage.typeText(newQueryText);
    await devToolsPage.pressKey('Enter');
    // TODO: it should actually wait for rendering to finish.
    await devToolsPage.drainTaskQueue();
    if (willDelete) {
        await devToolsPage.waitForFunction(async () => await queryStylesSections.evaluate(node => !node.isConnected));
    }
    else {
        await devToolsPage.waitForFunction(async () => {
            // Wait until the value element is not a text-prompt anymore.
            const queryText = await devToolsPage.$(STYLE_QUERY_RULE_TEXT_SELECTOR, queryStylesSections);
            chai_1.assert.isOk(queryText, 'Could not find any query in the given styles section');
            const check = await queryText.evaluate(node => {
                return !node.classList.contains('being-edited') && !node.hasAttribute('contenteditable');
            });
            return check;
        });
    }
    await (0, visual_logging_helpers_js_1.expectVeEvents)([
        (0, visual_logging_helpers_js_1.veClick)('Panel: elements > Pane: styles > Section: style-properties > CSSRuleHeader: container-query'),
        (0, visual_logging_helpers_js_1.veChange)('Panel: elements > Pane: styles > Section: style-properties > CSSRuleHeader: container-query'),
    ], undefined, devToolsPage);
}
async function waitForCSSPropertyValue(selector, name, value, sourcePosition, devToolsPage) {
    return await devToolsPage.waitForFunction(async () => {
        const propertyHandle = await (0, exports.getCSSPropertyInRule)(selector, name, sourcePosition, devToolsPage);
        if (!propertyHandle) {
            return undefined;
        }
        const valueHandle = await devToolsPage.$(CSS_PROPERTY_VALUE_SELECTOR, propertyHandle);
        if (!valueHandle) {
            return undefined;
        }
        const matches = await valueHandle.evaluate((node, value) => ((node instanceof HTMLElement ? node.innerText : '') || node.textContent) === value, value);
        if (matches) {
            return valueHandle;
        }
        return undefined;
    });
}
async function waitForPropertyToHighlight(ruleSelector, propertyName, devToolsPage) {
    await devToolsPage.waitForFunction(async () => {
        const property = await (0, exports.getCSSPropertyInRule)(ruleSelector, propertyName, undefined, devToolsPage);
        chai_1.assert.isOk(property, `Could not find property ${propertyName} in rule ${ruleSelector}`);
        // StylePropertyHighlighter temporarily highlights the property using the Web Animations API, so the only way to
        // know it's happening is by listing all animations.
        const animationCount = await property.evaluate(node => node.getAnimations().length);
        return animationCount > 0;
    });
}
const getBreadcrumbsTextContent = async ({ expectedNodeCount }, devToolsPage) => {
    const crumbsSelector = 'li.crumb > a > devtools-node-text';
    await devToolsPage.waitForFunction(async () => {
        const crumbs = await devToolsPage.$$(crumbsSelector);
        return crumbs.length === expectedNodeCount;
    });
    const crumbs = await devToolsPage.$$(crumbsSelector);
    const crumbsAsText = await Promise.all(crumbs.map(node => node.evaluate(node => {
        if (!node.shadowRoot) {
            throw new Error('Found breadcrumbs node that unexpectedly has no shadowRoot.');
        }
        return Array.from(node.shadowRoot.querySelectorAll('span') || []).map(span => span.textContent).join('');
    })));
    return crumbsAsText;
};
exports.getBreadcrumbsTextContent = getBreadcrumbsTextContent;
const getSelectedBreadcrumbTextContent = async (devToolsPage) => {
    const selectedCrumb = await devToolsPage.waitFor('li.crumb.selected > a > devtools-node-text');
    const text = selectedCrumb.evaluate(node => {
        if (!node.shadowRoot) {
            throw new Error('Found breadcrumbs node that unexpectedly has no shadowRoot.');
        }
        return Array.from(node.shadowRoot.querySelectorAll('span') || []).map(span => span.textContent).join('');
    });
    return await text;
};
exports.getSelectedBreadcrumbTextContent = getSelectedBreadcrumbTextContent;
const navigateToElementsTab = async (devtoolsPage, options) => {
    if ((await devtoolsPage.$$(exports.ELEMENTS_PANEL_SELECTOR)).length) {
        return;
    }
    // Open Elements panel
    await devtoolsPage.click('#tab-elements');
    await devtoolsPage.waitFor(exports.ELEMENTS_PANEL_SELECTOR);
    await devtoolsPage.timeout(100);
    if (!options?.expectExistingPanel) {
        await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veImpressionForElementsPanel)(options)], undefined, devtoolsPage);
    }
};
exports.navigateToElementsTab = navigateToElementsTab;
const clickOnFirstLinkInStylesPanel = async (devToolsPage) => {
    const stylesPane = await devToolsPage.waitFor('div.styles-pane');
    await devToolsPage.click('div.styles-section-subtitle button.devtools-link', { root: stylesPane });
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veClick)('Panel: elements > Pane: styles > Section: style-properties > Link: css-location')], undefined, devToolsPage);
};
exports.clickOnFirstLinkInStylesPanel = clickOnFirstLinkInStylesPanel;
const toggleClassesPane = async (devToolsPage) => {
    const stylesPane = await devToolsPage.waitFor('div.styles-pane');
    await devToolsPage.waitFor(CLS_BUTTON_SELECTOR, stylesPane);
    // Add a wait for TOGGLE_COMMON_RENDERING_EMULATIONS_SELECTOR so that the toolbar is stable before
    // clicking on CLS_BUTTON_SELECTOR
    await devToolsPage.waitFor(TOGGLE_COMMON_RENDERING_EMULATIONS_SELECTOR, stylesPane);
    await devToolsPage.click(CLS_BUTTON_SELECTOR, { root: stylesPane });
    await devToolsPage.waitFor('.styles-element-classes-pane .text-prompt', stylesPane); // wait for the animation
    await (0, visual_logging_helpers_js_1.expectVeEvents)([
        (0, visual_logging_helpers_js_1.veClick)('Panel: elements > Pane: styles > ToggleSubpane: elements-classes'),
        (0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements > Pane: styles', [(0, visual_logging_helpers_js_1.veImpression)('Pane', 'elements-classes', [(0, visual_logging_helpers_js_1.veImpression)('TextField')])]),
    ], undefined, devToolsPage);
};
exports.toggleClassesPane = toggleClassesPane;
const typeInClassesPaneInput = async (text, devToolsPage, commitWith = 'Enter', waitForNodeChange = true) => {
    await (0, helper_js_1.step)(`Typing in new class names ${text}`, async () => {
        await devToolsPage.click(CLS_INPUT_SELECTOR);
        await devToolsPage.typeText(text, { delay: 50 });
    });
    if (commitWith) {
        await (0, helper_js_1.step)(`Committing the changes with ${commitWith}`, async () => {
            await devToolsPage.pressKey(commitWith);
        });
    }
    if (waitForNodeChange) {
        // Make sure the classes provided in text can be found in the selected element's content. This is important as the
        // cls pane applies classes as you type, so it is not enough to wait for the selected node to change just once.
        await (0, helper_js_1.step)('Waiting for the selected node to change', async () => {
            await devToolsPage.waitForFunction(async () => {
                const nodeContent = await (0, exports.getContentOfSelectedNode)(devToolsPage);
                return text.split(' ').every(cls => nodeContent.includes(cls));
            });
        });
    }
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veChange)('Panel: elements > Pane: styles > Pane: elements-classes > TextField')], undefined, devToolsPage);
};
exports.typeInClassesPaneInput = typeInClassesPaneInput;
const toggleClassesPaneCheckbox = async (checkboxLabel, devToolsPage) => {
    const initialValue = await (0, exports.getContentOfSelectedNode)(devToolsPage);
    const classesPane = await devToolsPage.waitFor(CLS_PANE_SELECTOR);
    await devToolsPage.click(`[title="${checkboxLabel}"]`, { root: classesPane });
    const nodeChange = (0, exports.waitForSelectedNodeChange)(initialValue, devToolsPage);
    const veEvents = (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veChange)('Panel: elements > Pane: styles > Pane: elements-classes > Toggle: element-class')], undefined, devToolsPage);
    await Promise.all([nodeChange, veEvents]);
};
exports.toggleClassesPaneCheckbox = toggleClassesPaneCheckbox;
const uncheckStylesPaneCheckbox = async (checkboxLabel, devToolsPage) => {
    console.error('uncheckStylesPaneCheckbox', checkboxLabel);
    const initialValue = await (0, exports.getContentOfSelectedNode)(devToolsPage);
    await devToolsPage.click(`.enabled-button[aria-label="${checkboxLabel}"]`);
    await (0, exports.waitForSelectedNodeChange)(initialValue, devToolsPage);
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veClick)(`Panel: elements > Pane: styles > Section: style-properties > Tree > TreeItem: ${checkboxLabel.split(' ')[0]} > Toggle`)], undefined, devToolsPage);
};
exports.uncheckStylesPaneCheckbox = uncheckStylesPaneCheckbox;
const assertSelectedNodeClasses = async (expectedClasses, devToolsPage) => {
    const nodeText = await (0, exports.getContentOfSelectedNode)(devToolsPage);
    const match = nodeText.match(/class=\u200B"([^"]*)/);
    const classText = match ? match[1] : '';
    const classes = classText.split(/[\s]/).map(className => className.trim()).filter(className => className.length);
    chai_1.assert.strictEqual(classes.length, expectedClasses.length, 'Did not find the expected number of classes on the element');
    for (const expectedClass of expectedClasses) {
        chai_1.assert.include(classes, expectedClass, `Could not find class ${expectedClass} on the element`);
    }
};
exports.assertSelectedNodeClasses = assertSelectedNodeClasses;
const toggleAccessibilityPane = async (devToolsPage) => {
    let a11yPane = await devToolsPage.$('Accessibility', undefined, 'aria');
    if (!a11yPane) {
        const elementsPanel = await devToolsPage.waitForAria('Elements panel');
        await devToolsPage.clickMoreTabsButton(elementsPanel);
        a11yPane = await devToolsPage.waitForAria('Accessibility');
        await (0, visual_logging_helpers_js_1.expectVeEvents)([
            (0, visual_logging_helpers_js_1.veClick)('Panel: elements > Toolbar: sidebar > DropDown: more-tabs'),
            (0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements > Toolbar: sidebar > DropDown: more-tabs', [(0, visual_logging_helpers_js_1.veImpression)('Menu', undefined, [(0, visual_logging_helpers_js_1.veImpression)('Action', 'accessibility.view')])]),
        ], undefined, devToolsPage);
    }
    await devToolsPage.click('aria/Accessibility');
    await devToolsPage.waitFor('.source-order-checkbox');
    await devToolsPage.waitFor('[aria-label="ARIA Attributes"]');
    await devToolsPage.waitFor('[aria-label="Computed Properties"]');
    await (0, visual_logging_helpers_js_1.expectVeEvents)([
        (0, visual_logging_helpers_js_1.veClick)('Panel: elements > Toolbar: sidebar > DropDown: more-tabs > Menu > Action: accessibility.view'),
        (0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements > Toolbar: sidebar', [(0, visual_logging_helpers_js_1.veImpression)('PanelTabHeader', 'accessibility.view')]),
        veImpressionForAccessibilityPane(),
    ], undefined, devToolsPage);
};
exports.toggleAccessibilityPane = toggleAccessibilityPane;
function veImpressionForAccessibilityPane() {
    const result = (0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements', [(0, visual_logging_helpers_js_1.veImpression)('Pane', 'sidebar', [
            (0, visual_logging_helpers_js_1.veImpression)('SectionHeader', 'aria-attributes'),
            (0, visual_logging_helpers_js_1.veImpression)('Section', 'aria-attributes'),
            (0, visual_logging_helpers_js_1.veImpression)('SectionHeader', 'computed-properties'),
            (0, visual_logging_helpers_js_1.veImpression)('Section', 'computed-properties', [(0, visual_logging_helpers_js_1.veImpression)('Tree', undefined, [(0, visual_logging_helpers_js_1.veImpression)('TreeItem')])]),
            (0, visual_logging_helpers_js_1.veImpression)('SectionHeader', 'source-order-viewer'),
            (0, visual_logging_helpers_js_1.veImpression)('Section', 'source-order-viewer', [(0, visual_logging_helpers_js_1.veImpression)('Toggle')]),
        ])]);
    result.impressions.push('Panel: elements > Toggle: elements.toggle-a11y-tree');
    return result;
}
const toggleAccessibilityTree = async (devToolsPage) => {
    await (0, exports.toggleAccessibilityPane)(devToolsPage);
    await devToolsPage.click('aria/Show accessibility tree');
    await (0, visual_logging_helpers_js_1.expectVeEvents)([(0, visual_logging_helpers_js_1.veChange)('Panel: elements > Toggle: elements.toggle-a11y-tree')], undefined, devToolsPage);
};
exports.toggleAccessibilityTree = toggleAccessibilityTree;
const getPropertiesWithHints = async (devToolsPage) => {
    const allRuleSelectors = await devToolsPage.$$(CSS_STYLE_RULE_SELECTOR);
    const propertiesWithHints = [];
    for (const propertiesSection of allRuleSelectors) {
        const cssRuleNodes = await devToolsPage.$$('li ', propertiesSection);
        for (const cssRuleNode of cssRuleNodes) {
            const propertyNode = await devToolsPage.$(CSS_PROPERTY_NAME_SELECTOR, cssRuleNode);
            const propertyName = propertyNode !== null ? await propertyNode.evaluate(n => n.textContent) : null;
            if (propertyName === null) {
                continue;
            }
            const authoringHintsIcon = await devToolsPage.$(CSS_AUTHORING_HINTS_ICON_SELECTOR, cssRuleNode);
            if (authoringHintsIcon) {
                propertiesWithHints.push(propertyName);
            }
        }
    }
    return propertiesWithHints;
};
exports.getPropertiesWithHints = getPropertiesWithHints;
const summonAndWaitForSearchBox = async (devToolsPage) => {
    // Wait for elements to load.
    await devToolsPage.waitFor('devtools-elements-breadcrumbs');
    await devToolsPage.summonSearchBox();
    await devToolsPage.waitFor(exports.SEARCH_BOX_SELECTOR);
    await (0, visual_logging_helpers_js_1.expectVeEvents)([
        (0, visual_logging_helpers_js_1.veKeyDown)(''),
        (0, visual_logging_helpers_js_1.veImpressionsUnder)('Panel: elements', [(0, visual_logging_helpers_js_1.veImpression)('Toolbar', 'search', [
                (0, visual_logging_helpers_js_1.veImpression)('Action: close-search'),
                (0, visual_logging_helpers_js_1.veImpression)('Action: select-next'),
                (0, visual_logging_helpers_js_1.veImpression)('Action: select-previous'),
                (0, visual_logging_helpers_js_1.veImpression)('TextField: search'),
            ])]),
    ], undefined, devToolsPage);
};
exports.summonAndWaitForSearchBox = summonAndWaitForSearchBox;
const assertSearchResultMatchesText = async (text, devToolsPage) => {
    await devToolsPage.waitForFunction(async () => {
        return await devToolsPage.getTextContent(SEARCH_RESULTS_MATCHES) === text;
    });
};
exports.assertSearchResultMatchesText = assertSearchResultMatchesText;
const goToResourceAndWaitForStyleSection = async (path, devToolsPage, inspectedPage) => {
    await inspectedPage.goToResource(path);
    await (0, exports.waitForElementsStyleSection)(null, devToolsPage);
};
exports.goToResourceAndWaitForStyleSection = goToResourceAndWaitForStyleSection;
const checkStyleAttributes = async (expectedStyles, devToolsPage) => {
    const result = await devToolsPage.$$(exports.STYLE_PROPERTIES_SELECTOR, undefined, 'pierce');
    const actual = await Promise.all(result.map(e => e.evaluate(e => e.textContent?.trim())));
    return actual.sort().join(' ') === expectedStyles.sort().join(' ');
};
exports.checkStyleAttributes = checkStyleAttributes;
exports.TEXT_PROMPT_GHOST_TEXT_SELECTOR = '.auto-complete-text';
exports.GHOST_VALUE_PREDICTION_SELECTOR = '.ghost-value-prediction';
exports.GHOST_ROW_SELECTOR = '.ghost-row';
const mockAidaCodeComplete = async (devToolsPage, response) => {
    await devToolsPage.evaluate(responseString => {
        if (!window.InspectorFrontendHost) {
            return;
        }
        window.InspectorFrontendHost.aidaCodeComplete = (request, callback) => {
            window.__lastAidaRequest = request;
            callback({ response: responseString });
        };
    }, JSON.stringify(response));
};
exports.mockAidaCodeComplete = mockAidaCodeComplete;
const getLastAidaRequest = async (devToolsPage) => {
    return await devToolsPage.evaluate(() => {
        return window.__lastAidaRequest;
    });
};
exports.getLastAidaRequest = getLastAidaRequest;
const getGhostTextInCurrentTextPrompt = async (devToolsPage) => {
    const ghostElement = await devToolsPage.waitFor(exports.TEXT_PROMPT_GHOST_TEXT_SELECTOR);
    if (!ghostElement) {
        return null;
    }
    return await ghostElement.evaluate(node => node.textContent);
};
exports.getGhostTextInCurrentTextPrompt = getGhostTextInCurrentTextPrompt;
const getGhostText = async (devToolsPage) => {
    const ghostElement = await devToolsPage.waitFor(exports.GHOST_VALUE_PREDICTION_SELECTOR);
    if (!ghostElement) {
        return null;
    }
    return await ghostElement.evaluate(node => node.textContent);
};
exports.getGhostText = getGhostText;
const getMultilineGhostElements = async (devToolsPage) => {
    await devToolsPage.waitFor(exports.GHOST_ROW_SELECTOR);
    const ghostRows = await devToolsPage.$$(exports.GHOST_ROW_SELECTOR);
    return await Promise.all(ghostRows.map(row => row.evaluate(node => node.textContent)));
};
exports.getMultilineGhostElements = getMultilineGhostElements;
//# sourceMappingURL=elements-helpers.js.map