browser_rules_completion-new-property_multiline.js (5355B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // Test the behaviour of the CSS autocomplete for CSS value displayed on 7 // multiple lines. Expected behavior is: 8 // - UP/DOWN should navigate in the input and not increment/decrement numbers 9 // - typing a new value should still trigger the autocomplete 10 // - UP/DOWN when the autocomplete popup is displayed should cycle through 11 // suggestions 12 13 const LONG_CSS_VALUE = 14 "transparent linear-gradient(0deg, blue 0%, white 5%, red 10%, blue 15%, " + 15 "white 20%, red 25%, blue 30%, white 35%, red 40%, blue 45%, white 50%, " + 16 "red 55%, blue 60%, white 65%, red 70%, blue 75%, white 80%, red 85%, " + 17 "blue 90%, white 95% ) repeat scroll 0% 0%"; 18 19 const EXPECTED_CSS_VALUE = LONG_CSS_VALUE.replace("95%", "95%, red"); 20 21 const TEST_URI = `<style> 22 .title { 23 background: ${LONG_CSS_VALUE}; 24 } 25 </style> 26 <h1 class=title>Header</h1>`; 27 28 add_task(async function () { 29 await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); 30 const { inspector, view } = await openRuleView(); 31 32 info("Selecting the test node"); 33 await selectNode("h1", inspector); 34 35 info("Focusing the property editable field"); 36 const prop = getTextProperty(view, 1, { background: LONG_CSS_VALUE }); 37 38 // Calculate offsets to click in the middle of the first box quad. 39 const rect = prop.editor.valueSpan.getBoundingClientRect(); 40 const firstQuadBounds = prop.editor.valueSpan.getBoxQuads()[0].getBounds(); 41 // For a multiline value, the first quad left edge is not aligned with the 42 // bounding rect left edge. The offsets expected by focusEditableField are 43 // relative to the bouding rectangle, so we need to translate the x-offset. 44 const x = firstQuadBounds.left - rect.left + firstQuadBounds.width / 2; 45 // The first quad top edge is aligned with the bounding top edge, no 46 // translation needed here. 47 const y = firstQuadBounds.height / 2; 48 49 info("Focusing the css property editable value"); 50 const editor = await focusEditableField(view, prop.editor.valueSpan, x, y); 51 52 info("Moving the caret next to a number"); 53 let pos = editor.input.value.indexOf("0deg") + 1; 54 editor.input.setSelectionRange(pos, pos); 55 is( 56 editor.input.value[editor.input.selectionStart - 1], 57 "0", 58 "Input caret is after a 0" 59 ); 60 61 info("Check that UP/DOWN navigates in the input, even when next to a number"); 62 EventUtils.synthesizeKey("VK_DOWN", {}, view.styleWindow); 63 Assert.notStrictEqual(editor.input.selectionStart, pos, "Input caret moved"); 64 is(editor.input.value, LONG_CSS_VALUE, "Input value was not decremented."); 65 66 info("Move the caret to the end of the gradient definition."); 67 pos = editor.input.value.indexOf("95%") + 3; 68 editor.input.setSelectionRange(pos, pos); 69 70 info('Sending ", re" to the editable field.'); 71 for (const key of ", re") { 72 await synthesizeKeyForAutocomplete(key, editor, view.styleWindow); 73 } 74 75 info("Check the autocomplete can still be displayed."); 76 ok(editor.popup && editor.popup.isOpen, "Autocomplete popup is displayed."); 77 is( 78 editor.popup.selectedIndex, 79 0, 80 "Autocomplete has an item selected by default" 81 ); 82 83 let item = editor.popup.getItemAtIndex(editor.popup.selectedIndex); 84 is( 85 item.label, 86 "rebeccapurple", 87 "Check autocomplete displays expected value." 88 ); 89 90 info("Check autocomplete suggestions can be cycled using UP/DOWN arrows."); 91 92 await synthesizeKeyForAutocomplete("VK_DOWN", editor, view.styleWindow); 93 is(editor.popup.selectedIndex, 1, "Using DOWN cycles autocomplete values."); 94 await synthesizeKeyForAutocomplete("VK_DOWN", editor, view.styleWindow); 95 is(editor.popup.selectedIndex, 2, "Using DOWN cycles autocomplete values."); 96 await synthesizeKeyForAutocomplete("VK_UP", editor, view.styleWindow); 97 is(editor.popup.selectedIndex, 1, "Using UP cycles autocomplete values."); 98 item = editor.popup.getItemAtIndex(editor.popup.selectedIndex); 99 is(item.label, "red", "Check autocomplete displays expected value."); 100 101 info("Select the background-color suggestion with a mouse click."); 102 let onRuleviewChanged = view.once("ruleview-changed"); 103 const onSuggest = editor.once("after-suggest"); 104 105 const node = editor.popup.list.childNodes[editor.popup.selectedIndex]; 106 EventUtils.synthesizeMouseAtCenter(node, {}, node.ownerGlobal); 107 108 view.debounce.flush(); 109 await onSuggest; 110 await onRuleviewChanged; 111 112 is( 113 editor.input.value, 114 EXPECTED_CSS_VALUE, 115 "Input value correctly autocompleted" 116 ); 117 118 info("Press ESCAPE to leave the input."); 119 onRuleviewChanged = view.once("ruleview-changed"); 120 EventUtils.synthesizeKey("VK_ESCAPE", {}, view.styleWindow); 121 await onRuleviewChanged; 122 }); 123 124 /** 125 * Send the provided key to the currently focused input of the provided window. 126 * Wait for the editor to emit "after-suggest" to make sure the autocompletion 127 * process is finished. 128 * 129 * @param {string} key 130 * The key to send to the input. 131 * @param {InplaceEditor} editor 132 * The inplace editor which owns the focused input. 133 * @param {Window} win 134 * Window in which the key event will be dispatched. 135 */ 136 async function synthesizeKeyForAutocomplete(key, editor, win) { 137 const onSuggest = editor.once("after-suggest"); 138 EventUtils.synthesizeKey(key, {}, win); 139 await onSuggest; 140 }