Bug 966424 - Fix intermittent failures in browser_bug765105_background_image_tooltip.js. r=jwalker

This commit is contained in:
Patrick Brosset 2014-03-12 13:14:18 -04:00
parent c31092879c
commit f320ac7628
10 changed files with 320 additions and 266 deletions

View File

@ -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) {

View File

@ -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.

View File

@ -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");
});
}

View File

@ -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();

View File

@ -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,

View File

@ -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();
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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() {

View File

@ -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);
}