head.js (7218B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 /* eslint no-unused-vars: [2, {"vars": "local"}] */ 4 5 "use strict"; 6 7 // Import the inspector's head.js first (which itself imports shared-head.js). 8 Services.scriptloader.loadSubScript( 9 "chrome://mochitests/content/browser/devtools/client/inspector/test/head.js", 10 this 11 ); 12 13 var { 14 CssRuleView, 15 } = require("resource://devtools/client/inspector/rules/rules.js"); 16 var { 17 getInplaceEditorForSpan: inplaceEditor, 18 } = require("resource://devtools/client/shared/inplace-editor.js"); 19 const { 20 getCssVariableColor, 21 } = require("resource://devtools/client/shared/theme.js"); 22 23 const TEST_URL_ROOT = 24 "http://example.com/browser/devtools/client/inspector/shared/test/"; 25 const TEST_URL_ROOT_SSL = 26 "https://example.com/browser/devtools/client/inspector/shared/test/"; 27 const ROOT_TEST_DIR = getRootDirectory(gTestPath); 28 const STYLE_INSPECTOR_L10N = new LocalizationHelper( 29 "devtools/shared/locales/styleinspector.properties" 30 ); 31 32 /** 33 * The functions found below are here to ease test development and maintenance. 34 * Most of these functions are stateless and will require some form of context 35 * (the instance of the current toolbox, or inspector panel for instance). 36 * 37 * Most of these functions are async too and return promises. 38 * 39 * All tests should follow the following pattern: 40 * 41 * add_task(async function() { 42 * await addTab(TEST_URI); 43 * let {toolbox, inspector} = await openInspector(); 44 * await inspector.sidebar.select(viewId); 45 * let view = inspector.getPanel(viewId).view; 46 * await selectNode("#test", inspector); 47 * await someAsyncTestFunction(view); 48 * }); 49 * 50 * add_task is the way to define the testcase in the test file. It accepts 51 * a single argument: a function returning a promise (usually async function). 52 * 53 * There is no need to clean tabs up at the end of a test as this is done 54 * automatically. 55 * 56 * It is advised not to store any references on the global scope. There 57 * shouldn't be a need to anyway. Thanks to async functions, test steps, even 58 * though asynchronous, can be described in a nice flat way, and 59 * if/for/while/... control flow can be used as in sync code, making it 60 * possible to write the outline of the test case all in add_task, and delegate 61 * actual processing and assertions to other functions. 62 */ 63 64 /* ********************************************* 65 * UTILS 66 * ********************************************* 67 * General test utilities. 68 * Add new tabs, open the toolbox and switch to the various panels, select 69 * nodes, get node references, ... 70 */ 71 72 /** 73 * Polls a given function waiting for it to return true. 74 * 75 * @param {Function} validatorFn 76 * A validator function that returns a boolean. 77 * This is called every few milliseconds to check if the result is true. 78 * When it is true, the promise resolves. 79 * @param {string} name 80 * Optional name of the test. This is used to generate 81 * the success and failure messages. 82 * @return a promise that resolves when the function returned true or rejects 83 * if the timeout is reached 84 */ 85 function waitForSuccess(validatorFn, name = "untitled") { 86 return new Promise(resolve => { 87 function wait(validator) { 88 if (validator()) { 89 ok(true, "Validator function " + name + " returned true"); 90 resolve(); 91 } else { 92 setTimeout(() => wait(validator), 200); 93 } 94 } 95 wait(validatorFn); 96 }); 97 } 98 99 /** 100 * Get the dataURL for the font family tooltip. 101 * 102 * @param {Window} win 103 * @param {string} font 104 * The font family value. 105 * @param {object} nodeFront 106 * The NodeActor that will used to retrieve the dataURL for the 107 * font family tooltip contents. 108 */ 109 var getFontFamilyDataURL = async function (win, font, nodeFront) { 110 const fillStyle = getCssVariableColor("--theme-body-color", win); 111 112 const { data } = await nodeFront.getFontFamilyDataURL(font, fillStyle); 113 const dataURL = await data.string(); 114 return dataURL; 115 }; 116 117 /* ********************************************* 118 * RULE-VIEW 119 * ********************************************* 120 * Rule-view related test utility functions 121 * This object contains functions to get rules, get properties, ... 122 */ 123 124 /** 125 * Simulate a color change in a given color picker tooltip, and optionally wait 126 * for a given element in the page to have its style changed as a result 127 * 128 * @param {RuleView} ruleView 129 * The related rule view instance 130 * @param {SwatchColorPickerTooltip} colorPicker 131 * @param {Array} newRgba 132 * The new color to be set [r, g, b, a] 133 * @param {object} expectedChange 134 * Optional object that needs the following props: 135 * - {DOMNode} element The element in the page that will have its 136 * style changed. 137 * - {String} name The style name that will be changed 138 * - {String} value The expected style value 139 * The style will be checked like so: getComputedStyle(element)[name] === value 140 */ 141 var simulateColorPickerChange = async function ( 142 ruleView, 143 colorPicker, 144 newRgba, 145 expectedChange 146 ) { 147 const onRuleViewChanged = ruleView.once("ruleview-changed"); 148 info("Getting the spectrum colorpicker object"); 149 const spectrum = await colorPicker.spectrum; 150 info("Setting the new color"); 151 spectrum.rgb = newRgba; 152 info("Applying the change"); 153 spectrum.updateUI(); 154 spectrum.onChange(); 155 info("Waiting for rule-view to update"); 156 await onRuleViewChanged; 157 158 if (expectedChange) { 159 info("Waiting for the style to be applied on the page"); 160 await waitForSuccess(() => { 161 const { element, name, value } = expectedChange; 162 return content.getComputedStyle(element)[name] === value; 163 }, "Color picker change applied on the page"); 164 } 165 }; 166 167 /* ********************************************* 168 * COMPUTED-VIEW 169 * ********************************************* 170 * Computed-view related utility functions. 171 * Allows to get properties, links, expand properties, ... 172 */ 173 174 /** 175 * Get references to the name and value span nodes corresponding to a given 176 * property name in the computed-view 177 * 178 * @param {CssComputedView} view 179 * The instance of the computed view panel 180 * @param {string} name 181 * The name of the property to retrieve 182 * @return an object {nameSpan, valueSpan} 183 */ 184 function getComputedViewProperty(view, name) { 185 let prop; 186 for (const property of view.styleDocument.querySelectorAll( 187 ".computed-property-view" 188 )) { 189 const nameSpan = property.querySelector(".computed-property-name"); 190 const valueSpan = property.querySelector(".computed-property-value"); 191 192 if (nameSpan.firstChild.textContent === name) { 193 prop = { nameSpan, valueSpan }; 194 break; 195 } 196 } 197 return prop; 198 } 199 200 /** 201 * Get the text value of the property corresponding to a given name in the 202 * computed-view 203 * 204 * @param {CssComputedView} view 205 * The instance of the computed view panel 206 * @param {string} name 207 * The name of the property to retrieve 208 * @return {string} The property value 209 */ 210 function getComputedViewPropertyValue(view, name, propertyName) { 211 return getComputedViewProperty(view, name, propertyName).valueSpan 212 .textContent; 213 }