/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; // Test for autocomplete of CSS variables in the Rules view. const IFRAME_URL = `https://example.org/document-builder.sjs?html=${encodeURIComponent(`

iframe

`)}`; const TEST_URI = `https://example.org/document-builder.sjs?html=

Hello world

`; add_task(async function () { await pushPref("layout.css.properties-and-values.enabled", true); await addTab(TEST_URI); const { inspector, view } = await openRuleView(); await selectNode("h1", inspector); info("Wait for @property panel to be displayed"); await waitFor(() => view.styleDocument.querySelector("#registered-properties-container") ); const topLevelVariables = [ { label: "--css", postLabel: "rgb(255, 0, 0)", hasColorSwatch: true }, { label: "--js", postLabel: "gold", hasColorSwatch: true }, { label: "--nested", postLabel: "rgb(255, 215, 0)", hasColorSwatch: true }, { label: "--nested-with-function", postLabel: "color-mix(in srgb, rgb(255, 0, 0) 50%, blue)", hasColorSwatch: true, }, { label: "--not-registered", postLabel: "blue", hasColorSwatch: true }, ]; await checkNewPropertyCssVariableAutocomplete(view, topLevelVariables); await checkCssVariableAutocomplete( view, getTextProperty(view, 1, { color: "gold" }).editor.valueSpan, topLevelVariables ); info( "Check that the list is correct when selecting a node from another document" ); await selectNodeInFrames(["iframe", "h1"], inspector); const iframeVariables = [ { label: "--iframe" }, { label: "--iframe-not-registered", postLabel: "turquoise", hasColorSwatch: true, }, ]; await checkNewPropertyCssVariableAutocomplete(view, iframeVariables); await checkCssVariableAutocomplete( view, getTextProperty(view, 1, { color: "tomato" }).editor.valueSpan, iframeVariables ); }); async function checkNewPropertyCssVariableAutocomplete( view, expectedPopupItems ) { const ruleEditor = getRuleViewRuleEditor(view, 1); const editor = await focusNewRuleViewProperty(ruleEditor); const onPopupOpen = editor.popup.once("popup-opened"); EventUtils.sendString("--"); await onPopupOpen; assertEditorPopupItems( editor, // we don't display postLabel for the new property expectedPopupItems.map(item => ({ label: item.label })) ); info("Close the popup"); const onPopupClosed = once(editor.popup, "popup-closed"); EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow); await onPopupClosed; info("Close the editor"); EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow); } async function checkCssVariableAutocomplete( view, inplaceEditorEl, expectedPopupItems ) { const editor = await focusEditableField(view, inplaceEditorEl); await wait(500); const onCloseParenthesisAppended = editor.once("after-suggest"); EventUtils.sendString("var("); await onCloseParenthesisAppended; let onRuleViewChanged = view.once("ruleview-changed"); EventUtils.sendString("--"); const onPopupOpen = editor.popup.once("popup-opened"); view.debounce.flush(); await onPopupOpen; assertEditorPopupItems(editor, expectedPopupItems); await onRuleViewChanged; info("Close the popup"); const onPopupClosed = once(editor.popup, "popup-closed"); EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow); await onPopupClosed; info("Cancel"); onRuleViewChanged = view.once("ruleview-changed"); EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow); await onRuleViewChanged; view.debounce.flush(); } /** * Check that the popup items are the expected ones. * * @param {InplaceEditor} editor * @param {Array{Object}} expectedPopupItems */ function assertEditorPopupItems(editor, expectedPopupItems) { const popupListItems = Array.from(editor.popup.list.querySelectorAll("li")); is( popupListItems.length, expectedPopupItems.length, "Popup has expected number of items" ); popupListItems.forEach((li, i) => { const expected = expectedPopupItems[i]; const value = (li.querySelector(".initial-value")?.textContent ?? "") + li.querySelector(".autocomplete-value").textContent; is(value, expected.label, `Popup item #${i} as expected label`); // Don't pollute test logs if we don't have the expected variable if (value !== expected.label) { return; } const postLabelEl = li.querySelector(".autocomplete-postlabel"); is( li.querySelector(".autocomplete-postlabel")?.textContent, expected.postLabel, `${expected.label} has expected post label` ); is( !!postLabelEl?.querySelector(".autocomplete-swatch"), !!expected.hasColorSwatch, `${expected.label} ${ expected.hasColorSwatch ? "has" : "does not have" } a post label color swatch` ); }); }