diff --git a/browser/devtools/inspector/test/browser_inspector_bug_952294_tooltips_dimensions.js b/browser/devtools/inspector/test/browser_inspector_bug_952294_tooltips_dimensions.js index ffdea9ab0d3..2016213ce94 100644 --- a/browser/devtools/inspector/test/browser_inspector_bug_952294_tooltips_dimensions.js +++ b/browser/devtools/inspector/test/browser_inspector_bug_952294_tooltips_dimensions.js @@ -75,12 +75,14 @@ function selectDiv() { } function testTransformDimension() { - let deferred = promise.defer(); - info("Testing css transform tooltip dimensions"); + return Task.spawn(function*() { + let tooltip = ruleView.previewTooltip; + let panel = tooltip.panel; - let {valueSpan} = getRuleViewProperty("transform"); - showTooltipOn(ruleView.previewTooltip, valueSpan, () => { - let panel = ruleView.previewTooltip.panel; + info("Testing css transform tooltip dimensions"); + let {valueSpan} = getRuleViewProperty("transform"); + + yield assertTooltipShownOn(tooltip, valueSpan); // Let's not test for a specific size, but instead let's make sure it's at // least as big as the preview canvas @@ -92,22 +94,23 @@ function testTransformDimension() { ok(panelRect.width >= w, "The panel is wide enough to show the canvas"); ok(panelRect.height >= h, "The panel is high enough to show the canvas"); - ruleView.previewTooltip.hide(); - deferred.resolve(); + let onHidden = tooltip.once("hidden"); + tooltip.hide(); + yield onHidden; }); - - return deferred.promise; } function testImageDimension() { - let deferred = promise.defer(); - info("Testing background-image tooltip dimensions"); + return Task.spawn(function*() { + info("Testing background-image tooltip dimensions"); - let {valueSpan} = getRuleViewProperty("background"); - let uriSpan = valueSpan.querySelector(".theme-link"); + let tooltip = ruleView.previewTooltip; + let panel = tooltip.panel; - showTooltipOn(ruleView.previewTooltip, uriSpan, () => { - let panel = ruleView.previewTooltip.panel; + let {valueSpan} = getRuleViewProperty("background"); + let uriSpan = valueSpan.querySelector(".theme-link"); + + yield assertTooltipShownOn(tooltip, uriSpan); // Let's not test for a specific size, but instead let's make sure it's at // least as big as the image @@ -119,22 +122,24 @@ function testImageDimension() { ok(panelRect.height >= imageRect.height, "The panel is high enough to show the image"); - ruleView.previewTooltip.hide(); - deferred.resolve(); + let onHidden = tooltip.once("hidden"); + tooltip.hide(); + yield onHidden; }); - - return deferred.promise; } function testPickerDimension() { - let deferred = promise.defer(); - info("Testing color-picker tooltip dimensions"); + return Task.spawn(function*() { + info("Testing color-picker tooltip dimensions"); - let {valueSpan} = getRuleViewProperty("background"); - let swatch = valueSpan.querySelector(".ruleview-colorswatch"); - let cPicker = ruleView.colorPicker; + let {valueSpan} = getRuleViewProperty("background"); + let swatch = valueSpan.querySelector(".ruleview-colorswatch"); + let cPicker = ruleView.colorPicker; + + let onShown = cPicker.tooltip.once("shown"); + swatch.click(); + yield onShown; - cPicker.tooltip.once("shown", () => { // The colorpicker spectrum's iframe has a fixed width height, so let's // make sure the tooltip is at least as big as that let w = cPicker.tooltip.panel.querySelector("iframe").width; @@ -144,21 +149,43 @@ function testPickerDimension() { ok(panelRect.width >= w, "The panel is wide enough to show the picker"); ok(panelRect.height >= h, "The panel is high enough to show the picker"); + let onHidden = cPicker.tooltip.once("hidden"); cPicker.hide(); - deferred.resolve(); + yield onHidden; }); - swatch.click(); - - return deferred.promise; } -function showTooltipOn(tooltip, element, cb) { - // If there is indeed a show-on-hover on element, the xul panel will be shown - tooltip.panel.addEventListener("popupshown", function shown() { - tooltip.panel.removeEventListener("popupshown", shown, true); - cb(); - }, true); - tooltip._showOnHover(element); +/** + * @return a promise that resolves when the tooltip is shown + */ +function assertTooltipShownOn(tooltip, element) { + return Task.spawn(function*() { + let isTarget = yield isHoverTooltipTarget(tooltip, element); + ok(isTarget, "The element is a tooltip target and content has been inserted"); + + info("Showing the tooltip now that content has been inserted by isValidHoverTarget"); + let onShown = tooltip.once("shown"); + tooltip.show(); + yield onShown; + }); +} + +/** + * Given a tooltip object instance (see Tooltip.js), checks if it is set to + * toggle and hover and if so, checks if the given target is a valid hover target. + * This won't actually show the tooltip (the less we interact with XUL panels + * during test runs, the better). + * @return a promise that resolves when the answer is known. Also, this will + * delete to a function in the rule-view which will insert content into the + * tooltip + */ +function isHoverTooltipTarget(tooltip, target) { + if (!tooltip._basedNode || !tooltip.panel) { + return promise.reject(new Error("The tooltip passed isn't set to toggle on hover or is not a tooltip")); + } + // The tooltip delegates to a user defined cb that inserts content in the tooltip + // when calling isValidHoverTarget + return tooltip.isValidHoverTarget(target); } function getRuleViewProperty(name) { diff --git a/browser/devtools/markupview/markup-view.js b/browser/devtools/markupview/markup-view.js index f990eb1edc3..28365ac13c4 100644 --- a/browser/devtools/markupview/markup-view.js +++ b/browser/devtools/markupview/markup-view.js @@ -110,7 +110,7 @@ MarkupView.prototype = { _initTooltips: function() { this.tooltip = new Tooltip(this._inspector.panelDoc); this.tooltip.startTogglingOnHover(this._elt, - this._buildTooltipContent.bind(this)); + this._isImagePreviewTarget.bind(this)); }, _initHighlighter: function() { @@ -232,7 +232,15 @@ MarkupView.prototype = { updateChildren(documentElement); }, - _buildTooltipContent: function(target) { + /** + * Executed when the mouse hovers over a target in the markup-view and is used + * to decide whether this target should be used to display an image preview + * tooltip. + * Delegates the actual decision to the corresponding MarkupContainer instance + * if one is found. + * @return the promise returned by MarkupContainer._isImagePreviewTarget + */ + _isImagePreviewTarget: function(target) { // From the target passed here, let's find the parent MarkupContainer // and ask it if the tooltip should be shown let parent = target, container; @@ -247,7 +255,7 @@ MarkupView.prototype = { if (container) { // With the newly found container, delegate the tooltip content creation // and decision to show or not the tooltip - return container._buildTooltipContent(target, this.tooltip); + return container._isImagePreviewTarget(target, this.tooltip); } }, @@ -1265,6 +1273,13 @@ MarkupContainer.prototype = { } }, + /** + * If the node is an image or canvas (@see isPreviewable), then get the + * image data uri from the server so that it can then later be previewed in + * a tooltip if needed. + * Stores a promise in this.tooltipData.data that resolves when the data has + * been retrieved + */ _prepareImagePreview: function() { if (this.isPreviewable()) { // Get the image data for later so that when the user actually hovers over @@ -1291,6 +1306,27 @@ MarkupContainer.prototype = { } }, + /** + * Executed by MarkupView._isImagePreviewTarget which is itself called when the + * mouse hovers over a target in the markup-view. + * Checks if the target is indeed something we want to have an image tooltip + * preview over and, if so, inserts content into the tooltip. + * @return a promise that resolves when the content has been inserted or + * rejects if no preview is required. This promise is then used by Tooltip.js + * to decide if/when to show the tooltip + */ + _isImagePreviewTarget: function(target, tooltip) { + if (!this.tooltipData || this.tooltipData.target !== target) { + return promise.reject(); + } + + return this.tooltipData.data.then(({data, size}) => { + tooltip.setImageContent(data, size); + }, () => { + tooltip.setBrokenImageContent(); + }); + }, + copyImageDataUri: function() { // We need to send again a request to gettooltipData even if one was sent for // the tooltip, because we want the full-size image @@ -1301,17 +1337,6 @@ MarkupContainer.prototype = { }); }, - _buildTooltipContent: function(target, tooltip) { - if (this.tooltipData && target === this.tooltipData.target) { - this.tooltipData.data.then(({data, size}) => { - tooltip.setImageContent(data, size); - }, () => { - tooltip.setBrokenImageContent(); - }); - return true; - } - }, - /** * True if the current node has children. The MarkupView * will set this attribute for the MarkupContainer. diff --git a/browser/devtools/markupview/test/browser_inspector_markup_765105_tooltip.js b/browser/devtools/markupview/test/browser_inspector_markup_765105_tooltip.js index 5c5487c89d3..ee13158fd1c 100644 --- a/browser/devtools/markupview/test/browser_inspector_markup_765105_tooltip.js +++ b/browser/devtools/markupview/test/browser_inspector_markup_765105_tooltip.js @@ -88,7 +88,7 @@ function testImageTooltip(index) { target = container.editor.getAttributeElement("src"); } - assertTooltipShownOn(target, () => { + assertTooltipShownOn(target).then(() => { let images = markup.tooltip.panel.getElementsByTagName("image"); is(images.length, 1, "Tooltip for [" + TEST_NODES[index].selector + "] contains an image"); @@ -97,7 +97,6 @@ function testImageTooltip(index) { is(label.textContent, TEST_NODES[index].size, "Tooltip label for [" + TEST_NODES[index].selector + "] displays the right image size") - markup.tooltip.hide(); testImageTooltip(index + 1); }); } @@ -117,22 +116,10 @@ function compareImageData(img, imgData) { } function assertTooltipShownOn(element, cb) { - // If there is indeed a show-on-hover on element, the xul panel will be shown - markup.tooltip.panel.addEventListener("popupshown", function shown() { - markup.tooltip.panel.removeEventListener("popupshown", shown, true); + return Task.spawn(function*() { + info("Is the element a valid hover target"); - // Poll until the image gets loaded in the tooltip. This is required because - // markup containers only load images in their associated tooltips when - // the image data comes back from the server. However, this test is executed - // synchronously as soon as "inspector-updated" is fired, which is before - // the data for images is known. - let hasImage = () => markup.tooltip.panel.getElementsByTagName("image").length; - let poll = setInterval(() => { - if (hasImage()) { - clearInterval(poll); - cb(); - } - }, 200); - }, true); - markup.tooltip._showOnHover(element); + let isValid = yield markup.tooltip.isValidHoverTarget(element); + ok(isValid, "The element is a valid hover target for the image tooltip"); + }); } diff --git a/browser/devtools/netmonitor/test/browser_net_image-tooltip.js b/browser/devtools/netmonitor/test/browser_net_image-tooltip.js index 0da42590f3d..996b95064d1 100644 --- a/browser/devtools/netmonitor/test/browser_net_image-tooltip.js +++ b/browser/devtools/netmonitor/test/browser_net_image-tooltip.js @@ -59,16 +59,17 @@ function test() { }); } - function showTooltipOn(aTooltip, aTarget) { - let deferred = promise.defer(); - - aTooltip.panel.addEventListener("popupshown", function onEvent() { - aTooltip.panel.removeEventListener("popupshown", onEvent, true); - deferred.resolve(aTooltip); - }, true); - - aTooltip._showOnHover(aTarget); - return deferred.promise; + /** + * @return a promise that resolves when the tooltip is shown + */ + function showTooltipOn(tooltip, element) { + return Task.spawn(function*() { + let isTarget = yield tooltip.isValidHoverTarget(element); + let onShown = tooltip.once("shown"); + tooltip.show(); + yield onShown; + return tooltip; + }); } aDebuggee.performRequests(); diff --git a/browser/devtools/shared/widgets/Tooltip.js b/browser/devtools/shared/widgets/Tooltip.js index 81dd22f4814..9ff91f2fae7 100644 --- a/browser/devtools/shared/widgets/Tooltip.js +++ b/browser/devtools/shared/widgets/Tooltip.js @@ -392,19 +392,34 @@ Tooltip.prototype = { this.hide(); this._lastHovered = event.target; setNamedTimeout(this.uid, this._showDelay, () => { - this._showOnHover(event.target); + this.isValidHoverTarget(event.target).then(target => { + this.show(target); + }); }); } }, - _showOnHover: function(target) { + /** + * Is the given target DOMNode a valid node for toggling the tooltip on hover. + * This delegates to the user-defined _targetNodeCb callback. + * @return a promise that resolves or rejects depending if the tooltip should + * be shown or not. If it resolves, it does to the actual anchor to be used + */ + isValidHoverTarget: function(target) { + // Execute the user-defined callback which should return either true/false + // or a promise that resolves or rejects let res = this._targetNodeCb(target, this); - let show = arg => this.show(arg instanceof Ci.nsIDOMNode ? arg : target); + // The callback can additionally return a DOMNode to replace the anchor of + // the tooltip when shown if (res && res.then) { - res.then(show); - } else if (res) { - show(res); + return res.then(arg => { + return arg instanceof Ci.nsIDOMNode ? arg : target; + }, () => { + return false; + }); + } else { + return res ? promise.resolve(res) : promise.reject(false); } }, @@ -620,42 +635,44 @@ Tooltip.prototype = { * a number here */ setImageContent: function(imageUrl, options={}) { - if (imageUrl) { - // Main container - let vbox = this.doc.createElement("vbox"); - vbox.setAttribute("align", "center"); - - // Display the image - let image = this.doc.createElement("image"); - image.setAttribute("src", imageUrl); - if (options.maxDim) { - image.style.maxWidth = options.maxDim + "px"; - image.style.maxHeight = options.maxDim + "px"; - } - vbox.appendChild(image); - - // Dimension label - let label = this.doc.createElement("label"); - label.classList.add("devtools-tooltip-caption"); - label.classList.add("theme-comment"); - if (options.naturalWidth && options.naturalHeight) { - label.textContent = this._getImageDimensionLabel(options.naturalWidth, - options.naturalHeight); - } else { - // If no dimensions were provided, load the image to get them - label.textContent = l10n.strings.GetStringFromName("previewTooltip.image.brokenImage"); - let imgObj = new this.doc.defaultView.Image(); - imgObj.src = imageUrl; - imgObj.onload = () => { - imgObj.onload = null; - label.textContent = this._getImageDimensionLabel(imgObj.naturalWidth, - imgObj.naturalHeight); - } - } - vbox.appendChild(label); - - this.content = vbox; + if (!imageUrl) { + return; } + + // Main container + let vbox = this.doc.createElement("vbox"); + vbox.setAttribute("align", "center"); + + // Display the image + let image = this.doc.createElement("image"); + image.setAttribute("src", imageUrl); + if (options.maxDim) { + image.style.maxWidth = options.maxDim + "px"; + image.style.maxHeight = options.maxDim + "px"; + } + vbox.appendChild(image); + + // Dimension label + let label = this.doc.createElement("label"); + label.classList.add("devtools-tooltip-caption"); + label.classList.add("theme-comment"); + if (options.naturalWidth && options.naturalHeight) { + label.textContent = this._getImageDimensionLabel(options.naturalWidth, + options.naturalHeight); + } else { + // If no dimensions were provided, load the image to get them + label.textContent = l10n.strings.GetStringFromName("previewTooltip.image.brokenImage"); + let imgObj = new this.doc.defaultView.Image(); + imgObj.src = imageUrl; + imgObj.onload = () => { + imgObj.onload = null; + label.textContent = this._getImageDimensionLabel(imgObj.naturalWidth, + imgObj.naturalHeight); + } + } + vbox.appendChild(label); + + this.content = vbox; }, _getImageDimensionLabel: (w, h) => w + " x " + h, diff --git a/browser/devtools/styleinspector/rule-view.js b/browser/devtools/styleinspector/rule-view.js index b8452c670d1..bb55c2891dd 100644 --- a/browser/devtools/styleinspector/rule-view.js +++ b/browser/devtools/styleinspector/rule-view.js @@ -1122,7 +1122,7 @@ CssRuleView.prototype = { // Test for css transform if (property && property.name === "transform") { this.previewTooltip.setCssTransformContent(property.value, this.pageStyle, - this._viewedElement).then(def.resolve); + this._viewedElement).then(def.resolve, def.reject); hasTooltip = true; } @@ -1164,8 +1164,10 @@ CssRuleView.prototype = { } if (hasTooltip) { - this.colorPicker.revert(); - this.colorPicker.hide(); + if (this.colorPicker.tooltip.isShown()) { + this.colorPicker.revert(); + this.colorPicker.hide(); + } } else { def.reject(); } diff --git a/browser/devtools/styleinspector/test/browser_bug726427_csstransform_tooltip.js b/browser/devtools/styleinspector/test/browser_bug726427_csstransform_tooltip.js index fdec606709c..1283391303b 100644 --- a/browser/devtools/styleinspector/test/browser_bug726427_csstransform_tooltip.js +++ b/browser/devtools/styleinspector/test/browser_bug726427_csstransform_tooltip.js @@ -64,106 +64,82 @@ function endTests() { } function testTransformTooltipOnIDSelector() { - info("Testing that a transform tooltip appears on the #ID rule"); + Task.spawn(function*() { + info("Testing that a transform tooltip appears on the #ID rule"); - let panel = ruleView.previewTooltip.panel; - ok(panel, "The XUL panel exists for the rule-view preview tooltips"); + let panel = ruleView.previewTooltip.panel; + ok(panel, "The XUL panel exists for the rule-view preview tooltips"); + + let {valueSpan} = getRuleViewProperty("#testElement", "transform"); + yield assertTooltipShownOn(ruleView.previewTooltip, valueSpan); - let {valueSpan} = getRuleViewProperty("#testElement", "transform"); - assertTooltipShownOn(ruleView.previewTooltip, valueSpan, () => { // The transform preview is canvas, so there's not much we can test, so for // now, let's just be happy with the fact that the tooltips is shown! ok(true, "Tooltip shown on the transform property of the #ID rule"); - ruleView.previewTooltip.hide(); - executeSoon(testTransformTooltipOnClassSelector); - }); + }).then(testTransformTooltipOnClassSelector); } function testTransformTooltipOnClassSelector() { - info("Testing that a transform tooltip appears on the .class rule"); + Task.spawn(function*() { + info("Testing that a transform tooltip appears on the .class rule"); + + let {valueSpan} = getRuleViewProperty(".test-element", "transform"); + yield assertTooltipShownOn(ruleView.previewTooltip, valueSpan); - let {valueSpan} = getRuleViewProperty(".test-element", "transform"); - assertTooltipShownOn(ruleView.previewTooltip, valueSpan, () => { // The transform preview is canvas, so there's not much we can test, so for // now, let's just be happy with the fact that the tooltips is shown! ok(true, "Tooltip shown on the transform property of the .class rule"); - ruleView.previewTooltip.hide(); - executeSoon(testTransformTooltipOnTagSelector); - }); + }).then(testTransformTooltipOnTagSelector); } function testTransformTooltipOnTagSelector() { - info("Testing that a transform tooltip appears on the tag rule"); + Task.spawn(function*() { + info("Testing that a transform tooltip appears on the tag rule"); + + let {valueSpan} = getRuleViewProperty("div", "transform"); + yield assertTooltipShownOn(ruleView.previewTooltip, valueSpan); - let {valueSpan} = getRuleViewProperty("div", "transform"); - assertTooltipShownOn(ruleView.previewTooltip, valueSpan, () => { // The transform preview is canvas, so there's not much we can test, so for // now, let's just be happy with the fact that the tooltips is shown! ok(true, "Tooltip shown on the transform property of the tag rule"); - ruleView.previewTooltip.hide(); - executeSoon(testTransformTooltipNotShownOnInvalidTransform); - }); + }).then(testTransformTooltipNotShownOnInvalidTransform); } function testTransformTooltipNotShownOnInvalidTransform() { - info("Testing that a transform tooltip does not appear for invalid values"); + Task.spawn(function*() { + info("Testing that a transform tooltip does not appear for invalid values"); - let ruleEditor; - for (let rule of ruleView._elementStyle.rules) { - if (rule.matchedSelectors[0] === "[attr]") { - ruleEditor = rule.editor; + let ruleEditor; + for (let rule of ruleView._elementStyle.rules) { + if (rule.matchedSelectors[0] === "[attr]") { + ruleEditor = rule.editor; + } } - } - ruleEditor.addProperty("transform", "muchTransform(suchAngle)", ""); + ruleEditor.addProperty("transform", "muchTransform(suchAngle)", ""); - let {valueSpan} = getRuleViewProperty("[attr]", "transform"); - assertTooltipNotShownOn(ruleView.previewTooltip, valueSpan, () => { - executeSoon(testTransformTooltipOnComputedView); - }); + let {valueSpan} = getRuleViewProperty("[attr]", "transform"); + let isValid = yield isHoverTooltipTarget(ruleView.previewTooltip, valueSpan); + ok(!isValid, "The tooltip did not appear on hover of an invalid transform value"); + }).then(testTransformTooltipOnComputedView); } function testTransformTooltipOnComputedView() { - info("Testing that a transform tooltip appears in the computed view too"); + Task.spawn(function*() { + info("Testing that a transform tooltip appears in the computed view too"); - inspector.sidebar.select("computedview"); - computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view; - let doc = computedView.styleDocument; + inspector.sidebar.select("computedview"); + computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view; + let doc = computedView.styleDocument; - let panel = computedView.tooltip.panel; - let {valueSpan} = getComputedViewProperty("transform"); + let panel = computedView.tooltip.panel; + let {valueSpan} = getComputedViewProperty("transform"); + + yield assertTooltipShownOn(computedView.tooltip, valueSpan); - assertTooltipShownOn(computedView.tooltip, valueSpan, () => { // The transform preview is canvas, so there's not much we can test, so for // now, let's just be happy with the fact that the tooltips is shown! ok(true, "Tooltip shown on the computed transform property"); - computedView.tooltip.hide(); - executeSoon(endTests); - }); -} - -function assertTooltipShownOn(tooltip, element, cb) { - // If there is indeed a show-on-hover on element, the xul panel will be shown - tooltip.panel.addEventListener("popupshown", function shown() { - tooltip.panel.removeEventListener("popupshown", shown, true); - cb(); - }, true); - - // Run _showOnHover at stable state after the next refresh driver tick. - // This way nothing during reflow or painting should be able to - // cancel showing the popup. - element.ownerDocument.defaultView.requestAnimationFrame(() => { - executeSoon(() => { tooltip._showOnHover(element); }); - }); -} - -function assertTooltipNotShownOn(tooltip, element, cb) { - // The only way to make sure the tooltip is not shown is try and show it, wait - // for a given amount of time, and then check if it's shown or not - tooltip._showOnHover(element); - setTimeout(() => { - ok(!tooltip.isShown(), "The tooltip did not appear on hover of the element"); - cb(); - }, tooltip.defaultShowDelay + 100); + }).then(endTests); } function getRule(selectorText) { diff --git a/browser/devtools/styleinspector/test/browser_bug765105_background_image_tooltip.js b/browser/devtools/styleinspector/test/browser_bug765105_background_image_tooltip.js index 16ba5bf2ced..85e30833c29 100644 --- a/browser/devtools/styleinspector/test/browser_bug765105_background_image_tooltip.js +++ b/browser/devtools/styleinspector/test/browser_bug765105_background_image_tooltip.js @@ -59,100 +59,92 @@ function endTests() { finish(); } -function assertTooltipShownOn(tooltip, element, cb) { - // If there is indeed a show-on-hover on element, the xul panel will be shown - tooltip.panel.addEventListener("popupshown", function shown() { - tooltip.panel.removeEventListener("popupshown", shown, true); - cb(); - }, true); - tooltip._showOnHover(element); -} - function testBodyRuleView() { - info("Testing tooltips in the rule view"); + Task.spawn(function*() { + info("Testing tooltips in the rule view"); + let panel = ruleView.previewTooltip.panel; - let panel = ruleView.previewTooltip.panel; + // Check that the rule view has a tooltip and that a XUL panel has been created + ok(ruleView.previewTooltip, "Tooltip instance exists"); + ok(panel, "XUL panel exists"); - // Check that the rule view has a tooltip and that a XUL panel has been created - ok(ruleView.previewTooltip, "Tooltip instance exists"); - ok(panel, "XUL panel exists"); + // Get the background-image property inside the rule view + let {valueSpan} = getRuleViewProperty("background-image"); + let uriSpan = valueSpan.querySelector(".theme-link"); + + yield assertTooltipShownOn(ruleView.previewTooltip, uriSpan); - // Get the background-image property inside the rule view - let {valueSpan} = getRuleViewProperty("background-image"); - let uriSpan = valueSpan.querySelector(".theme-link"); - // And verify that the tooltip gets shown on this property - assertTooltipShownOn(ruleView.previewTooltip, uriSpan, () => { let images = panel.getElementsByTagName("image"); is(images.length, 1, "Tooltip contains an image"); - ok(images[0].src.indexOf("iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHe") !== -1, "The image URL seems fine"); - - ruleView.previewTooltip.hide(); + ok(images[0].getAttribute("src").indexOf("iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHe") !== -1, + "The image URL seems fine"); + let onUpdated = inspector.once("inspector-updated"); inspector.selection.setNode(contentDoc.querySelector(".test-element")); - inspector.once("inspector-updated", testDivRuleView); - }); + yield onUpdated; + }).then(testDivRuleView); } function testDivRuleView() { - let panel = ruleView.previewTooltip.panel; + Task.spawn(function*() { + let panel = ruleView.previewTooltip.panel; - // Get the background property inside the rule view - let {valueSpan} = getRuleViewProperty("background"); - let uriSpan = valueSpan.querySelector(".theme-link"); + // Get the background property inside the rule view + let {valueSpan} = getRuleViewProperty("background"); + let uriSpan = valueSpan.querySelector(".theme-link"); + + yield assertTooltipShownOn(ruleView.previewTooltip, uriSpan); - // And verify that the tooltip gets shown on this property - assertTooltipShownOn(ruleView.previewTooltip, uriSpan, () => { let images = panel.getElementsByTagName("image"); is(images.length, 1, "Tooltip contains an image"); - ok(images[0].src.startsWith("data:"), "Tooltip contains a data-uri image as expected"); - - ruleView.previewTooltip.hide(); - - testTooltipAppearsEvenInEditMode(); - }); + ok(images[0].getAttribute("src").startsWith("data:"), "Tooltip contains a data-uri image as expected"); + }).then(testTooltipAppearsEvenInEditMode); } function testTooltipAppearsEvenInEditMode() { - let panel = ruleView.previewTooltip.panel; + Task.spawn(function*() { + let panel = ruleView.previewTooltip.panel; - // Switch one field to edit mode - let brace = ruleView.doc.querySelector(".ruleview-ruleclose"); - waitForEditorFocus(brace.parentNode, editor => { - // Now try to show the tooltip + info("Switching to edit mode in the rule view"); + let editor = yield turnToEditMode(ruleView); + + info("Now trying to show the preview tooltip"); let {valueSpan} = getRuleViewProperty("background"); let uriSpan = valueSpan.querySelector(".theme-link"); - assertTooltipShownOn(ruleView.previewTooltip, uriSpan, () => { - is(ruleView.doc.activeElement, editor.input, - "Tooltip was shown in edit mode, and inplace-editor still focused"); + yield assertTooltipShownOn(ruleView.previewTooltip, uriSpan); - ruleView.previewTooltip.hide(); + is(ruleView.doc.activeElement, editor.input, + "Tooltip was shown in edit mode, and inplace-editor still focused"); + }).then(testComputedView); +} - testComputedView(); - }); - }); +function turnToEditMode(ruleView) { + let def = promise.defer(); + let brace = ruleView.doc.querySelector(".ruleview-ruleclose"); + waitForEditorFocus(brace.parentNode, def.resolve); brace.click(); + return def.promise; } function testComputedView() { - info("Testing tooltips in the computed view"); + Task.spawn(function*() { + info("Testing tooltips in the computed view"); - inspector.sidebar.select("computedview"); - computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view; - let doc = computedView.styleDocument; + inspector.sidebar.select("computedview"); + computedView = inspector.sidebar.getWindowForTab("computedview").computedview.view; + let doc = computedView.styleDocument; - let panel = computedView.tooltip.panel; - let {valueSpan} = getComputedViewProperty("background-image"); - let uriSpan = valueSpan.querySelector(".theme-link"); + let panel = computedView.tooltip.panel; + let {valueSpan} = getComputedViewProperty("background-image"); + let uriSpan = valueSpan.querySelector(".theme-link"); + + yield assertTooltipShownOn(computedView.tooltip, uriSpan); - assertTooltipShownOn(computedView.tooltip, uriSpan, () => { let images = panel.getElementsByTagName("image"); is(images.length, 1, "Tooltip contains an image"); - ok(images[0].src.startsWith("data:"), "Tooltip contains a data-uri in the computed-view too"); - computedView.tooltip.hide(); - - endTests(); - }); + ok(images[0].getAttribute("src").startsWith("data:"), "Tooltip contains a data-uri in the computed-view too"); + }).then(endTests); } function getRuleViewProperty(name) { diff --git a/browser/devtools/styleinspector/test/browser_bug889638_rule_view_color_picker.js b/browser/devtools/styleinspector/test/browser_bug889638_rule_view_color_picker.js index d79163aba1c..c7eabe9a315 100644 --- a/browser/devtools/styleinspector/test/browser_bug889638_rule_view_color_picker.js +++ b/browser/devtools/styleinspector/test/browser_bug889638_rule_view_color_picker.js @@ -105,24 +105,24 @@ function testColorPickerAppearsOnColorSwatchClick() { } function testColorPickerHidesWhenImageTooltipAppears() { - let swatch = swatches[0]; - let bgImageSpan = getRuleViewProperty("background-image").valueSpan; - let uriSpan = bgImageSpan.querySelector(".theme-link"); + Task.spawn(function*() { + let swatch = swatches[0]; + let bgImageSpan = getRuleViewProperty("background-image").valueSpan; + let uriSpan = bgImageSpan.querySelector(".theme-link"); + let tooltip = ruleView.colorPicker.tooltip; + + info("Showing the color picker tooltip by clicking on the color swatch"); + let onShown = tooltip.once("shown"); + swatch.click(); + yield onShown; + + info("Now showing the image preview tooltip to hide the color picker"); + let onHidden = tooltip.once("hidden"); + yield assertTooltipShownOn(ruleView.previewTooltip, uriSpan); + yield onHidden; - ruleView.colorPicker.tooltip.once("shown", () => { - info("The color picker is shown, now display an image tooltip to hide it"); - ruleView.previewTooltip._showOnHover(uriSpan); - }); - ruleView.colorPicker.tooltip.once("hidden", () => { ok(true, "The color picker closed when the image preview tooltip appeared"); - - executeSoon(() => { - ruleView.previewTooltip.hide(); - testPressingEscapeRevertsChanges(); - }); - }); - - swatch.click(); + }).then(testPressingEscapeRevertsChanges); } function testPressingEscapeRevertsChanges() { diff --git a/browser/devtools/styleinspector/test/head.js b/browser/devtools/styleinspector/test/head.js index 9cdfb09bfd0..692402e3aec 100644 --- a/browser/devtools/styleinspector/test/head.js +++ b/browser/devtools/styleinspector/test/head.js @@ -280,3 +280,30 @@ registerCleanupFunction(tearDown); waitForExplicitFinish(); +/** + * @return a promise that resolves when the tooltip is shown + */ +function assertTooltipShownOn(tooltip, element) { + return Task.spawn(function*() { + let isTarget = yield isHoverTooltipTarget(tooltip, element); + ok(isTarget, "The element is a tooltip target"); + }); +} + +/** + * Given a tooltip object instance (see Tooltip.js), checks if it is set to + * toggle and hover and if so, checks if the given target is a valid hover target. + * This won't actually show the tooltip (the less we interact with XUL panels + * during test runs, the better). + * @return a promise that resolves when the answer is known. Also, this will + * delete to a function in the rule-view which will insert content into the + * tooltip + */ +function isHoverTooltipTarget(tooltip, target) { + if (!tooltip._basedNode || !tooltip.panel) { + return promise.reject(new Error("The tooltip passed isn't set to toggle on hover or is not a tooltip")); + } + // The tooltip delegates to a user defined cb that inserts content in the tooltip + // when calling isValidHoverTarget + return tooltip.isValidHoverTarget(target); +}