import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,6 @@
"use strict";
module.exports = {
// Extend from the shared list of defined globals for mochitests.
"extends": "../../../.eslintrc.mochitests.js"
};

View file

@ -0,0 +1,172 @@
[DEFAULT]
tags = devtools
subsuite = devtools
support-files =
doc_inspector_add_node.html
doc_inspector_breadcrumbs.html
doc_inspector_breadcrumbs_visibility.html
doc_inspector_csp.html
doc_inspector_csp.html^headers^
doc_inspector_delete-selected-node-01.html
doc_inspector_delete-selected-node-02.html
doc_inspector_embed.html
doc_inspector_gcli-inspect-command.html
doc_inspector_highlight_after_transition.html
doc_inspector_highlighter-comments.html
doc_inspector_highlighter-geometry_01.html
doc_inspector_highlighter-geometry_02.html
doc_inspector_highlighter_csstransform.html
doc_inspector_highlighter_dom.html
doc_inspector_highlighter_inline.html
doc_inspector_highlighter.html
doc_inspector_highlighter_rect.html
doc_inspector_highlighter_rect_iframe.html
doc_inspector_highlighter_xbl.xul
doc_inspector_infobar_01.html
doc_inspector_infobar_02.html
doc_inspector_infobar_03.html
doc_inspector_infobar_textnode.html
doc_inspector_long-divs.html
doc_inspector_menu.html
doc_inspector_outerhtml.html
doc_inspector_remove-iframe-during-load.html
doc_inspector_search.html
doc_inspector_search-reserved.html
doc_inspector_search-suggestions.html
doc_inspector_search-svg.html
doc_inspector_select-last-selected-01.html
doc_inspector_select-last-selected-02.html
doc_inspector_svg.svg
head.js
shared-head.js
!/devtools/client/commandline/test/helpers.js
!/devtools/client/framework/test/shared-head.js
!/devtools/client/shared/test/test-actor.js
!/devtools/client/shared/test/test-actor-registry.js
[browser_inspector_addNode_01.js]
[browser_inspector_addNode_02.js]
[browser_inspector_addNode_03.js]
[browser_inspector_addSidebarTab.js]
[browser_inspector_breadcrumbs.js]
[browser_inspector_breadcrumbs_highlight_hover.js]
[browser_inspector_breadcrumbs_keybinding.js]
[browser_inspector_breadcrumbs_keyboard_trap.js]
skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard Preferences
[browser_inspector_breadcrumbs_mutations.js]
[browser_inspector_breadcrumbs_namespaced.js]
[browser_inspector_breadcrumbs_visibility.js]
[browser_inspector_delete-selected-node-01.js]
[browser_inspector_delete-selected-node-02.js]
[browser_inspector_delete-selected-node-03.js]
[browser_inspector_destroy-after-navigation.js]
[browser_inspector_destroy-before-ready.js]
[browser_inspector_expand-collapse.js]
[browser_inspector_gcli-inspect-command.js]
[browser_inspector_highlighter-01.js]
[browser_inspector_highlighter-02.js]
[browser_inspector_highlighter-03.js]
[browser_inspector_highlighter-04.js]
[browser_inspector_highlighter-by-type.js]
[browser_inspector_highlighter-cancel.js]
[browser_inspector_highlighter-comments.js]
[browser_inspector_highlighter-cssgrid_01.js]
[browser_inspector_highlighter-csstransform_01.js]
[browser_inspector_highlighter-csstransform_02.js]
[browser_inspector_highlighter-embed.js]
[browser_inspector_highlighter-eyedropper-clipboard.js]
subsuite = clipboard
[browser_inspector_highlighter-eyedropper-csp.js]
[browser_inspector_highlighter-eyedropper-events.js]
[browser_inspector_highlighter-eyedropper-label.js]
[browser_inspector_highlighter-eyedropper-show-hide.js]
[browser_inspector_highlighter-eyedropper-xul.js]
[browser_inspector_highlighter-geometry_01.js]
[browser_inspector_highlighter-geometry_02.js]
[browser_inspector_highlighter-geometry_03.js]
[browser_inspector_highlighter-geometry_04.js]
[browser_inspector_highlighter-geometry_05.js]
[browser_inspector_highlighter-geometry_06.js]
[browser_inspector_highlighter-hover_01.js]
[browser_inspector_highlighter-hover_02.js]
[browser_inspector_highlighter-hover_03.js]
[browser_inspector_highlighter-iframes_01.js]
[browser_inspector_highlighter-iframes_02.js]
[browser_inspector_highlighter-inline.js]
[browser_inspector_highlighter-keybinding_01.js]
[browser_inspector_highlighter-keybinding_02.js]
[browser_inspector_highlighter-keybinding_03.js]
[browser_inspector_highlighter-keybinding_04.js]
[browser_inspector_highlighter-measure_01.js]
[browser_inspector_highlighter-measure_02.js]
[browser_inspector_highlighter-options.js]
[browser_inspector_highlighter-preview.js]
[browser_inspector_highlighter-rect_01.js]
[browser_inspector_highlighter-rect_02.js]
[browser_inspector_highlighter-rulers_01.js]
[browser_inspector_highlighter-rulers_02.js]
[browser_inspector_highlighter-selector_01.js]
[browser_inspector_highlighter-selector_02.js]
[browser_inspector_highlighter-xbl.js]
[browser_inspector_highlighter-zoom.js]
[browser_inspector_iframe-navigation.js]
[browser_inspector_infobar_01.js]
[browser_inspector_infobar_02.js]
[browser_inspector_infobar_03.js]
[browser_inspector_infobar_textnode.js]
[browser_inspector_initialization.js]
skip-if = (e10s && debug) # Bug 1250058 - Docshell leak on debug e10s
[browser_inspector_inspect-object-element.js]
[browser_inspector_invalidate.js]
[browser_inspector_keyboard-shortcuts-copy-outerhtml.js]
subsuite = clipboard
[browser_inspector_keyboard-shortcuts.js]
[browser_inspector_menu-01-sensitivity.js]
subsuite = clipboard
[browser_inspector_menu-02-copy-items.js]
subsuite = clipboard
[browser_inspector_menu-03-paste-items.js]
subsuite = clipboard
[browser_inspector_menu-03-paste-items-svg.js]
subsuite = clipboard
[browser_inspector_menu-04-use-in-console.js]
[browser_inspector_menu-05-attribute-items.js]
[browser_inspector_menu-06-other.js]
[browser_inspector_navigation.js]
[browser_inspector_navigate_to_errors.js]
[browser_inspector_open_on_neterror.js]
[browser_inspector_pane-toggle-01.js]
[browser_inspector_pane-toggle-02.js]
[browser_inspector_pane-toggle-03.js]
[browser_inspector_pane-toggle-05.js]
skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard
[browser_inspector_picker-stop-on-destroy.js]
[browser_inspector_picker-stop-on-tool-change.js]
[browser_inspector_portrait_mode.js]
[browser_inspector_pseudoclass-lock.js]
[browser_inspector_pseudoclass-menu.js]
[browser_inspector_reload-01.js]
[browser_inspector_reload-02.js]
[browser_inspector_remove-iframe-during-load.js]
[browser_inspector_search-01.js]
[browser_inspector_search-02.js]
[browser_inspector_search-03.js]
[browser_inspector_search-04.js]
[browser_inspector_search-05.js]
[browser_inspector_search-06.js]
[browser_inspector_search-07.js]
[browser_inspector_search-08.js]
[browser_inspector_search-clear.js]
[browser_inspector_search-filter_context-menu.js]
subsuite = clipboard
[browser_inspector_search_keyboard_trap.js]
[browser_inspector_search-label.js]
[browser_inspector_search-reserved.js]
[browser_inspector_search-selection.js]
[browser_inspector_search-sidebar.js]
[browser_inspector_select-docshell.js]
[browser_inspector_select-last-selected.js]
[browser_inspector_search-navigation.js]
[browser_inspector_sidebarstate.js]
[browser_inspector_switch-to-inspector-on-pick.js]
[browser_inspector_textbox-menu.js]

View file

@ -0,0 +1,22 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the add node button and context menu items are present in the UI.
const TEST_URL = "data:text/html;charset=utf-8,<h1>Add node</h1>";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
let {panelDoc} = inspector;
let allMenuItems = openContextMenuAndGetAllItems(inspector);
let menuItem = allMenuItems.find(item => item.id === "node-menu-add");
ok(menuItem, "The item is in the menu");
let toolbarButton =
panelDoc.querySelector("#inspector-toolbar #inspector-element-add-button");
ok(toolbarButton, "The add button is in the toolbar");
});

View file

@ -0,0 +1,63 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the add node button and context menu items have the right state
// depending on the current selection.
const TEST_URL = URL_ROOT + "doc_inspector_add_node.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Select the DOCTYPE element");
let {nodes} = yield inspector.walker.children(inspector.walker.rootNode);
yield selectNode(nodes[0], inspector);
assertState(false, inspector,
"The button and item are disabled on DOCTYPE");
info("Select the ::before pseudo-element");
let body = yield getNodeFront("body", inspector);
({nodes} = yield inspector.walker.children(body));
yield selectNode(nodes[0], inspector);
assertState(false, inspector,
"The button and item are disabled on a pseudo-element");
info("Select the svg element");
yield selectNode("svg", inspector);
assertState(false, inspector,
"The button and item are disabled on a SVG element");
info("Select the div#foo element");
yield selectNode("#foo", inspector);
assertState(true, inspector,
"The button and item are enabled on a DIV element");
info("Select the documentElement element (html)");
yield selectNode("html", inspector);
assertState(false, inspector,
"The button and item are disabled on the documentElement");
info("Select the iframe element");
yield selectNode("iframe", inspector);
assertState(false, inspector,
"The button and item are disabled on an IFRAME element");
});
function assertState(isEnabled, inspector, desc) {
let doc = inspector.panelDoc;
let btn = doc.querySelector("#inspector-element-add-button");
// Force an update of the context menu to make sure menu items are updated
// according to the current selection. This normally happens when the menu is
// opened, but for the sake of this test's simplicity, we directly call the
// private update function instead.
let allMenuItems = openContextMenuAndGetAllItems(inspector);
let menuItem = allMenuItems.find(item => item.id === "node-menu-add");
ok(menuItem, "The item is in the menu");
is(!menuItem.disabled, isEnabled, desc);
is(!btn.hasAttribute("disabled"), isEnabled, desc);
}

View file

@ -0,0 +1,84 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that adding nodes does work as expected: the parent gets expanded, the
// new node gets selected.
const TEST_URL = URL_ROOT + "doc_inspector_add_node.html";
const PARENT_TREE_LEVEL = 3;
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Adding in element that has no children and is collapsed");
let parentNode = yield getNodeFront("#foo", inspector);
yield selectNode(parentNode, inspector);
yield testAddNode(parentNode, inspector);
info("Adding in element with children but that has not been expanded yet");
parentNode = yield getNodeFront("#bar", inspector);
yield selectNode(parentNode, inspector);
yield testAddNode(parentNode, inspector);
info("Adding in element with children that has been expanded then collapsed");
// Select again #bar and collapse it.
parentNode = yield getNodeFront("#bar", inspector);
yield selectNode(parentNode, inspector);
collapseNode(parentNode, inspector);
yield testAddNode(parentNode, inspector);
info("Adding in element with children that is expanded");
parentNode = yield getNodeFront("#bar", inspector);
yield selectNode(parentNode, inspector);
yield testAddNode(parentNode, inspector);
});
function* testAddNode(parentNode, inspector) {
let btn = inspector.panelDoc.querySelector("#inspector-element-add-button");
let markupWindow = inspector.markup.win;
let parentContainer = inspector.markup.getContainer(parentNode);
is(parentContainer.tagLine.getAttribute("aria-level"), PARENT_TREE_LEVEL,
"Parent level should be up to date.");
info("Clicking 'add node' and expecting a markup mutation and focus event");
let onMutation = inspector.once("markupmutation");
btn.click();
let mutations = yield onMutation;
info("Expecting an inspector-updated event right after the mutation event " +
"to wait for the new node selection");
yield inspector.once("inspector-updated");
is(mutations.length, 1, "There is one mutation only");
is(mutations[0].added.length, 1, "There is one new node only");
let newNode = mutations[0].added[0];
is(newNode, inspector.selection.nodeFront,
"The new node is selected");
ok(parentContainer.expanded, "The parent node is now expanded");
is(inspector.selection.nodeFront.parentNode(), parentNode,
"The new node is inside the right parent");
let focusedElement = markupWindow.document.activeElement;
let focusedContainer = focusedElement.container;
let selectedContainer = inspector.markup._selectedContainer;
is(selectedContainer.tagLine.getAttribute("aria-level"),
PARENT_TREE_LEVEL + 1, "Added container level should be up to date.");
is(selectedContainer.node, inspector.selection.nodeFront,
"The right container is selected in the markup-view");
ok(selectedContainer.selected, "Selected container is set to selected");
is(focusedContainer.toString(), "[root container]",
"Root container is focused");
}
function collapseNode(node, inspector) {
let container = inspector.markup.getContainer(node);
container.setExpanded(false);
}

View file

@ -0,0 +1,62 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const TEST_URI = "data:text/html;charset=UTF-8," +
"<h1>browser_inspector_addtabbar.js</h1>";
const CONTENT_TEXT = "Hello World!";
/**
* Verify InspectorPanel.addSidebarTab() API that can be consumed
* by DevTools extensions as well as DevTools code base.
*/
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URI);
const React = inspector.React;
const { div } = React.DOM;
info("Adding custom panel.");
// Define custom side-panel.
let tabPanel = React.createFactory(React.createClass({
displayName: "myTabPanel",
render: function () {
return (
div({className: "my-tab-panel"},
CONTENT_TEXT
)
);
}
}));
// Append custom panel (tab) into the Inspector panel and
// make sure it's selected by default (the last arg = true).
inspector.addSidebarTab("myPanel", "My Panel", tabPanel, true);
is(inspector.sidebar.getCurrentTabID(), "myPanel",
"My Panel is selected by default");
// Define another custom side-panel.
tabPanel = React.createFactory(React.createClass({
displayName: "myTabPanel2",
render: function () {
return (
div({className: "my-tab-panel2"},
"Another Content"
)
);
}
}));
// Append second panel, but don't select it by default.
inspector.addSidebarTab("myPanel", "My Panel", tabPanel, false);
is(inspector.sidebar.getCurrentTabID(), "myPanel",
"My Panel is selected by default");
// Check the the panel content is properly rendered.
let tabPanelNode = inspector.panelDoc.querySelector(".my-tab-panel");
is(tabPanelNode.textContent, CONTENT_TEXT,
"Side panel content has been rendered.");
});

View file

@ -0,0 +1,132 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the breadcrumbs widget content is correct.
const TEST_URI = URL_ROOT + "doc_inspector_breadcrumbs.html";
const NODES = [
{selector: "#i1111", ids: "i1 i11 i111 i1111", nodeName: "div",
title: "div#i1111"},
{selector: "#i22", ids: "i2 i22", nodeName: "div",
title: "div#i22"},
{selector: "#i2111", ids: "i2 i21 i211 i2111", nodeName: "div",
title: "div#i2111"},
{selector: "#i21", ids: "i2 i21 i211 i2111", nodeName: "div",
title: "div#i21"},
{selector: "#i22211", ids: "i2 i22 i222 i2221 i22211", nodeName: "div",
title: "div#i22211"},
{selector: "#i22", ids: "i2 i22 i222 i2221 i22211", nodeName: "div",
title: "div#i22"},
{selector: "#i3", ids: "i3", nodeName: "article",
title: "article#i3"},
{selector: "clipPath", ids: "vector clip", nodeName: "clipPath",
title: "clipPath#clip"},
];
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URI);
let breadcrumbs = inspector.panelDoc.getElementById("inspector-breadcrumbs");
let container = breadcrumbs.querySelector(".html-arrowscrollbox-inner");
for (let node of NODES) {
info("Testing node " + node.selector);
info("Selecting node and waiting for breadcrumbs to update");
let breadcrumbsUpdated = inspector.once("breadcrumbs-updated");
yield selectNode(node.selector, inspector);
yield breadcrumbsUpdated;
info("Performing checks for node " + node.selector);
let buttonsLabelIds = node.ids.split(" ");
// html > body > …
is(container.childNodes.length, buttonsLabelIds.length + 2,
"Node " + node.selector + ": Items count");
for (let i = 2; i < container.childNodes.length; i++) {
let expectedId = "#" + buttonsLabelIds[i - 2];
let button = container.childNodes[i];
let labelId = button.querySelector(".breadcrumbs-widget-item-id");
is(labelId.textContent, expectedId,
"Node " + node.selector + ": button " + i + " matches");
}
let checkedButton = container.querySelector("button[checked]");
let labelId = checkedButton.querySelector(".breadcrumbs-widget-item-id");
let id = inspector.selection.nodeFront.id;
is(labelId.textContent, "#" + id,
"Node " + node.selector + ": selection matches");
let labelTag = checkedButton.querySelector(".breadcrumbs-widget-item-tag");
is(labelTag.textContent, node.nodeName,
"Node " + node.selector + " has the expected tag name");
is(checkedButton.getAttribute("title"), node.title,
"Node " + node.selector + " has the expected tooltip");
}
yield testPseudoElements(inspector, container);
yield testComments(inspector, container);
});
function* testPseudoElements(inspector, container) {
info("Checking for pseudo elements");
let pseudoParent = yield getNodeFront("#pseudo-container", inspector);
let children = yield inspector.walker.children(pseudoParent);
is(children.nodes.length, 2, "Pseudo children returned from walker");
let beforeElement = children.nodes[0];
let breadcrumbsUpdated = inspector.once("breadcrumbs-updated");
yield selectNode(beforeElement, inspector);
yield breadcrumbsUpdated;
is(container.childNodes[3].textContent, "::before",
"::before shows up in breadcrumb");
let afterElement = children.nodes[1];
breadcrumbsUpdated = inspector.once("breadcrumbs-updated");
yield selectNode(afterElement, inspector);
yield breadcrumbsUpdated;
is(container.childNodes[3].textContent, "::after",
"::before shows up in breadcrumb");
}
function* testComments(inspector, container) {
info("Checking for comment elements");
let breadcrumbs = inspector.breadcrumbs;
let checkedButtonIndex = 2;
let button = container.childNodes[checkedButtonIndex];
let onBreadcrumbsUpdated = inspector.once("breadcrumbs-updated");
button.click();
yield onBreadcrumbsUpdated;
is(breadcrumbs.currentIndex, checkedButtonIndex, "New button is selected");
ok(breadcrumbs.outer.hasAttribute("aria-activedescendant"),
"Active descendant must be set");
let comment = [...inspector.markup._containers].find(([node]) =>
node.nodeType === Ci.nsIDOMNode.COMMENT_NODE)[0];
let onInspectorUpdated = inspector.once("inspector-updated");
inspector.selection.setNodeFront(comment);
yield onInspectorUpdated;
is(breadcrumbs.currentIndex, -1,
"When comment is selected no breadcrumb should be checked");
ok(!breadcrumbs.outer.hasAttribute("aria-activedescendant"),
"Active descendant must not be set");
onInspectorUpdated = inspector.once("inspector-updated");
onBreadcrumbsUpdated = inspector.once("breadcrumbs-updated");
button.click();
yield Promise.all([onInspectorUpdated, onBreadcrumbsUpdated]);
is(breadcrumbs.currentIndex, checkedButtonIndex,
"Same button is selected again");
ok(breadcrumbs.outer.hasAttribute("aria-activedescendant"),
"Active descendant must be set again");
}

View file

@ -0,0 +1,47 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that hovering over nodes on the breadcrumb buttons in the inspector
// shows the highlighter over those nodes
add_task(function* () {
info("Loading the test document and opening the inspector");
let {toolbox, inspector, testActor} = yield openInspectorForURL(
"data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>");
info("Selecting the test node");
yield selectNode("span", inspector);
let bcButtons = inspector.breadcrumbs.container;
let onNodeHighlighted = toolbox.once("node-highlight");
let button = bcButtons.childNodes[1];
EventUtils.synthesizeMouseAtCenter(button, {type: "mousemove"},
button.ownerDocument.defaultView);
yield onNodeHighlighted;
let isVisible = yield testActor.isHighlighting();
ok(isVisible, "The highlighter is shown on a markup container hover");
ok((yield testActor.assertHighlightedNode("body")),
"The highlighter highlights the right node");
let onNodeUnhighlighted = toolbox.once("node-unhighlight");
// move outside of the breadcrumb trail to trigger unhighlight
EventUtils.synthesizeMouseAtCenter(inspector.addNodeButton,
{type: "mousemove"},
inspector.addNodeButton.ownerDocument.defaultView);
yield onNodeUnhighlighted;
onNodeHighlighted = toolbox.once("node-highlight");
button = bcButtons.childNodes[2];
EventUtils.synthesizeMouseAtCenter(button, {type: "mousemove"},
button.ownerDocument.defaultView);
yield onNodeHighlighted;
isVisible = yield testActor.isHighlighting();
ok(isVisible, "The highlighter is shown on a markup container hover");
ok((yield testActor.assertHighlightedNode("span")),
"The highlighter highlights the right node");
});

View file

@ -0,0 +1,71 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the breadcrumbs keybindings work.
const TEST_URI = URL_ROOT + "doc_inspector_breadcrumbs.html";
const TEST_DATA = [{
desc: "Pressing left should select the parent <body>",
key: "VK_LEFT",
newSelection: "body"
}, {
desc: "Pressing left again should select the parent <html>",
key: "VK_LEFT",
newSelection: "html"
}, {
desc: "Pressing left again should stay on <html>, it's the first element",
key: "VK_LEFT",
newSelection: "html"
}, {
desc: "Pressing right should go to <body>",
key: "VK_RIGHT",
newSelection: "body"
}, {
desc: "Pressing right again should go to #i2",
key: "VK_RIGHT",
newSelection: "#i2"
}, {
desc: "Pressing right again should stay on #i2, it's the last element",
key: "VK_RIGHT",
newSelection: "#i2"
}];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URI);
info("Selecting the test node");
yield selectNode("#i2", inspector);
info("Clicking on the corresponding breadcrumbs node to focus it");
let container = inspector.panelDoc.getElementById("inspector-breadcrumbs");
let button = container.querySelector("button[checked]");
button.click();
let currentSelection = "#id2";
for (let {desc, key, newSelection} of TEST_DATA) {
info(desc);
// If the selection will change, wait for the breadcrumb to update,
// otherwise continue.
let onUpdated = null;
if (newSelection !== currentSelection) {
info("Expecting a new node to be selected");
onUpdated = inspector.once("breadcrumbs-updated");
}
EventUtils.synthesizeKey(key, {});
yield onUpdated;
let newNodeFront = yield getNodeFront(newSelection, inspector);
is(newNodeFront, inspector.selection.nodeFront,
"The current selection is correct");
is(container.getAttribute("aria-activedescendant"),
container.querySelector("button[checked]").id,
"aria-activedescendant is set correctly");
currentSelection = newSelection;
}
});

View file

@ -0,0 +1,83 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test ability to tab to and away from breadcrumbs using keyboard.
const TEST_URL = URL_ROOT + "doc_inspector_breadcrumbs.html";
/**
* Test data has the format of:
* {
* desc {String} description for better logging
* focused {Boolean} flag, indicating if breadcrumbs contain focus
* key {String} key event's key
* options {?Object} optional event data such as shiftKey, etc
* }
*/
const TEST_DATA = [
{
desc: "Move the focus away from breadcrumbs to a next focusable element",
focused: false,
key: "VK_TAB",
options: { }
},
{
desc: "Move the focus back to the breadcrumbs",
focused: true,
key: "VK_TAB",
options: { shiftKey: true }
},
{
desc: "Move the focus back away from breadcrumbs to a previous focusable " +
"element",
focused: false,
key: "VK_TAB",
options: { shiftKey: true }
},
{
desc: "Move the focus back to the breadcrumbs",
focused: true,
key: "VK_TAB",
options: { }
}
];
add_task(function* () {
let { toolbox, inspector } = yield openInspectorForURL(TEST_URL);
let doc = inspector.panelDoc;
let {breadcrumbs} = inspector;
yield selectNode("#i2", inspector);
info("Clicking on the corresponding breadcrumbs node to focus it");
let container = doc.getElementById("inspector-breadcrumbs");
let button = container.querySelector("button[checked]");
let onHighlight = toolbox.once("node-highlight");
button.click();
yield onHighlight;
// Ensure a breadcrumb is focused.
is(doc.activeElement, container, "Focus is on selected breadcrumb");
is(container.getAttribute("aria-activedescendant"), button.id,
"aria-activedescendant is set correctly");
for (let { desc, focused, key, options } of TEST_DATA) {
info(desc);
EventUtils.synthesizeKey(key, options);
// Wait until the keyPromise promise resolves.
yield breadcrumbs.keyPromise;
if (focused) {
is(doc.activeElement, container, "Focus is on selected breadcrumb");
} else {
ok(!containsFocus(doc, container), "Focus is outside of breadcrumbs");
}
is(container.getAttribute("aria-activedescendant"), button.id,
"aria-activedescendant is set correctly");
}
});

View file

@ -0,0 +1,212 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the breadcrumbs widget refreshes correctly when there are markup
// mutations (and that it doesn't refresh when those mutations don't change its
// output).
const TEST_URI = URL_ROOT + "doc_inspector_breadcrumbs.html";
// Each item in the TEST_DATA array is a test case that should contain the
// following properties:
// - desc {String} A description of this test case (will be logged).
// - setup {Function*} A generator function (can yield promises) that sets up
// the test case. Useful for selecting a node before starting the test.
// - run {Function*} A generator function (can yield promises) that runs the
// actual test case, i.e, mutates the content DOM to cause the breadcrumbs
// to refresh, or not.
// - shouldRefresh {Boolean} Once the `run` function has completed, and the test
// has detected that the page has changed, this boolean instructs the test to
// verify if the breadcrumbs has refreshed or not.
// - output {Array} A list of strings for the text that should be found in each
// button after the test has run.
const TEST_DATA = [{
desc: "Adding a child at the end of the chain shouldn't change anything",
setup: function* (inspector) {
yield selectNode("#i1111", inspector);
},
run: function* ({walker, selection}) {
yield walker.setInnerHTML(selection.nodeFront, "<b>test</b>");
},
shouldRefresh: false,
output: ["html", "body", "article#i1", "div#i11", "div#i111", "div#i1111"]
}, {
desc: "Updating an ID to an displayed element should refresh",
setup: function* () {},
run: function* ({walker}) {
let node = yield walker.querySelector(walker.rootNode, "#i1");
yield node.modifyAttributes([{
attributeName: "id",
newValue: "i1-changed"
}]);
},
shouldRefresh: true,
output: ["html", "body", "article#i1-changed", "div#i11", "div#i111",
"div#i1111"]
}, {
desc: "Updating an class to a displayed element should refresh",
setup: function* () {},
run: function* ({walker}) {
let node = yield walker.querySelector(walker.rootNode, "body");
yield node.modifyAttributes([{
attributeName: "class",
newValue: "test-class"
}]);
},
shouldRefresh: true,
output: ["html", "body.test-class", "article#i1-changed", "div#i11",
"div#i111", "div#i1111"]
}, {
desc: "Updating a non id/class attribute to a displayed element should not " +
"refresh",
setup: function* () {},
run: function* ({walker}) {
let node = yield walker.querySelector(walker.rootNode, "#i11");
yield node.modifyAttributes([{
attributeName: "name",
newValue: "value"
}]);
},
shouldRefresh: false,
output: ["html", "body.test-class", "article#i1-changed", "div#i11",
"div#i111", "div#i1111"]
}, {
desc: "Moving a child in an element that's not displayed should not refresh",
setup: function* () {},
run: function* ({walker}) {
// Re-append #i1211 as a last child of #i2.
let parent = yield walker.querySelector(walker.rootNode, "#i2");
let child = yield walker.querySelector(walker.rootNode, "#i211");
yield walker.insertBefore(child, parent);
},
shouldRefresh: false,
output: ["html", "body.test-class", "article#i1-changed", "div#i11",
"div#i111", "div#i1111"]
}, {
desc: "Moving an undisplayed child in a displayed element should not refresh",
setup: function* () {},
run: function* ({walker}) {
// Re-append #i2 in body (move it to the end).
let parent = yield walker.querySelector(walker.rootNode, "body");
let child = yield walker.querySelector(walker.rootNode, "#i2");
yield walker.insertBefore(child, parent);
},
shouldRefresh: false,
output: ["html", "body.test-class", "article#i1-changed", "div#i11",
"div#i111", "div#i1111"]
}, {
desc: "Updating attributes on an element that's not displayed should not " +
"refresh",
setup: function* () {},
run: function* ({walker}) {
let node = yield walker.querySelector(walker.rootNode, "#i2");
yield node.modifyAttributes([{
attributeName: "id",
newValue: "i2-changed"
}, {
attributeName: "class",
newValue: "test-class"
}]);
},
shouldRefresh: false,
output: ["html", "body.test-class", "article#i1-changed", "div#i11",
"div#i111", "div#i1111"]
}, {
desc: "Removing the currently selected node should refresh",
setup: function* (inspector) {
yield selectNode("#i2-changed", inspector);
},
run: function* ({walker, selection}) {
yield walker.removeNode(selection.nodeFront);
},
shouldRefresh: true,
output: ["html", "body.test-class"]
}, {
desc: "Changing the class of the currently selected node should refresh",
setup: function* () {},
run: function* ({selection}) {
yield selection.nodeFront.modifyAttributes([{
attributeName: "class",
newValue: "test-class-changed"
}]);
},
shouldRefresh: true,
output: ["html", "body.test-class-changed"]
}, {
desc: "Changing the id of the currently selected node should refresh",
setup: function* () {},
run: function* ({selection}) {
yield selection.nodeFront.modifyAttributes([{
attributeName: "id",
newValue: "new-id"
}]);
},
shouldRefresh: true,
output: ["html", "body#new-id.test-class-changed"]
}];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URI);
let breadcrumbs = inspector.panelDoc.getElementById("inspector-breadcrumbs");
let container = breadcrumbs.querySelector(".html-arrowscrollbox-inner");
let win = container.ownerDocument.defaultView;
for (let {desc, setup, run, shouldRefresh, output} of TEST_DATA) {
info("Running test case: " + desc);
info("Listen to markupmutation events from the inspector to know when a " +
"test case has completed");
let onContentMutation = inspector.once("markupmutation");
info("Running setup");
yield setup(inspector);
info("Listen to mutations on the breadcrumbs container");
let hasBreadcrumbsMutated = false;
let observer = new win.MutationObserver(mutations => {
// Only consider childList changes or tooltiptext/checked attributes
// changes. The rest may be mutations caused by the overflowing arrowbox.
for (let {type, attributeName} of mutations) {
let isChildList = type === "childList";
let isAttributes = type === "attributes" &&
(attributeName === "checked" ||
attributeName === "tooltiptext");
if (isChildList || isAttributes) {
hasBreadcrumbsMutated = true;
break;
}
}
});
observer.observe(container, {
attributes: true,
childList: true,
subtree: true
});
info("Running the test case");
yield run(inspector);
info("Wait until the page has mutated");
yield onContentMutation;
if (shouldRefresh) {
info("The breadcrumbs is expected to refresh, so wait for it");
yield inspector.once("inspector-updated");
} else {
ok(!inspector._updateProgress,
"The breadcrumbs widget is not currently updating");
}
is(shouldRefresh, hasBreadcrumbsMutated, "Has the breadcrumbs refreshed?");
observer.disconnect();
info("Check the output of the breadcrumbs widget");
is(container.childNodes.length, output.length, "Correct number of buttons");
for (let i = 0; i < container.childNodes.length; i++) {
is(output[i], container.childNodes[i].textContent,
"Text content for button " + i + " is correct");
}
}
});

View file

@ -0,0 +1,55 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the breadcrumbs widget content for namespaced elements is correct.
const XHTML = `
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:svg="http://www.w3.org/2000/svg">
<body>
<svg:svg width="100" height="100">
<svg:clipPath id="clip">
<svg:rect id="rectangle" x="0" y="0" width="10" height="5"></svg:rect>
</svg:clipPath>
<svg:circle cx="0" cy="0" r="5"></svg:circle>
</svg:svg>
</body>
</html>
`;
const TEST_URI = "data:application/xhtml+xml;charset=utf-8," + encodeURI(XHTML);
const NODES = [
{selector: "clipPath", nodes: ["svg:svg", "svg:clipPath"],
nodeName: "svg:clipPath", title: "svg:clipPath#clip"},
{selector: "circle", nodes: ["svg:svg", "svg:circle"],
nodeName: "svg:circle", title: "svg:circle"},
];
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URI);
let container = inspector.panelDoc.getElementById("inspector-breadcrumbs");
for (let node of NODES) {
info("Testing node " + node.selector);
info("Selecting node and waiting for breadcrumbs to update");
let breadcrumbsUpdated = inspector.once("breadcrumbs-updated");
yield selectNode(node.selector, inspector);
yield breadcrumbsUpdated;
info("Performing checks for node " + node.selector);
let checkedButton = container.querySelector("button[checked]");
let labelTag = checkedButton.querySelector(".breadcrumbs-widget-item-tag");
is(labelTag.textContent, node.nodeName,
"Node " + node.selector + " has the expected tag name");
is(checkedButton.getAttribute("title"), node.title,
"Node " + node.selector + " has the expected tooltip");
}
});

View file

@ -0,0 +1,110 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the start and end buttons on the breadcrumb trail bring the right
// crumbs into the visible area, for both LTR and RTL
let { Toolbox } = require("devtools/client/framework/toolbox");
const TEST_URI = URL_ROOT + "doc_inspector_breadcrumbs_visibility.html";
const NODE_ONE = "div#aVeryLongIdToExceedTheBreadcrumbTruncationLimit";
const NODE_TWO = "div#anotherVeryLongIdToExceedTheBreadcrumbTruncationLimit";
const NODE_THREE = "div#aThirdVeryLongIdToExceedTheTruncationLimit";
const NODE_FOUR = "div#aFourthOneToExceedTheTruncationLimit";
const NODE_FIVE = "div#aFifthOneToExceedTheTruncationLimit";
const NODE_SIX = "div#aSixthOneToExceedTheTruncationLimit";
const NODE_SEVEN = "div#aSeventhOneToExceedTheTruncationLimit";
const NODES = [
{ action: "start", title: NODE_SIX },
{ action: "start", title: NODE_FIVE },
{ action: "start", title: NODE_FOUR },
{ action: "start", title: NODE_THREE },
{ action: "start", title: NODE_TWO },
{ action: "start", title: NODE_ONE },
{ action: "end", title: NODE_TWO },
{ action: "end", title: NODE_THREE },
{ action: "end", title: NODE_FOUR },
{ action: "end", title: NODE_FIVE },
{ action: "end", title: NODE_SIX }
];
add_task(function* () {
// This test needs specific initial size of the sidebar.
yield pushPref("devtools.toolsidebar-width.inspector", 350);
yield pushPref("devtools.toolsidebar-height.inspector", 150);
let { inspector, toolbox } = yield openInspectorForURL(TEST_URI);
// No way to wait for scrolling to end (Bug 1172171)
// Rather than wait a max time; limit test to instant scroll behavior
inspector.breadcrumbs.arrowScrollBox.scrollBehavior = "instant";
yield toolbox.switchHost(Toolbox.HostType.WINDOW);
let hostWindow = toolbox.win.parent;
let originalWidth = hostWindow.outerWidth;
let originalHeight = hostWindow.outerHeight;
hostWindow.resizeTo(640, 300);
info("Testing transitions ltr");
yield pushPref("intl.uidirection.en-US", "ltr");
yield testBreadcrumbTransitions(hostWindow, inspector);
info("Testing transitions rtl");
yield pushPref("intl.uidirection.en-US", "rtl");
yield testBreadcrumbTransitions(hostWindow, inspector);
hostWindow.resizeTo(originalWidth, originalHeight);
});
function* testBreadcrumbTransitions(hostWindow, inspector) {
let breadcrumbs = inspector.panelDoc.getElementById("inspector-breadcrumbs");
let startBtn = breadcrumbs.querySelector(".scrollbutton-up");
let endBtn = breadcrumbs.querySelector(".scrollbutton-down");
let container = breadcrumbs.querySelector(".html-arrowscrollbox-inner");
let breadcrumbsUpdated = inspector.once("breadcrumbs-updated");
info("Selecting initial node");
yield selectNode(NODE_SEVEN, inspector);
// So just need to wait for a duration
yield breadcrumbsUpdated;
let initialCrumb = container.querySelector("button[checked]");
is(isElementInViewport(hostWindow, initialCrumb), true,
"initial element was visible");
for (let node of NODES) {
info("Checking for visibility of crumb " + node.title);
if (node.action === "end") {
info("Simulating click of end button");
EventUtils.synthesizeMouseAtCenter(endBtn, {}, inspector.panelWin);
} else if (node.action === "start") {
info("Simulating click of start button");
EventUtils.synthesizeMouseAtCenter(startBtn, {}, inspector.panelWin);
}
yield breadcrumbsUpdated;
let selector = "button[title=\"" + node.title + "\"]";
let relevantCrumb = container.querySelector(selector);
is(isElementInViewport(hostWindow, relevantCrumb), true,
node.title + " crumb is visible");
}
}
function isElementInViewport(window, el) {
let rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= window.innerHeight &&
rect.right <= window.innerWidth
);
}
registerCleanupFunction(function () {
// Restore the host type for other tests.
Services.prefs.clearUserPref("devtools.toolbox.host");
});

View file

@ -0,0 +1,24 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test to ensure inspector handles deletion of selected node correctly.
const TEST_URL = URL_ROOT + "doc_inspector_delete-selected-node-01.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
let span = yield getNodeFrontInFrame("span", "iframe", inspector);
yield selectNode(span, inspector);
info("Removing selected <span> element.");
let parentNode = span.parentNode();
yield inspector.walker.removeNode(span);
// Wait for the inspector to process the mutation
yield inspector.once("inspector-updated");
is(inspector.selection.nodeFront, parentNode,
"Parent node of selected <span> got selected.");
});

View file

@ -0,0 +1,154 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that when nodes are being deleted in the page, the current selection
// and therefore the markup view, css rule view, computed view, font view,
// box model view, and breadcrumbs, reset accordingly to show the right node
const TEST_PAGE = URL_ROOT +
"doc_inspector_delete-selected-node-02.html";
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_PAGE);
yield testManuallyDeleteSelectedNode();
yield testAutomaticallyDeleteSelectedNode();
yield testDeleteSelectedNodeContainerFrame();
yield testDeleteWithNonElementNode();
function* testManuallyDeleteSelectedNode() {
info("Selecting a node, deleting it via context menu and checking that " +
"its parent node is selected and breadcrumbs are updated.");
yield deleteNodeWithContextMenu("#deleteManually");
info("Performing checks.");
yield assertNodeSelectedAndPanelsUpdated("#selectedAfterDelete",
"li#selectedAfterDelete");
}
function* testAutomaticallyDeleteSelectedNode() {
info("Selecting a node, deleting it via javascript and checking that " +
"its parent node is selected and breadcrumbs are updated.");
let div = yield getNodeFront("#deleteAutomatically", inspector);
yield selectNode(div, inspector);
info("Deleting selected node via javascript.");
yield inspector.walker.removeNode(div);
info("Waiting for inspector to update.");
yield inspector.once("inspector-updated");
info("Inspector updated, performing checks.");
yield assertNodeSelectedAndPanelsUpdated("#deleteChildren",
"ul#deleteChildren");
}
function* testDeleteSelectedNodeContainerFrame() {
info("Selecting a node inside iframe, deleting the iframe via javascript " +
"and checking the parent node of the iframe is selected and " +
"breadcrumbs are updated.");
info("Selecting an element inside iframe.");
let iframe = yield getNodeFront("#deleteIframe", inspector);
let div = yield getNodeFrontInFrame("#deleteInIframe", iframe, inspector);
yield selectNode(div, inspector);
info("Deleting selected node via javascript.");
yield inspector.walker.removeNode(iframe);
info("Waiting for inspector to update.");
yield inspector.once("inspector-updated");
info("Inspector updated, performing checks.");
yield assertNodeSelectedAndPanelsUpdated("body", "body");
}
function* testDeleteWithNonElementNode() {
info("Selecting a node, deleting it via context menu and checking that " +
"its parent node is selected and breadcrumbs are updated " +
"when the node is followed by a non-element node");
yield deleteNodeWithContextMenu("#deleteWithNonElement");
let expectedCrumbs = ["html", "body", "div#deleteToMakeSingleTextNode"];
yield assertNodeSelectedAndCrumbsUpdated(expectedCrumbs,
Node.TEXT_NODE);
// Delete node with key, as cannot delete text node with
// context menu at this time.
inspector.markup._frame.focus();
EventUtils.synthesizeKey("VK_DELETE", {});
yield inspector.once("inspector-updated");
expectedCrumbs = ["html", "body", "div#deleteToMakeSingleTextNode"];
yield assertNodeSelectedAndCrumbsUpdated(expectedCrumbs,
Node.ELEMENT_NODE);
}
function* deleteNodeWithContextMenu(selector) {
yield selectNode(selector, inspector);
let nodeToBeDeleted = inspector.selection.nodeFront;
info("Getting the node container in the markup view.");
let container = yield getContainerForSelector(selector, inspector);
let allMenuItems = openContextMenuAndGetAllItems(inspector, {
target: container.tagLine,
});
let menuItem = allMenuItems.find(item => item.id === "node-menu-delete");
info("Clicking 'Delete Node' in the context menu.");
is(menuItem.disabled, false, "delete menu item is enabled");
menuItem.click();
// close the open context menu
EventUtils.synthesizeKey("VK_ESCAPE", {});
info("Waiting for inspector to update.");
yield inspector.once("inspector-updated");
// Since the mutations are sent asynchronously from the server, the
// inspector-updated event triggered by the deletion might happen before
// the mutation is received and the element is removed from the
// breadcrumbs. See bug 1284125.
if (inspector.breadcrumbs.indexOf(nodeToBeDeleted) > -1) {
info("Crumbs haven't seen deletion. Waiting for breadcrumbs-updated.");
yield inspector.once("breadcrumbs-updated");
}
return menuItem;
}
function* assertNodeSelectedAndCrumbsUpdated(expectedCrumbs,
expectedNodeType) {
info("Performing checks");
let actualNodeType = inspector.selection.nodeFront.nodeType;
is(actualNodeType, expectedNodeType, "The node has the right type");
let breadcrumbs = inspector.panelDoc.querySelectorAll(
"#inspector-breadcrumbs .html-arrowscrollbox-inner > *");
is(breadcrumbs.length, expectedCrumbs.length,
"Have the correct number of breadcrumbs");
for (let i = 0; i < breadcrumbs.length; i++) {
is(breadcrumbs[i].textContent, expectedCrumbs[i],
"Text content for button " + i + " is correct");
}
}
function* assertNodeSelectedAndPanelsUpdated(selector, crumbLabel) {
let nodeFront = yield getNodeFront(selector, inspector);
is(inspector.selection.nodeFront, nodeFront, "The right node is selected");
let breadcrumbs = inspector.panelDoc.querySelector(
"#inspector-breadcrumbs .html-arrowscrollbox-inner");
is(breadcrumbs.querySelector("button[checked=true]").textContent,
crumbLabel,
"The right breadcrumb is selected");
}
});

View file

@ -0,0 +1,27 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test to ensure inspector can handle destruction of selected node inside an
// iframe.
const TEST_URL = URL_ROOT + "doc_inspector_delete-selected-node-01.html";
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URL);
let iframe = yield getNodeFront("iframe", inspector);
let node = yield getNodeFrontInFrame("span", iframe, inspector);
yield selectNode(node, inspector);
info("Removing iframe.");
yield inspector.walker.removeNode(iframe);
yield inspector.selection.once("detached-front");
let body = yield getNodeFront("body", inspector);
is(inspector.selection.nodeFront, body, "Selection is now the body node");
yield inspector.once("inspector-updated");
});

View file

@ -0,0 +1,24 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Testing that closing the inspector after navigating to a page doesn't fail.
const URL_1 = "data:text/plain;charset=UTF-8,abcde";
const URL_2 = "data:text/plain;charset=UTF-8,12345";
add_task(function* () {
let { inspector, toolbox } = yield openInspectorForURL(URL_1);
yield navigateTo(inspector, URL_2);
info("Destroying toolbox");
try {
yield toolbox.destroy();
ok(true, "Toolbox destroyed");
} catch (e) {
ok(false, "An exception occured while destroying toolbox");
console.error(e);
}
});

View file

@ -0,0 +1,26 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that switching to the inspector panel and not waiting for it to be fully
// loaded doesn't fail the test with unhandled rejected promises.
add_task(function* () {
// At least one assertion is needed to avoid failing the test, but really,
// what we're interested in is just having the test pass when switching to the
// inspector.
ok(true);
yield addTab("data:text/html;charset=utf-8,test inspector destroy");
info("Open the toolbox on the debugger panel");
let target = TargetFactory.forTab(gBrowser.selectedTab);
let toolbox = yield gDevTools.showToolbox(target, "jsdebugger");
info("Switch to the inspector panel and immediately end the test");
let onInspectorSelected = toolbox.once("inspector-selected");
toolbox.selectTool("inspector");
yield onInspectorSelected;
});

View file

@ -0,0 +1,64 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that context menu items exapnd all and collapse are shown properly.
const TEST_URL = "data:text/html;charset=utf-8," +
"<div id='parent-node'><div id='child-node'></div></div>";
add_task(function* () {
// Test is often exceeding time-out threshold, similar to Bug 1137765
requestLongerTimeout(2);
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Selecting the parent node");
let front = yield getNodeFrontForSelector("#parent-node", inspector);
yield selectNode(front, inspector);
info("Simulating context menu click on the selected node container.");
let allMenuItems = openContextMenuAndGetAllItems(inspector, {
target: getContainerForNodeFront(front, inspector).tagLine,
});
let nodeMenuCollapseElement =
allMenuItems.find(item => item.id === "node-menu-collapse");
let nodeMenuExpandElement =
allMenuItems.find(item => item.id === "node-menu-expand");
ok(nodeMenuCollapseElement.disabled, "Collapse option is disabled");
ok(!nodeMenuExpandElement.disabled, "ExpandAll option is enabled");
info("Testing whether expansion works properly");
nodeMenuExpandElement.click();
info("Waiting for expansion to occur");
yield waitForMultipleChildrenUpdates(inspector);
let markUpContainer = getContainerForNodeFront(front, inspector);
ok(markUpContainer.expanded, "node has been successfully expanded");
// reselecting node after expansion
yield selectNode(front, inspector);
info("Testing whether collapse works properly");
info("Simulating context menu click on the selected node container.");
allMenuItems = openContextMenuAndGetAllItems(inspector, {
target: getContainerForNodeFront(front, inspector).tagLine,
});
nodeMenuCollapseElement =
allMenuItems.find(item => item.id === "node-menu-collapse");
nodeMenuExpandElement =
allMenuItems.find(item => item.id === "node-menu-expand");
ok(!nodeMenuCollapseElement.disabled, "Collapse option is enabled");
ok(!nodeMenuExpandElement.disabled, "ExpandAll option is enabled");
nodeMenuCollapseElement.click();
info("Waiting for collapse to occur");
yield waitForMultipleChildrenUpdates(inspector);
ok(!markUpContainer.expanded, "node has been successfully collapsed");
});

View file

@ -0,0 +1,118 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint key-spacing: 0 */
"use strict";
// Testing that the gcli 'inspect' command works as it should.
const TEST_URI = URL_ROOT + "doc_inspector_gcli-inspect-command.html";
add_task(function* () {
return helpers.addTabWithToolbar(TEST_URI, Task.async(function* (options) {
let {inspector} = yield openInspector();
let checkSelection = Task.async(function* (selector) {
let node = yield getNodeFront(selector, inspector);
is(inspector.selection.nodeFront, node, "the current selection is correct");
});
yield helpers.audit(options, [
{
setup: "inspect",
check: {
input: "inspect",
hints: " <selector>",
markup: "VVVVVVV",
status: "ERROR",
args: {
selector: {
message: "Value required for \u2018selector\u2019."
},
}
},
},
{
setup: "inspect div",
check: {
input: "inspect div",
hints: "",
markup: "VVVVVVVVVVV",
status: "VALID",
args: {
selector: { message: "" },
}
},
exec: {},
post: () => checkSelection("div"),
},
{
setup: "inspect .someclass",
check: {
input: "inspect .someclass",
hints: "",
markup: "VVVVVVVVVVVVVVVVVV",
status: "VALID",
args: {
selector: { message: "" },
}
},
exec: {},
post: () => checkSelection(".someclass"),
},
{
setup: "inspect #someid",
check: {
input: "inspect #someid",
hints: "",
markup: "VVVVVVVVVVVVVVV",
status: "VALID",
args: {
selector: { message: "" },
}
},
exec: {},
post: () => checkSelection("#someid"),
},
{
setup: "inspect button[disabled]",
check: {
input: "inspect button[disabled]",
hints: "",
markup: "VVVVVVVVVVVVVVVVVVVVVVVV",
status: "VALID",
args: {
selector: { message: "" },
}
},
exec: {},
post: () => checkSelection("button[disabled]"),
},
{
setup: "inspect p>strong",
check: {
input: "inspect p>strong",
hints: "",
markup: "VVVVVVVVVVVVVVVV",
status: "VALID",
args: {
selector: { message: "" },
}
},
exec: {},
post: () => checkSelection("p>strong"),
},
{
setup: "inspect :root",
check: {
input: "inspect :root",
hints: "",
markup: "VVVVVVVVVVVVV",
status: "VALID"
},
exec: {},
post: () => checkSelection(":root"),
},
]);
}));
});

View file

@ -0,0 +1,31 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that hovering over nodes in the markup-view shows the highlighter over
// those nodes
add_task(function* () {
info("Loading the test document and opening the inspector");
let {toolbox, inspector, testActor} = yield openInspectorForURL(
"data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>");
let isVisible = yield testActor.isHighlighting(toolbox);
ok(!isVisible, "The highlighter is hidden by default");
info("Selecting the test node");
yield selectNode("span", inspector);
let container = yield getContainerForSelector("h1", inspector);
let onHighlighterReady = toolbox.once("highlighter-ready");
EventUtils.synthesizeMouseAtCenter(container.tagLine, {type: "mousemove"},
inspector.markup.doc.defaultView);
yield onHighlighterReady;
isVisible = yield testActor.isHighlighting();
ok(isVisible, "The highlighter is shown on a markup container hover");
ok((yield testActor.assertHighlightedNode("h1")),
"The highlighter highlights the right node");
});

View file

@ -0,0 +1,39 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the highlighter is correctly displayed over a variety of elements
const TEST_URI = URL_ROOT + "doc_inspector_highlighter.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URI);
info("Selecting the simple, non-transformed DIV");
yield selectAndHighlightNode("#simple-div", inspector);
let isVisible = yield testActor.isHighlighting();
ok(isVisible, "The highlighter is shown");
ok((yield testActor.assertHighlightedNode("#simple-div")),
"The highlighter's outline corresponds to the simple div");
yield testActor.isNodeCorrectlyHighlighted("#simple-div", is, "non-zoomed");
info("Selecting the rotated DIV");
yield selectAndHighlightNode("#rotated-div", inspector);
isVisible = yield testActor.isHighlighting();
ok(isVisible, "The highlighter is shown");
yield testActor.isNodeCorrectlyHighlighted("#rotated-div", is, "rotated");
info("Selecting the zero width height DIV");
yield selectAndHighlightNode("#widthHeightZero-div", inspector);
isVisible = yield testActor.isHighlighting();
ok(isVisible, "The highlighter is shown");
yield testActor.isNodeCorrectlyHighlighted("#widthHeightZero-div", is,
"zero width height");
});

View file

@ -0,0 +1,70 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that iframes are correctly highlighted.
const IFRAME_SRC = "<style>" +
"body {" +
"margin:0;" +
"height:100%;" +
"background-color:red" +
"}" +
"</style><body>hello from iframe</body>";
const DOCUMENT_SRC = "<style>" +
"iframe {" +
"height:200px;" +
"border: 11px solid black;" +
"padding: 13px;" +
"}" +
"body,iframe {" +
"margin:0" +
"}" +
"</style>" +
"<body>" +
"<iframe src='data:text/html;charset=utf-8," + IFRAME_SRC + "'></iframe>" +
"</body>";
const TEST_URI = "data:text/html;charset=utf-8," + DOCUMENT_SRC;
add_task(function* () {
let { inspector, toolbox, testActor } = yield openInspectorForURL(TEST_URI);
info("Waiting for box mode to show.");
let body = yield getNodeFront("body", inspector);
yield inspector.highlighter.showBoxModel(body);
info("Waiting for element picker to become active.");
yield startPicker(toolbox);
info("Moving mouse over iframe padding.");
yield moveMouseOver("iframe", 1, 1);
info("Performing checks");
yield testActor.isNodeCorrectlyHighlighted("iframe", is);
info("Scrolling the document");
yield testActor.setProperty("iframe", "style", "margin-bottom: 2000px");
yield testActor.eval("window.scrollBy(0, 40);");
// target the body within the iframe
let iframeBodySelector = ["iframe", "body"];
info("Moving mouse over iframe body");
yield moveMouseOver("iframe", 40, 40);
ok((yield testActor.assertHighlightedNode(iframeBodySelector)),
"highlighter shows the right node");
yield testActor.isNodeCorrectlyHighlighted(iframeBodySelector, is);
info("Waiting for the element picker to deactivate.");
yield inspector.toolbox.highlighterUtils.stopPicker();
function moveMouseOver(selector, x, y) {
info("Waiting for element " + selector + " to be highlighted");
testActor.synthesizeMouse({selector, x, y, options: {type: "mousemove"}});
return inspector.toolbox.once("picker-node-hovered");
}
});

View file

@ -0,0 +1,43 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Check that various highlighter elements exist.
const TEST_URL = "data:text/html;charset=utf-8,<div>test</div>";
// IDs of all highlighter elements that we expect to find in the canvasFrame.
const ELEMENTS = ["box-model-root",
"box-model-elements",
"box-model-margin",
"box-model-border",
"box-model-padding",
"box-model-content",
"box-model-guide-top",
"box-model-guide-right",
"box-model-guide-bottom",
"box-model-guide-left",
"box-model-infobar-container",
"box-model-infobar-tagname",
"box-model-infobar-id",
"box-model-infobar-classes",
"box-model-infobar-pseudo-classes",
"box-model-infobar-dimensions"];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("Show the box-model highlighter");
let divFront = yield getNodeFront("div", inspector);
yield inspector.highlighter.showBoxModel(divFront);
for (let id of ELEMENTS) {
let foundId = yield testActor.getHighlighterNodeAttribute(id, "id");
is(foundId, id, "Element " + id + " found");
}
info("Hide the box-model highlighter");
yield inspector.highlighter.hideBoxModel();
});

View file

@ -0,0 +1,66 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Check that custom highlighters can be retrieved by type and that they expose
// the expected API.
const TEST_URL = "data:text/html;charset=utf-8,custom highlighters";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
yield onlyOneInstanceOfMainHighlighter(inspector);
yield manyInstancesOfCustomHighlighters(inspector);
yield showHideMethodsAreAvailable(inspector);
yield unknownHighlighterTypeShouldntBeAccepted(inspector);
});
function* onlyOneInstanceOfMainHighlighter({inspector}) {
info("Check that the inspector always sends back the same main highlighter");
let h1 = yield inspector.getHighlighter(false);
let h2 = yield inspector.getHighlighter(false);
is(h1, h2, "The same highlighter front was returned");
is(h1.typeName, "highlighter", "The right front type was returned");
}
function* manyInstancesOfCustomHighlighters({inspector}) {
let h1 = yield inspector.getHighlighterByType("BoxModelHighlighter");
let h2 = yield inspector.getHighlighterByType("BoxModelHighlighter");
ok(h1 !== h2, "getHighlighterByType returns new instances every time (1)");
let h3 = yield inspector.getHighlighterByType("CssTransformHighlighter");
let h4 = yield inspector.getHighlighterByType("CssTransformHighlighter");
ok(h3 !== h4, "getHighlighterByType returns new instances every time (2)");
ok(h3 !== h1 && h3 !== h2,
"getHighlighterByType returns new instances every time (3)");
ok(h4 !== h1 && h4 !== h2,
"getHighlighterByType returns new instances every time (4)");
yield h1.finalize();
yield h2.finalize();
yield h3.finalize();
yield h4.finalize();
}
function* showHideMethodsAreAvailable({inspector}) {
let h1 = yield inspector.getHighlighterByType("BoxModelHighlighter");
let h2 = yield inspector.getHighlighterByType("CssTransformHighlighter");
ok("show" in h1, "Show method is present on the front API");
ok("show" in h2, "Show method is present on the front API");
ok("hide" in h1, "Hide method is present on the front API");
ok("hide" in h2, "Hide method is present on the front API");
yield h1.finalize();
yield h2.finalize();
}
function* unknownHighlighterTypeShouldntBeAccepted({inspector}) {
let h = yield inspector.getHighlighterByType("whatever");
ok(!h, "No highlighter was returned for the invalid type");
}

View file

@ -0,0 +1,52 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that canceling the element picker zooms back on the focused element. Bug 1224304.
const TEST_URL = URL_ROOT + "doc_inspector_long-divs.html";
add_task(function* () {
let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
yield selectAndHighlightNode("#focus-here", inspector);
ok((yield testActor.assertHighlightedNode("#focus-here")),
"The highlighter focuses on div#focus-here");
ok(isSelectedMarkupNodeInView(),
"The currently selected node is on the screen.");
// Start the picker but skip focusing manually focusing on the target, let the element
// picker do the focusing.
yield startPicker(toolbox, true);
yield moveMouseOver("#zoom-here");
ok(!isSelectedMarkupNodeInView(),
"The currently selected node is off the screen.");
yield cancelPickerByShortcut();
ok(isSelectedMarkupNodeInView(),
"The currently selected node is focused back on the screen.");
function cancelPickerByShortcut() {
info("Key pressed. Waiting for picker to be canceled.");
testActor.synthesizeKey({key: "VK_ESCAPE", options: {}});
return inspector.toolbox.once("picker-canceled");
}
function moveMouseOver(selector) {
info(`Waiting for element ${selector} to be hovered in the markup view`);
testActor.synthesizeMouse({
options: {type: "mousemove"},
center: true,
selector: selector
});
return inspector.markup.once("showcontainerhovered");
}
function isSelectedMarkupNodeInView() {
const selectedNodeContainer = inspector.markup._selectedContainer.elt;
const bounds = selectedNodeContainer.getBoundingClientRect();
return bounds.top > 0 && bounds.bottom > 0;
}
});

View file

@ -0,0 +1,105 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
//
// Whitelisting this test.
// As part of bug 1077403, the leaking uncaught rejection should be fixed.
//
thisTestLeaksUncaughtRejectionsAndShouldBeFixed("false");
// Test that hovering over the markup-view's containers doesn't always show the
// highlighter, depending on the type of node hovered over.
const TEST_PAGE = URL_ROOT +
"doc_inspector_highlighter-comments.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_PAGE);
let markupView = inspector.markup;
yield selectNode("p", inspector);
info("Hovering over #id1 and waiting for highlighter to appear.");
yield hoverElement("#id1");
yield assertHighlighterShownOn("#id1");
info("Hovering over comment node and ensuring highlighter doesn't appear.");
yield hoverComment();
yield assertHighlighterHidden();
info("Hovering over #id1 again and waiting for highlighter to appear.");
yield hoverElement("#id1");
yield assertHighlighterShownOn("#id1");
info("Hovering over #id2 and waiting for highlighter to appear.");
yield hoverElement("#id2");
yield assertHighlighterShownOn("#id2");
info("Hovering over <script> and ensuring highlighter doesn't appear.");
yield hoverElement("script");
yield assertHighlighterHidden();
info("Hovering over #id3 and waiting for highlighter to appear.");
yield hoverElement("#id3");
yield assertHighlighterShownOn("#id3");
info("Hovering over hidden #id4 and ensuring highlighter doesn't appear.");
yield hoverElement("#id4");
yield assertHighlighterHidden();
info("Hovering over a text node and waiting for highlighter to appear.");
yield hoverTextNode("Visible text node");
yield assertHighlighterShownOnTextNode("body", 14);
function hoverContainer(container) {
let promise = inspector.toolbox.once("node-highlight");
EventUtils.synthesizeMouse(container.tagLine, 2, 2, {type: "mousemove"},
markupView.doc.defaultView);
return promise;
}
function* hoverElement(selector) {
info(`Hovering node ${selector} in the markup view`);
let container = yield getContainerForSelector(selector, inspector);
return hoverContainer(container);
}
function hoverComment() {
info("Hovering the comment node in the markup view");
for (let [node, container] of markupView._containers) {
if (node.nodeType === Ci.nsIDOMNode.COMMENT_NODE) {
return hoverContainer(container);
}
}
return null;
}
function hoverTextNode(text) {
info(`Hovering the text node "${text}" in the markup view`);
let container = [...markupView._containers].filter(([nodeFront]) => {
return nodeFront.nodeType === Ci.nsIDOMNode.TEXT_NODE &&
nodeFront._form.nodeValue.trim() === text.trim();
})[0][1];
return hoverContainer(container);
}
function* assertHighlighterShownOn(selector) {
ok((yield testActor.assertHighlightedNode(selector)),
"Highlighter is shown on the right node: " + selector);
}
function* assertHighlighterShownOnTextNode(parentSelector, childNodeIndex) {
ok((yield testActor.assertHighlightedTextNode(parentSelector, childNodeIndex)),
"Highlighter is shown on the right text node");
}
function* assertHighlighterHidden() {
let isVisible = yield testActor.isHighlighting();
ok(!isVisible, "Highlighter is hidden");
}
});

View file

@ -0,0 +1,77 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test the creation of the canvas highlighter element of the css grid highlighter.
const TEST_URL = `
<style type='text/css'>
#grid {
display: grid;
}
#cell1 {
grid-column: 1;
grid-row: 1;
}
#cell2 {
grid-column: 2;
grid-row: 1;
}
#cell3 {
grid-column: 1;
grid-row: 2;
}
#cell4 {
grid-column: 2;
grid-row: 2;
}
</style>
<div id="grid">
<div id="cell1">cell1</div>
<div id="cell2">cell2</div>
<div id="cell3">cell3</div>
<div id="cell4">cell4</div>
</div>
`;
const HIGHLIGHTER_TYPE = "CssGridHighlighter";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(
"data:text/html;charset=utf-8," + encodeURIComponent(TEST_URL));
let front = inspector.inspector;
let highlighter = yield front.getHighlighterByType(HIGHLIGHTER_TYPE);
yield isHiddenByDefault(testActor, highlighter);
yield isVisibleWhenShown(testActor, inspector, highlighter);
yield highlighter.finalize();
});
function* isHiddenByDefault(testActor, highlighterFront) {
info("Checking that the highlighter is hidden by default");
let hidden = yield testActor.getHighlighterNodeAttribute(
"css-grid-canvas", "hidden", highlighterFront);
ok(hidden, "The highlighter is hidden by default");
}
function* isVisibleWhenShown(testActor, inspector, highlighterFront) {
info("Asking to show the highlighter on the test node");
let node = yield getNodeFront("#grid", inspector);
yield highlighterFront.show(node);
let hidden = yield testActor.getHighlighterNodeAttribute(
"css-grid-canvas", "hidden", highlighterFront);
ok(!hidden, "The highlighter is visible");
info("Hiding the highlighter");
yield highlighterFront.hide();
hidden = yield testActor.getHighlighterNodeAttribute(
"css-grid-canvas", "hidden", highlighterFront);
ok(hidden, "The highlighter is hidden");
}

View file

@ -0,0 +1,152 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test the creation of the SVG highlighter elements of the css transform
// highlighter.
const TEST_URL = `
<div id="transformed"
style="border:1px solid red;width:100px;height:100px;transform:skew(13deg);">
</div>
<div id="untransformed"
style="border:1px solid blue;width:100px;height:100px;">
</div>
<span id="inline"
style="transform:rotate(90deg);">this is an inline transformed element
</span>
`;
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(
"data:text/html;charset=utf-8," + encodeURI(TEST_URL));
let front = inspector.inspector;
let highlighter = yield front.getHighlighterByType("CssTransformHighlighter");
yield isHiddenByDefault(testActor, highlighter);
yield has2PolygonsAnd4Lines(testActor, highlighter);
yield isNotShownForUntransformed(testActor, inspector, highlighter);
yield isNotShownForInline(testActor, inspector, highlighter);
yield isVisibleWhenShown(testActor, inspector, highlighter);
yield linesLinkThePolygons(testActor, inspector, highlighter);
yield highlighter.finalize();
});
function* isHiddenByDefault(testActor, highlighterFront) {
info("Checking that the highlighter is hidden by default");
let hidden = yield testActor.getHighlighterNodeAttribute(
"css-transform-elements", "hidden", highlighterFront);
ok(hidden, "The highlighter is hidden by default");
}
function* has2PolygonsAnd4Lines(testActor, highlighterFront) {
info("Checking that the highlighter is made up of 4 lines and 2 polygons");
let value = yield testActor.getHighlighterNodeAttribute(
"css-transform-untransformed", "class", highlighterFront);
is(value, "css-transform-untransformed", "The untransformed polygon exists");
value = yield testActor.getHighlighterNodeAttribute(
"css-transform-transformed", "class", highlighterFront);
is(value, "css-transform-transformed", "The transformed polygon exists");
for (let nb of ["1", "2", "3", "4"]) {
value = yield testActor.getHighlighterNodeAttribute(
"css-transform-line" + nb, "class", highlighterFront);
is(value, "css-transform-line", "The line " + nb + " exists");
}
}
function* isNotShownForUntransformed(testActor, inspector, highlighterFront) {
info("Asking to show the highlighter on the untransformed test node");
let node = yield getNodeFront("#untransformed", inspector);
yield highlighterFront.show(node);
let hidden = yield testActor.getHighlighterNodeAttribute(
"css-transform-elements", "hidden", highlighterFront);
ok(hidden, "The highlighter is still hidden");
}
function* isNotShownForInline(testActor, inspector, highlighterFront) {
info("Asking to show the highlighter on the inline test node");
let node = yield getNodeFront("#inline", inspector);
yield highlighterFront.show(node);
let hidden = yield testActor.getHighlighterNodeAttribute(
"css-transform-elements", "hidden", highlighterFront);
ok(hidden, "The highlighter is still hidden");
}
function* isVisibleWhenShown(testActor, inspector, highlighterFront) {
info("Asking to show the highlighter on the test node");
let node = yield getNodeFront("#transformed", inspector);
yield highlighterFront.show(node);
let hidden = yield testActor.getHighlighterNodeAttribute(
"css-transform-elements", "hidden", highlighterFront);
ok(!hidden, "The highlighter is visible");
info("Hiding the highlighter");
yield highlighterFront.hide();
hidden = yield testActor.getHighlighterNodeAttribute(
"css-transform-elements", "hidden", highlighterFront);
ok(hidden, "The highlighter is hidden");
}
function* linesLinkThePolygons(testActor, inspector, highlighterFront) {
info("Showing the highlighter on the transformed node");
let node = yield getNodeFront("#transformed", inspector);
yield highlighterFront.show(node);
info("Checking that the 4 lines do link the 2 shape's corners");
let lines = [];
for (let nb of ["1", "2", "3", "4"]) {
let x1 = yield testActor.getHighlighterNodeAttribute(
"css-transform-line" + nb, "x1", highlighterFront);
let y1 = yield testActor.getHighlighterNodeAttribute(
"css-transform-line" + nb, "y1", highlighterFront);
let x2 = yield testActor.getHighlighterNodeAttribute(
"css-transform-line" + nb, "x2", highlighterFront);
let y2 = yield testActor.getHighlighterNodeAttribute(
"css-transform-line" + nb, "y2", highlighterFront);
lines.push({x1, y1, x2, y2});
}
let points1 = yield testActor.getHighlighterNodeAttribute(
"css-transform-untransformed", "points", highlighterFront);
points1 = points1.split(" ");
let points2 = yield testActor.getHighlighterNodeAttribute(
"css-transform-transformed", "points", highlighterFront);
points2 = points2.split(" ");
for (let i = 0; i < lines.length; i++) {
info("Checking line nb " + i);
let line = lines[i];
let p1 = points1[i].split(",");
is(p1[0], line.x1,
"line " + i + "'s first point matches the untransformed x coordinate");
is(p1[1], line.y1,
"line " + i + "'s first point matches the untransformed y coordinate");
let p2 = points2[i].split(",");
is(p2[0], line.x2,
"line " + i + "'s first point matches the transformed x coordinate");
is(p2[1], line.y2,
"line " + i + "'s first point matches the transformed y coordinate");
}
yield highlighterFront.hide();
}

View file

@ -0,0 +1,56 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/*
Bug 1014547 - CSS transforms highlighter
Test that the highlighter elements created have the right size and coordinates.
Note that instead of hard-coding values here, the assertions are made by
comparing with the result of getAdjustedQuads.
There's a separate test for checking that getAdjustedQuads actually returns
sensible values
(devtools/client/shared/test/browser_layoutHelpers-getBoxQuads.js),
so the present test doesn't care about that, it just verifies that the css
transform highlighter applies those values correctly to the SVG elements
*/
const TEST_URL = URL_ROOT + "doc_inspector_highlighter_csstransform.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
let front = inspector.inspector;
let highlighter = yield front.getHighlighterByType("CssTransformHighlighter");
let nodeFront = yield getNodeFront("#test-node", inspector);
info("Displaying the transform highlighter on test node");
yield highlighter.show(nodeFront);
let data = yield testActor.getAllAdjustedQuads("#test-node");
let [expected] = data.border;
let points = yield testActor.getHighlighterNodeAttribute(
"css-transform-transformed", "points", highlighter);
let polygonPoints = points.split(" ").map(p => {
return {
x: +p.substring(0, p.indexOf(",")),
y: +p.substring(p.indexOf(",") + 1)
};
});
for (let i = 1; i < 5; i++) {
is(polygonPoints[i - 1].x, expected["p" + i].x,
"p" + i + " x coordinate is correct");
is(polygonPoints[i - 1].y, expected["p" + i].y,
"p" + i + " y coordinate is correct");
}
info("Hiding the transform highlighter");
yield highlighter.hide();
yield highlighter.finalize();
});

View file

@ -0,0 +1,30 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the highlighter can go inside <embed> elements
const TEST_URL = URL_ROOT + "doc_inspector_embed.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Get a node inside the <embed> element and select/highlight it");
let body = yield getEmbeddedBody(inspector);
yield selectAndHighlightNode(body, inspector);
let selectedNode = inspector.selection.nodeFront;
is(selectedNode.tagName.toLowerCase(), "body", "The selected node is <body>");
ok(selectedNode.baseURI.endsWith("doc_inspector_menu.html"),
"The selected node is the <body> node inside the <embed> element");
});
function* getEmbeddedBody({walker}) {
let embed = yield walker.querySelector(walker.rootNode, "embed");
let {nodes} = yield walker.children(embed);
let contentDoc = nodes[0];
let body = yield walker.querySelector(contentDoc, "body");
return body;
}

View file

@ -0,0 +1,39 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the eyedropper can copy colors to the clipboard
const HIGHLIGHTER_TYPE = "EyeDropper";
const ID = "eye-dropper-";
const TEST_URI = "data:text/html;charset=utf-8,<style>html{background:red}</style>";
add_task(function* () {
let helper = yield openInspectorForURL(TEST_URI)
.then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
helper.prefix = ID;
let {show, finalize,
waitForElementAttributeSet, waitForElementAttributeRemoved} = helper;
info("Show the eyedropper with the copyOnSelect option");
yield show("html", {copyOnSelect: true});
info("Make sure to wait until the eyedropper is done taking a screenshot of the page");
yield waitForElementAttributeSet("root", "drawn", helper);
yield waitForClipboardPromise(() => {
info("Activate the eyedropper so the background color is copied");
EventUtils.synthesizeKey("VK_RETURN", {});
}, "#FF0000");
ok(true, "The clipboard contains the right value");
yield waitForElementAttributeRemoved("root", "drawn", helper);
yield waitForElementAttributeSet("root", "hidden", helper);
ok(true, "The eyedropper is now hidden");
finalize();
});

View file

@ -0,0 +1,30 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the eyedropper opens correctly even when the page defines CSP headers.
const HIGHLIGHTER_TYPE = "EyeDropper";
const ID = "eye-dropper-";
const TEST_URI = URL_ROOT + "doc_inspector_csp.html";
add_task(function* () {
let helper = yield openInspectorForURL(TEST_URI)
.then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
helper.prefix = ID;
let {show, hide, finalize, isElementHidden, waitForElementAttributeSet} = helper;
info("Try to display the eyedropper");
yield show("html");
let hidden = yield isElementHidden("root");
ok(!hidden, "The eyedropper is now shown");
info("Wait until the eyedropper is done taking a screenshot of the page");
yield waitForElementAttributeSet("root", "drawn", helper);
ok(true, "The image data was retrieved successfully from the window");
yield hide();
finalize();
});

View file

@ -0,0 +1,141 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test the eyedropper mouse and keyboard handling.
const HIGHLIGHTER_TYPE = "EyeDropper";
const ID = "eye-dropper-";
const TEST_URI = `
<style>
html{width:100%;height:100%;}
</style>
<body>eye-dropper test</body>`;
const MOVE_EVENTS_DATA = [
{type: "mouse", x: 200, y: 100, expected: {x: 200, y: 100}},
{type: "mouse", x: 100, y: 200, expected: {x: 100, y: 200}},
{type: "keyboard", key: "VK_LEFT", expected: {x: 99, y: 200}},
{type: "keyboard", key: "VK_LEFT", shift: true, expected: {x: 89, y: 200}},
{type: "keyboard", key: "VK_RIGHT", expected: {x: 90, y: 200}},
{type: "keyboard", key: "VK_RIGHT", shift: true, expected: {x: 100, y: 200}},
{type: "keyboard", key: "VK_DOWN", expected: {x: 100, y: 201}},
{type: "keyboard", key: "VK_DOWN", shift: true, expected: {x: 100, y: 211}},
{type: "keyboard", key: "VK_UP", expected: {x: 100, y: 210}},
{type: "keyboard", key: "VK_UP", shift: true, expected: {x: 100, y: 200}},
// Mouse initialization for left and top snapping
{type: "mouse", x: 7, y: 7, expected: {x: 7, y: 7}},
// Left Snapping
{type: "keyboard", key: "VK_LEFT", shift: true, expected: {x: 0, y: 7},
desc: "Left Snapping to x=0"},
// Top Snapping
{type: "keyboard", key: "VK_UP", shift: true, expected: {x: 0, y: 0},
desc: "Top Snapping to y=0"},
// Mouse initialization for right snapping
{
type: "mouse",
x: (width, height) => width - 5,
y: 0,
expected: {
x: (width, height) => width - 5,
y: 0
}
},
// Right snapping
{
type: "keyboard",
key: "VK_RIGHT",
shift: true,
expected: {
x: (width, height) => width,
y: 0
},
desc: "Right snapping to x=max window width available"
},
// Mouse initialization for bottom snapping
{
type: "mouse",
x: 0,
y: (width, height) => height - 5,
expected: {
x: 0,
y: (width, height) => height - 5
}
},
// Bottom snapping
{
type: "keyboard",
key: "VK_DOWN",
shift: true,
expected: {
x: 0,
y: (width, height) => height
},
desc: "Bottom snapping to y=max window height available"
},
];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(
"data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
let helper = yield getHighlighterHelperFor(HIGHLIGHTER_TYPE)({inspector, testActor});
helper.prefix = ID;
yield helper.show("html");
yield respondsToMoveEvents(helper, testActor);
yield respondsToReturnAndEscape(helper);
helper.finalize();
});
function* respondsToMoveEvents(helper, testActor) {
info("Checking that the eyedropper responds to events from the mouse and keyboard");
let {mouse} = helper;
let {width, height} = yield testActor.getBoundingClientRect("html");
for (let {type, x, y, key, shift, expected, desc} of MOVE_EVENTS_DATA) {
x = typeof x === "function" ? x(width, height) : x;
y = typeof y === "function" ? y(width, height) : y;
expected.x = typeof expected.x === "function" ?
expected.x(width, height) : expected.x;
expected.y = typeof expected.y === "function" ?
expected.y(width, height) : expected.y;
if (typeof desc === "undefined") {
info(`Simulating a ${type} event to move to ${expected.x} ${expected.y}`);
} else {
info(`Simulating ${type} event: ${desc}`);
}
if (type === "mouse") {
yield mouse.move(x, y);
} else if (type === "keyboard") {
let options = shift ? {shiftKey: true} : {};
yield EventUtils.synthesizeKey(key, options);
}
yield checkPosition(expected, helper);
}
}
function* checkPosition({x, y}, {getElementAttribute}) {
let style = yield getElementAttribute("root", "style");
is(style, `top:${y}px;left:${x}px;`,
`The eyedropper is at the expected ${x} ${y} position`);
}
function* respondsToReturnAndEscape({isElementHidden, show}) {
info("Simulating return to select the color and hide the eyedropper");
yield EventUtils.synthesizeKey("VK_RETURN", {});
let hidden = yield isElementHidden("root");
ok(hidden, "The eyedropper has been hidden");
info("Showing the eyedropper again and simulating escape to hide it");
yield show("html");
yield EventUtils.synthesizeKey("VK_ESCAPE", {});
hidden = yield isElementHidden("root");
ok(hidden, "The eyedropper has been hidden again");
}

View file

@ -0,0 +1,115 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test the position of the eyedropper label.
// It should move around when the eyedropper is close to the edges of the viewport so as
// to always stay visible.
const HIGHLIGHTER_TYPE = "EyeDropper";
const ID = "eye-dropper-";
const HTML = `
<style>
html, body {height: 100%; margin: 0;}
body {background: linear-gradient(red, gold); display: flex; justify-content: center;
align-items: center;}
</style>
Eyedropper label position test
`;
const TEST_PAGE = "data:text/html;charset=utf-8," + encodeURI(HTML);
const TEST_DATA = [{
desc: "Move the mouse to the center of the screen",
getCoordinates: (width, height) => {
return {x: width / 2, y: height / 2};
},
expectedPositions: {top: false, right: false, left: false}
}, {
desc: "Move the mouse to the center left",
getCoordinates: (width, height) => {
return {x: 0, y: height / 2};
},
expectedPositions: {top: false, right: true, left: false}
}, {
desc: "Move the mouse to the center right",
getCoordinates: (width, height) => {
return {x: width, y: height / 2};
},
expectedPositions: {top: false, right: false, left: true}
}, {
desc: "Move the mouse to the bottom center",
getCoordinates: (width, height) => {
return {x: width / 2, y: height};
},
expectedPositions: {top: true, right: false, left: false}
}, {
desc: "Move the mouse to the bottom left",
getCoordinates: (width, height) => {
return {x: 0, y: height};
},
expectedPositions: {top: true, right: true, left: false}
}, {
desc: "Move the mouse to the bottom right",
getCoordinates: (width, height) => {
return {x: width, y: height};
},
expectedPositions: {top: true, right: false, left: true}
}, {
desc: "Move the mouse to the top left",
getCoordinates: (width, height) => {
return {x: 0, y: 0};
},
expectedPositions: {top: false, right: true, left: false}
}, {
desc: "Move the mouse to the top right",
getCoordinates: (width, height) => {
return {x: width, y: 0};
},
expectedPositions: {top: false, right: false, left: true}
}];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_PAGE);
let helper = yield getHighlighterHelperFor(HIGHLIGHTER_TYPE)({inspector, testActor});
helper.prefix = ID;
let {mouse, show, hide, finalize} = helper;
let {width, height} = yield testActor.getBoundingClientRect("html");
// This test fails in non-e10s windows if we use width and height. For some reasons, the
// mouse events can't be dispatched/handled properly when we try to move the eyedropper
// to the far right and/or bottom of the screen. So just removing 10px from each side
// fixes it.
width -= 10;
height -= 10;
info("Show the eyedropper on the page");
yield show("html");
info("Move the eyedropper around and check that the label appears at the right place");
for (let {desc, getCoordinates, expectedPositions} of TEST_DATA) {
info(desc);
let {x, y} = getCoordinates(width, height);
info(`Moving the mouse to ${x} ${y}`);
yield mouse.move(x, y);
yield checkLabelPositionAttributes(helper, expectedPositions);
}
info("Hide the eyedropper");
yield hide();
finalize();
});
function* checkLabelPositionAttributes(helper, positions) {
for (let position in positions) {
is((yield hasAttribute(helper, position)), positions[position],
`The label was ${positions[position] ? "" : "not "}moved to the ${position}`);
}
}
function* hasAttribute({getElementAttribute}, name) {
let value = yield getElementAttribute("root", name);
return value !== null;
}

View file

@ -0,0 +1,42 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test the basic structure of the eye-dropper highlighter.
const HIGHLIGHTER_TYPE = "EyeDropper";
const ID = "eye-dropper-";
add_task(function* () {
let helper = yield openInspectorForURL("data:text/html;charset=utf-8,eye-dropper test")
.then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
helper.prefix = ID;
yield isInitiallyHidden(helper);
yield canBeShownAndHidden(helper);
helper.finalize();
});
function* isInitiallyHidden({isElementHidden}) {
info("Checking that the eyedropper is hidden by default");
let hidden = yield isElementHidden("root");
ok(hidden, "The eyedropper is hidden by default");
}
function* canBeShownAndHidden({show, hide, isElementHidden, getElementAttribute}) {
info("Asking to show and hide the highlighter actually works");
yield show("html");
let hidden = yield isElementHidden("root");
ok(!hidden, "The eyedropper is now shown");
let style = yield getElementAttribute("root", "style");
is(style, "top:100px;left:100px;", "The eyedropper is correctly positioned");
yield hide();
hidden = yield isElementHidden("root");
ok(hidden, "The eyedropper is now hidden again");
}

View file

@ -0,0 +1,64 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the eyedropper icons in the toolbar and in the color picker aren't displayed
// when the page isn't an HTML one.
const TEST_URL = URL_ROOT + "doc_inspector_highlighter_xbl.xul";
const TEST_URL_2 =
"data:text/html;charset=utf-8,<h1 style='color:red'>HTML test page</h1>";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Check the inspector toolbar");
let button = inspector.panelDoc.querySelector("#inspector-eyedropper-toggle");
ok(isDisabled(button), "The button is hidden in the toolbar");
info("Check the color picker");
yield selectNode("#scale", inspector);
// Find the color swatch in the rule-view.
let ruleView = inspector.ruleview.view;
let ruleViewDocument = ruleView.styleDocument;
let swatchEl = ruleViewDocument.querySelector(".ruleview-colorswatch");
info("Open the color picker");
let cPicker = ruleView.tooltips.colorPicker;
let onColorPickerReady = cPicker.once("ready");
swatchEl.click();
yield onColorPickerReady;
button = cPicker.tooltip.doc.querySelector("#eyedropper-button");
ok(isDisabled(button), "The button is disabled in the color picker");
info("Navigate to a HTML document");
yield navigateTo(inspector, TEST_URL_2);
info("Check the inspector toolbar in HTML document");
button = inspector.panelDoc.querySelector("#inspector-eyedropper-toggle");
ok(!isDisabled(button), "The button is enabled in the toolbar");
info("Check the color picker in HTML document");
// Find the color swatch in the rule-view.
yield selectNode("h1", inspector);
ruleView = inspector.ruleview.view;
ruleViewDocument = ruleView.styleDocument;
swatchEl = ruleViewDocument.querySelector(".ruleview-colorswatch");
info("Open the color picker in HTML document");
cPicker = ruleView.tooltips.colorPicker;
onColorPickerReady = cPicker.once("ready");
swatchEl.click();
yield onColorPickerReady;
button = cPicker.tooltip.doc.querySelector("#eyedropper-button");
ok(!isDisabled(button), "The button is enabled in the color picker");
});
function isDisabled(button) {
return button.disabled;
}

View file

@ -0,0 +1,89 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test the creation of the geometry highlighter elements.
const TEST_URL = `data:text/html;charset=utf-8,
<span id='inline'></span>
<div id='positioned' style='
background:yellow;
position:absolute;
left:5rem;
top:30px;
right:300px;
bottom:10em;'></div>
<div id='sized' style='
background:red;
width:5em;
height:50%;'></div>`;
const HIGHLIGHTER_TYPE = "GeometryEditorHighlighter";
const ID = "geometry-editor-";
const SIDES = ["left", "right", "top", "bottom"];
add_task(function* () {
let helper = yield openInspectorForURL(TEST_URL)
.then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
let { finalize } = helper;
helper.prefix = ID;
yield hasArrowsAndLabelsAndHandlers(helper);
yield isHiddenForNonPositionedNonSizedElement(helper);
yield sideArrowsAreDisplayedForPositionedNode(helper);
finalize();
});
function* hasArrowsAndLabelsAndHandlers({getElementAttribute}) {
info("Checking that the highlighter has the expected arrows and labels");
for (let name of [...SIDES]) {
let value = yield getElementAttribute("arrow-" + name, "class");
is(value, ID + "arrow " + name, "The " + name + " arrow exists");
value = yield getElementAttribute("label-text-" + name, "class");
is(value, ID + "label-text", "The " + name + " label exists");
value = yield getElementAttribute("handler-" + name, "class");
is(value, ID + "handler-" + name, "The " + name + " handler exists");
}
}
function* isHiddenForNonPositionedNonSizedElement(
{show, hide, isElementHidden}) {
info("Asking to show the highlighter on an inline, non p ositioned element");
yield show("#inline");
for (let name of [...SIDES]) {
let hidden = yield isElementHidden("arrow-" + name);
ok(hidden, "The " + name + " arrow is hidden");
hidden = yield isElementHidden("handler-" + name);
ok(hidden, "The " + name + " handler is hidden");
}
}
function* sideArrowsAreDisplayedForPositionedNode(
{show, hide, isElementHidden}) {
info("Asking to show the highlighter on the positioned node");
yield show("#positioned");
for (let name of SIDES) {
let hidden = yield isElementHidden("arrow-" + name);
ok(!hidden, "The " + name + " arrow is visible for the positioned node");
hidden = yield isElementHidden("handler-" + name);
ok(!hidden, "The " + name + " handler is visible for the positioned node");
}
info("Hiding the highlighter");
yield hide();
}

View file

@ -0,0 +1,116 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Globals defined in: devtools/client/inspector/test/head.js */
"use strict";
// Test that the geometry highlighter labels are correct.
const TEST_URL = `data:text/html;charset=utf-8,
<div id='positioned' style='
background:yellow;
position:absolute;
left:5rem;
top:30px;
right:300px;
bottom:10em;'></div>
<div id='positioned2' style='
background:blue;
position:absolute;
right:10%;
top:5vmin;'>test element</div>
<div id='relative' style='
background:green;
position:relative;
top:10px;
left:20px;
bottom:30px;
right:40px;
width:100px;
height:100px;'></div>
<div id='relative2' style='
background:grey;
position:relative;
top:0;bottom:-50px;
height:3em;'>relative</div>`;
const ID = "geometry-editor-";
const HIGHLIGHTER_TYPE = "GeometryEditorHighlighter";
const POSITIONED_ELEMENT_TESTS = [{
selector: "#positioned",
expectedLabels: [
{side: "left", visible: true, label: "5rem"},
{side: "top", visible: true, label: "30px"},
{side: "right", visible: true, label: "300px"},
{side: "bottom", visible: true, label: "10em"}
]
}, {
selector: "#positioned2",
expectedLabels: [
{side: "left", visible: false},
{side: "top", visible: true, label: "5vmin"},
{side: "right", visible: true, label: "10%"},
{side: "bottom", visible: false}
]
}, {
selector: "#relative",
expectedLabels: [
{side: "left", visible: true, label: "20px"},
{side: "top", visible: true, label: "10px"},
{side: "right", visible: false},
{side: "bottom", visible: false}
]
}, {
selector: "#relative2",
expectedLabels: [
{side: "left", visible: false},
{side: "top", visible: true, label: "0px"},
{side: "right", visible: false},
{side: "bottom", visible: false}
]
}];
add_task(function* () {
let helper = yield openInspectorForURL(TEST_URL)
.then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
helper.prefix = ID;
let { finalize } = helper;
yield positionLabelsAreCorrect(helper);
yield finalize();
});
function* positionLabelsAreCorrect(
{show, hide, isElementHidden, getElementTextContent}
) {
info("Highlight nodes and check position labels");
for (let {selector, expectedLabels} of POSITIONED_ELEMENT_TESTS) {
info("Testing node " + selector);
yield show(selector);
for (let {side, visible, label} of expectedLabels) {
let id = "label-" + side;
let hidden = yield isElementHidden(id);
if (visible) {
ok(!hidden, "The " + side + " label is visible");
let value = yield getElementTextContent(id);
is(value, label, "The " + side + " label textcontent is correct");
} else {
ok(hidden, "The " + side + " label is hidden");
}
}
info("Hiding the highlighter");
yield hide();
}
}

View file

@ -0,0 +1,61 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Globals defined in: devtools/client/inspector/test/head.js */
"use strict";
// Test that the right arrows/labels are shown even when the css properties are
// in several different css rules.
const TEST_URL = URL_ROOT + "doc_inspector_highlighter-geometry_01.html";
const ID = "geometry-editor-";
const HIGHLIGHTER_TYPE = "GeometryEditorHighlighter";
const PROPS = ["left", "right", "top", "bottom"];
add_task(function* () {
let helper = yield openInspectorForURL(TEST_URL)
.then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
helper.prefix = ID;
let { finalize } = helper;
yield checkArrowsLabelsAndHandlers(
"#node2", ["top", "left", "bottom", "right"],
helper);
yield checkArrowsLabelsAndHandlers("#node3", ["top", "left"], helper);
yield finalize();
});
function* checkArrowsLabelsAndHandlers(selector, expectedProperties,
{show, hide, isElementHidden}
) {
info("Getting node " + selector + " from the page");
yield show(selector);
for (let name of expectedProperties) {
let hidden = (yield isElementHidden("arrow-" + name)) &&
(yield isElementHidden("handler-" + name));
ok(!hidden,
"The " + name + " label/arrow & handler is visible for node " + selector);
}
// Testing that the other arrows are hidden
for (let name of PROPS) {
if (expectedProperties.indexOf(name) !== -1) {
continue;
}
let hidden = (yield isElementHidden("arrow-" + name)) &&
(yield isElementHidden("handler-" + name));
ok(hidden,
"The " + name + " arrow & handler is hidden for node " + selector);
}
info("Hiding the highlighter");
yield hide();
}

View file

@ -0,0 +1,85 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Globals defined in: devtools/client/inspector/test/head.js */
"use strict";
// Test that the arrows and handlers are positioned correctly and have the right
// size.
const TEST_URL = URL_ROOT + "doc_inspector_highlighter-geometry_01.html";
const ID = "geometry-editor-";
const HIGHLIGHTER_TYPE = "GeometryEditorHighlighter";
const handlerMap = {
"top": {"cx": "x2", "cy": "y2"},
"bottom": {"cx": "x2", "cy": "y2"},
"left": {"cx": "x2", "cy": "y2"},
"right": {"cx": "x2", "cy": "y2"}
};
add_task(function* () {
let helper = yield openInspectorForURL(TEST_URL)
.then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
helper.prefix = ID;
let { hide, finalize } = helper;
yield checkArrowsAndHandlers(helper, ".absolute-all-4", {
"top": {x1: 506, y1: 51, x2: 506, y2: 61},
"bottom": {x1: 506, y1: 451, x2: 506, y2: 251},
"left": {x1: 401, y1: 156, x2: 411, y2: 156},
"right": {x1: 901, y1: 156, x2: 601, y2: 156}
});
yield checkArrowsAndHandlers(helper, ".relative", {
"top": {x1: 901, y1: 51, x2: 901, y2: 91},
"left": {x1: 401, y1: 97, x2: 651, y2: 97}
});
yield checkArrowsAndHandlers(helper, ".fixed", {
"top": {x1: 25, y1: 0, x2: 25, y2: 400},
"left": {x1: 0, y1: 425, x2: 0, y2: 425}
});
info("Hiding the highlighter");
yield hide();
yield finalize();
});
function* checkArrowsAndHandlers(helper, selector, arrows) {
info("Highlighting the test node " + selector);
yield helper.show(selector);
for (let side in arrows) {
yield checkArrowAndHandler(helper, side, arrows[side]);
}
}
function* checkArrowAndHandler({getElementAttribute}, name, expectedCoords) {
info("Checking " + name + "arrow and handler coordinates are correct");
let handlerX = yield getElementAttribute("handler-" + name, "cx");
let handlerY = yield getElementAttribute("handler-" + name, "cy");
let expectedHandlerX = yield getElementAttribute("arrow-" + name,
handlerMap[name].cx);
let expectedHandlerY = yield getElementAttribute("arrow-" + name,
handlerMap[name].cy);
is(handlerX, expectedHandlerX,
"coordinate X for handler " + name + " is correct.");
is(handlerY, expectedHandlerY,
"coordinate Y for handler " + name + " is correct.");
for (let coordinate in expectedCoords) {
let value = yield getElementAttribute("arrow-" + name, coordinate);
is(Math.floor(value), expectedCoords[coordinate],
coordinate + " coordinate for arrow " + name + " is correct");
}
}

View file

@ -0,0 +1,119 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Globals defined in: devtools/client/inspector/test/head.js */
"use strict";
// Test that the arrows/handlers and offsetparent and currentnode elements of
// the geometry highlighter only appear when needed.
const TEST_URL = URL_ROOT + "doc_inspector_highlighter-geometry_02.html";
const ID = "geometry-editor-";
const HIGHLIGHTER_TYPE = "GeometryEditorHighlighter";
const TEST_DATA = [{
selector: "body",
isOffsetParentVisible: false,
isCurrentNodeVisible: false,
hasVisibleArrowsAndHandlers: false
}, {
selector: "h1",
isOffsetParentVisible: false,
isCurrentNodeVisible: false,
hasVisibleArrowsAndHandlers: false
}, {
selector: ".absolute",
isOffsetParentVisible: false,
isCurrentNodeVisible: true,
hasVisibleArrowsAndHandlers: true
}, {
selector: "#absolute-container",
isOffsetParentVisible: false,
isCurrentNodeVisible: true,
hasVisibleArrowsAndHandlers: false
}, {
selector: ".absolute-bottom-right",
isOffsetParentVisible: true,
isCurrentNodeVisible: true,
hasVisibleArrowsAndHandlers: true
}, {
selector: ".absolute-width-margin",
isOffsetParentVisible: true,
isCurrentNodeVisible: true,
hasVisibleArrowsAndHandlers: true
}, {
selector: ".absolute-all-4",
isOffsetParentVisible: true,
isCurrentNodeVisible: true,
hasVisibleArrowsAndHandlers: true
}, {
selector: ".relative",
isOffsetParentVisible: true,
isCurrentNodeVisible: true,
hasVisibleArrowsAndHandlers: true
}, {
selector: ".static",
isOffsetParentVisible: false,
isCurrentNodeVisible: false,
hasVisibleArrowsAndHandlers: false
}, {
selector: ".static-size",
isOffsetParentVisible: false,
isCurrentNodeVisible: true,
hasVisibleArrowsAndHandlers: false
}, {
selector: ".fixed",
isOffsetParentVisible: false,
isCurrentNodeVisible: true,
hasVisibleArrowsAndHandlers: true
}];
add_task(function* () {
let helper = yield openInspectorForURL(TEST_URL)
.then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
helper.prefix = ID;
let { hide, finalize } = helper;
for (let data of TEST_DATA) {
yield testNode(helper, data);
}
info("Hiding the highlighter");
yield hide();
yield finalize();
});
function* testNode(helper, data) {
let { selector } = data;
yield helper.show(data.selector);
is((yield isOffsetParentVisible(helper)), data.isOffsetParentVisible,
"The offset-parent highlighter visibility is correct for node " + selector);
is((yield isCurrentNodeVisible(helper)), data.isCurrentNodeVisible,
"The current-node highlighter visibility is correct for node " + selector);
is((yield hasVisibleArrowsAndHandlers(helper)),
data.hasVisibleArrowsAndHandlers,
"The arrows visibility is correct for node " + selector);
}
function* isOffsetParentVisible({isElementHidden}) {
return !(yield isElementHidden("offset-parent"));
}
function* isCurrentNodeVisible({isElementHidden}) {
return !(yield isElementHidden("current-node"));
}
function* hasVisibleArrowsAndHandlers({isElementHidden}) {
for (let side of ["top", "left", "bottom", "right"]) {
let hidden = yield isElementHidden("arrow-" + side);
if (!hidden) {
return !(yield isElementHidden("handler-" + side));
}
}
return false;
}

View file

@ -0,0 +1,166 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the geometry editor resizes properly an element on all sides,
// with different unit measures, and that arrow/handlers are updated correctly.
const TEST_URL = URL_ROOT + "doc_inspector_highlighter-geometry_01.html";
const ID = "geometry-editor-";
const HIGHLIGHTER_TYPE = "GeometryEditorHighlighter";
const SIDES = ["top", "right", "bottom", "left"];
// The object below contains all the tests for this unit test.
// The property's name is the test's description, that points to an
// object contains the steps (what side of the geometry editor to drag,
// the amount of pixels) and the expectation.
const TESTS = {
"Drag top's handler along x and y, south-east direction": {
"expects": "Only y axis is used to updated the top's element value",
"drag": "top",
"by": {x: 10, y: 10}
},
"Drag right's handler along x and y, south-east direction": {
"expects": "Only x axis is used to updated the right's element value",
"drag": "right",
"by": {x: 10, y: 10}
},
"Drag bottom's handler along x and y, south-east direction": {
"expects": "Only y axis is used to updated the bottom's element value",
"drag": "bottom",
"by": {x: 10, y: 10}
},
"Drag left's handler along x and y, south-east direction": {
"expects": "Only y axis is used to updated the left's element value",
"drag": "left",
"by": {x: 10, y: 10}
},
"Drag top's handler along x and y, north-west direction": {
"expects": "Only y axis is used to updated the top's element value",
"drag": "top",
"by": {x: -20, y: -20}
},
"Drag right's handler along x and y, north-west direction": {
"expects": "Only x axis is used to updated the right's element value",
"drag": "right",
"by": {x: -20, y: -20}
},
"Drag bottom's handler along x and y, north-west direction": {
"expects": "Only y axis is used to updated the bottom's element value",
"drag": "bottom",
"by": {x: -20, y: -20}
},
"Drag left's handler along x and y, north-west direction": {
"expects": "Only y axis is used to updated the left's element value",
"drag": "left",
"by": {x: -20, y: -20}
}
};
add_task(function* () {
let inspector = yield openInspectorForURL(TEST_URL);
let helper = yield getHighlighterHelperFor(HIGHLIGHTER_TYPE)(inspector);
helper.prefix = ID;
let { show, hide, finalize } = helper;
info("Showing the highlighter");
yield show("#node2");
for (let desc in TESTS) {
yield executeTest(helper, desc, TESTS[desc]);
}
info("Hiding the highlighter");
yield hide();
yield finalize();
});
function* executeTest(helper, desc, data) {
info(desc);
ok((yield areElementAndHighlighterMovedCorrectly(
helper, data.drag, data.by)), data.expects);
}
function* areElementAndHighlighterMovedCorrectly(helper, side, by) {
let { mouse, reflow, highlightedNode } = helper;
let {x, y} = yield getHandlerCoords(helper, side);
let dx = x + by.x;
let dy = y + by.y;
let beforeDragStyle = yield highlightedNode.getComputedStyle();
// simulate drag & drop
yield mouse.down(x, y);
yield mouse.move(dx, dy);
yield mouse.up();
yield reflow();
info(`Checking ${side} handler is moved correctly`);
yield isHandlerPositionUpdated(helper, side, x, y, by);
let delta = (side === "left" || side === "right") ? by.x : by.y;
delta = delta * ((side === "right" || side === "bottom") ? -1 : 1);
info("Checking element's sides are correct after drag & drop");
return yield areElementSideValuesCorrect(highlightedNode, beforeDragStyle,
side, delta);
}
function* isHandlerPositionUpdated(helper, name, x, y, by) {
let {x: afterDragX, y: afterDragY} = yield getHandlerCoords(helper, name);
if (name === "left" || name === "right") {
is(afterDragX, x + by.x,
`${name} handler's x axis updated.`);
is(afterDragY, y,
`${name} handler's y axis unchanged.`);
} else {
is(afterDragX, x,
`${name} handler's x axis unchanged.`);
is(afterDragY, y + by.y,
`${name} handler's y axis updated.`);
}
}
function* areElementSideValuesCorrect(node, beforeDragStyle, name, delta) {
let afterDragStyle = yield node.getComputedStyle();
let isSideCorrect = true;
for (let side of SIDES) {
let afterValue = Math.round(parseFloat(afterDragStyle[side].value));
let beforeValue = Math.round(parseFloat(beforeDragStyle[side].value));
if (side === name) {
// `isSideCorrect` is used only as test's return value, not to perform
// the actual test, because with `is` instead of `ok` we gather more
// information in case of failure
isSideCorrect = isSideCorrect && (afterValue === beforeValue + delta);
is(afterValue, beforeValue + delta,
`${side} is updated.`);
} else {
isSideCorrect = isSideCorrect && (afterValue === beforeValue);
is(afterValue, beforeValue,
`${side} is unchaged.`);
}
}
return isSideCorrect;
}
function* getHandlerCoords({getElementAttribute}, side) {
return {
x: Math.round(yield getElementAttribute("handler-" + side, "cx")),
y: Math.round(yield getElementAttribute("handler-" + side, "cy"))
};
}

View file

@ -0,0 +1,41 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that when first hovering over a node and immediately after selecting it
// by clicking on it leaves the highlighter visible for as long as the mouse is
// over the node
const TEST_URL = "data:text/html;charset=utf-8," +
"<p>It's going to be legen....</p>";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("hovering over the <p> line in the markup-view");
yield hoverContainer("p", inspector);
let isVisible = yield testActor.isHighlighting();
ok(isVisible, "the highlighter is still visible");
info("selecting the <p> line by clicking in the markup-view");
yield clickContainer("p", inspector);
yield testActor.setProperty("p", "textContent", "wait for it ....");
info("wait and see if the highlighter stays visible even after the node " +
"was selected");
yield waitForTheBrieflyShowBoxModelTimeout();
yield testActor.setProperty("p", "textContent", "dary!!!!");
isVisible = yield testActor.isHighlighting();
ok(isVisible, "the highlighter is still visible");
});
function waitForTheBrieflyShowBoxModelTimeout() {
let deferred = defer();
// Note that the current timeout is 1 sec and is neither configurable nor
// exported anywhere we can access, so hard-coding the timeout
setTimeout(deferred.resolve, 1500);
return deferred.promise;
}

View file

@ -0,0 +1,38 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that when after an element is selected and highlighted on hover, if the
// mouse leaves the markup-view and comes back again on the same element, that
// the highlighter is shown again on the node
const TEST_URL = "data:text/html;charset=utf-8,<p>Select me!</p>";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("hover over the <p> line in the markup-view so that it's the " +
"currently hovered node");
yield hoverContainer("p", inspector);
info("select the <p> markup-container line by clicking");
yield clickContainer("p", inspector);
let isVisible = yield testActor.isHighlighting();
ok(isVisible, "the highlighter is shown");
info("listen to the highlighter's hidden event");
let onHidden = testActor.waitForHighlighterEvent("hidden",
inspector.highlighter);
info("mouse-leave the markup-view");
yield mouseLeaveMarkupView(inspector);
yield onHidden;
isVisible = yield testActor.isHighlighting();
ok(!isVisible, "the highlighter is hidden after mouseleave");
info("hover over the <p> line again, which is still selected");
yield hoverContainer("p", inspector);
isVisible = yield testActor.isHighlighting();
ok(isVisible, "the highlighter is visible again");
});

View file

@ -0,0 +1,55 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that once a node has been hovered over and marked as such, if it is
// navigated away using the keyboard, the highlighter moves to the new node, and
// if it is then navigated back to, it is briefly highlighted again
const TEST_PAGE = "data:text/html;charset=utf-8," +
"<p id=\"one\">one</p><p id=\"two\">two</p>";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_PAGE);
info("Making sure the markup-view frame is focused");
inspector.markup._frame.focus();
// Mock the highlighter to easily track which node gets highlighted.
// We don't need to test here that the highlighter is actually visible, we
// just care about whether the markup-view asks it to be shown
let highlightedNode = null;
inspector.toolbox._highlighter.showBoxModel = function (nodeFront) {
highlightedNode = nodeFront;
return promise.resolve();
};
inspector.toolbox._highlighter.hideBoxModel = function () {
return promise.resolve();
};
function* isHighlighting(selector, desc) {
let nodeFront = yield getNodeFront(selector, inspector);
is(highlightedNode, nodeFront, desc);
}
info("Hover over <p#one> line in the markup-view");
yield hoverContainer("#one", inspector);
yield isHighlighting("#one", "<p#one> is highlighted");
info("Navigate to <p#two> with the keyboard");
let onUpdated = inspector.once("inspector-updated");
EventUtils.synthesizeKey("VK_DOWN", {}, inspector.panelWin);
yield onUpdated;
onUpdated = inspector.once("inspector-updated");
EventUtils.synthesizeKey("VK_DOWN", {}, inspector.panelWin);
yield onUpdated;
yield isHighlighting("#two", "<p#two> is highlighted");
info("Navigate back to <p#one> with the keyboard");
onUpdated = inspector.once("inspector-updated");
EventUtils.synthesizeKey("VK_UP", {}, inspector.panelWin);
yield onUpdated;
yield isHighlighting("#one", "<p#one> is highlighted again");
});

View file

@ -0,0 +1,64 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Testing that moving the mouse over the document with the element picker
// started highlights nodes
const NESTED_FRAME_SRC = "data:text/html;charset=utf-8," +
"nested iframe<div>nested div</div>";
const OUTER_FRAME_SRC = "data:text/html;charset=utf-8," +
"little frame<div>little div</div>" +
"<iframe src='" + NESTED_FRAME_SRC + "' />";
const TEST_URI = "data:text/html;charset=utf-8," +
"iframe tests for inspector" +
"<iframe src=\"" + OUTER_FRAME_SRC + "\" />";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URI);
let outerFrameDiv = ["iframe", "div"];
let innerFrameDiv = ["iframe", "iframe", "div"];
info("Waiting for element picker to activate.");
yield startPicker(inspector.toolbox);
info("Moving mouse over outerFrameDiv");
yield moveMouseOver(outerFrameDiv);
ok((yield testActor.assertHighlightedNode(outerFrameDiv)),
"outerFrameDiv is highlighted.");
info("Moving mouse over innerFrameDiv");
yield moveMouseOver(innerFrameDiv);
ok((yield testActor.assertHighlightedNode(innerFrameDiv)),
"innerFrameDiv is highlighted.");
info("Selecting root node");
yield selectNode(inspector.walker.rootNode, inspector);
info("Selecting an element from the nested iframe directly");
let innerFrameFront = yield getNodeFrontInFrame("iframe", "iframe",
inspector);
let innerFrameDivFront = yield getNodeFrontInFrame("div", innerFrameFront,
inspector);
yield selectNode(innerFrameDivFront, inspector);
is(inspector.breadcrumbs.nodeHierarchy.length, 9,
"Breadcrumbs have 9 items.");
info("Waiting for element picker to deactivate.");
yield inspector.toolbox.highlighterUtils.stopPicker();
function moveMouseOver(selector) {
info("Waiting for element " + selector + " to be highlighted");
testActor.synthesizeMouse({
selector: selector,
options: {type: "mousemove"},
center: true
}).then(() => inspector.toolbox.once("picker-node-hovered"));
}
});

View file

@ -0,0 +1,59 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the highlighter is correctly positioned when switching context
// to an iframe that has an offset from the parent viewport (eg. 100px margin)
const TEST_URI = "data:text/html;charset=utf-8," +
"<div id=\"outer\"></div>" +
"<iframe style='margin:100px' src='data:text/html," +
"<div id=\"inner\">Look I am here!</div>'>";
add_task(function* () {
info("Enable command-button-frames preference setting");
Services.prefs.setBoolPref("devtools.command-button-frames.enabled", true);
let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URI);
info("Switch to the iframe context.");
yield switchToFrameContext(1, toolbox, inspector);
info("Check navigation was successful.");
let hasOuterNode = yield testActor.hasNode("#outer");
ok(!hasOuterNode, "Check testActor has no access to outer element");
let hasTestNode = yield testActor.hasNode("#inner");
ok(hasTestNode, "Check testActor has access to inner element");
info("Check highlighting is correct after switching iframe context");
yield selectAndHighlightNode("#inner", inspector);
let isHighlightCorrect = yield testActor.assertHighlightedNode("#inner");
ok(isHighlightCorrect, "The selected node is properly highlighted.");
info("Cleanup command-button-frames preferences.");
Services.prefs.clearUserPref("devtools.command-button-frames.enabled");
});
/**
* Helper designed to switch context to another frame at the provided index.
* Returns a promise that will resolve when the navigation is complete.
* @return {Promise}
*/
function* switchToFrameContext(frameIndex, toolbox, inspector) {
// Open frame menu and wait till it's available on the screen.
let btn = toolbox.doc.getElementById("command-button-frames");
let menu = toolbox.showFramesMenu({target: btn});
yield once(menu, "open");
info("Select the iframe in the frame list.");
let newRoot = inspector.once("new-root");
menu.items[frameIndex].click();
yield newRoot;
yield inspector.once("inspector-updated");
info("Navigation to the iframe is done.");
}

View file

@ -0,0 +1,76 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
requestLongerTimeout(2);
// Test that highlighting various inline boxes displays the right number of
// polygons in the page.
const TEST_URL = URL_ROOT + "doc_inspector_highlighter_inline.html";
const TEST_DATA = [
"body",
"h1",
"h2",
"h2 em",
"p",
"p span",
// The following test case used to fail. See bug 1139925.
"[dir=rtl] > span"
];
add_task(function* () {
info("Loading the test document and opening the inspector");
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
for (let selector of TEST_DATA) {
info("Selecting and highlighting node " + selector);
yield selectAndHighlightNode(selector, inspector);
info("Get all quads for this node");
let data = yield testActor.getAllAdjustedQuads(selector);
info("Iterate over the box-model regions and verify that the highlighter " +
"is correct");
for (let region of ["margin", "border", "padding", "content"]) {
let {points} = yield testActor.getHighlighterRegionPath(region);
is(points.length, data[region].length, "The highlighter's " + region +
" path defines the correct number of boxes");
}
info("Verify that the guides define a rectangle that contains all " +
"content boxes");
let expectedContentRect = {
p1: {x: Infinity, y: Infinity},
p2: {x: -Infinity, y: Infinity},
p3: {x: -Infinity, y: -Infinity},
p4: {x: Infinity, y: -Infinity}
};
for (let {p1, p2, p3, p4} of data.content) {
expectedContentRect.p1.x = Math.min(expectedContentRect.p1.x, p1.x);
expectedContentRect.p1.y = Math.min(expectedContentRect.p1.y, p1.y);
expectedContentRect.p2.x = Math.max(expectedContentRect.p2.x, p2.x);
expectedContentRect.p2.y = Math.min(expectedContentRect.p2.y, p2.y);
expectedContentRect.p3.x = Math.max(expectedContentRect.p3.x, p3.x);
expectedContentRect.p3.y = Math.max(expectedContentRect.p3.y, p3.y);
expectedContentRect.p4.x = Math.min(expectedContentRect.p4.x, p4.x);
expectedContentRect.p4.y = Math.max(expectedContentRect.p4.y, p4.y);
}
let contentRect = yield testActor.getGuidesRectangle();
for (let point of ["p1", "p2", "p3", "p4"]) {
is((contentRect[point].x),
(expectedContentRect[point].x),
"x coordinate of point " + point +
" of the content rectangle defined by the outer guides is correct");
is((contentRect[point].y),
(expectedContentRect[point].y),
"y coordinate of point " + point +
" of the content rectangle defined by the outer guides is correct");
}
}
});

View file

@ -0,0 +1,64 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the keybindings for Picker work alright
const TEST_URL = URL_ROOT + "doc_inspector_highlighter_dom.html";
add_task(function* () {
let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
yield startPicker(toolbox);
info("Selecting the simple-div1 DIV");
yield moveMouseOver("#simple-div1");
ok((yield testActor.assertHighlightedNode("#simple-div1")),
"The highlighter shows #simple-div1. OK.");
// First Child selection
info("Testing first-child selection.");
yield doKeyHover({key: "VK_RIGHT", options: {}});
ok((yield testActor.assertHighlightedNode("#useless-para")),
"The highlighter shows #useless-para. OK.");
info("Selecting the useful-para paragraph DIV");
yield moveMouseOver("#useful-para");
ok((yield testActor.assertHighlightedNode("#useful-para")),
"The highlighter shows #useful-para. OK.");
yield doKeyHover({key: "VK_RIGHT", options: {}});
ok((yield testActor.assertHighlightedNode("#bold")),
"The highlighter shows #bold. OK.");
info("Going back up to the simple-div1 DIV");
yield doKeyHover({key: "VK_LEFT", options: {}});
yield doKeyHover({key: "VK_LEFT", options: {}});
ok((yield testActor.assertHighlightedNode("#simple-div1")),
"The highlighter shows #simple-div1. OK.");
info("First child selection test Passed.");
info("Stopping the picker");
yield toolbox.highlighterUtils.stopPicker();
function doKeyHover(args) {
info("Key pressed. Waiting for element to be highlighted/hovered");
testActor.synthesizeKey(args);
return inspector.toolbox.once("picker-node-hovered");
}
function moveMouseOver(selector) {
info("Waiting for element " + selector + " to be highlighted");
testActor.synthesizeMouse({
options: {type: "mousemove"},
center: true,
selector: selector
});
return inspector.toolbox.once("picker-node-hovered");
}
});

View file

@ -0,0 +1,64 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the keybindings for Picker work alright
const TEST_URL = URL_ROOT + "doc_inspector_highlighter_dom.html";
add_task(function* () {
let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
yield startPicker(toolbox);
// Previously chosen child memory
info("Testing whether previously chosen child is remembered");
info("Selecting the ahoy paragraph DIV");
yield moveMouseOver("#ahoy");
yield doKeyHover({key: "VK_LEFT", options: {}});
ok((yield testActor.assertHighlightedNode("#simple-div2")),
"The highlighter shows #simple-div2. OK.");
yield doKeyHover({key: "VK_RIGHT", options: {}});
ok((yield testActor.assertHighlightedNode("#ahoy")),
"The highlighter shows #ahoy. OK.");
info("Going back up to the complex-div DIV");
yield doKeyHover({key: "VK_LEFT", options: {}});
yield doKeyHover({key: "VK_LEFT", options: {}});
ok((yield testActor.assertHighlightedNode("#complex-div")),
"The highlighter shows #complex-div. OK.");
yield doKeyHover({key: "VK_RIGHT", options: {}});
ok((yield testActor.assertHighlightedNode("#simple-div2")),
"The highlighter shows #simple-div2. OK.");
info("Previously chosen child is remembered. Passed.");
info("Stopping the picker");
yield toolbox.highlighterUtils.stopPicker();
function doKeyHover(args) {
info("Key pressed. Waiting for element to be highlighted/hovered");
let onHighlighterReady = toolbox.once("highlighter-ready");
let onPickerNodeHovered = inspector.toolbox.once("picker-node-hovered");
testActor.synthesizeKey(args);
return promise.all([onHighlighterReady, onPickerNodeHovered]);
}
function moveMouseOver(selector) {
info("Waiting for element " + selector + " to be highlighted");
let onHighlighterReady = toolbox.once("highlighter-ready");
let onPickerNodeHovered = inspector.toolbox.once("picker-node-hovered");
testActor.synthesizeMouse({
options: {type: "mousemove"},
center: true,
selector: selector
});
return promise.all([onHighlighterReady, onPickerNodeHovered]);
}
});

View file

@ -0,0 +1,71 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the keybindings for Picker work alright
const IS_OSX = Services.appinfo.OS === "Darwin";
const TEST_URL = URL_ROOT + "doc_inspector_highlighter_dom.html";
add_task(function* () {
let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
yield startPicker(toolbox);
yield moveMouseOver("#another");
info("Testing enter/return key as pick-node command");
yield doKeyPick({key: "VK_RETURN", options: {}});
is(inspector.selection.nodeFront.id, "another",
"The #another node was selected. Passed.");
info("Testing escape key as cancel-picker command");
yield startPicker(toolbox);
yield moveMouseOver("#ahoy");
yield doKeyStop({key: "VK_ESCAPE", options: {}});
is(inspector.selection.nodeFront.id, "another",
"The #another DIV is still selected. Passed.");
info("Testing Ctrl+Shift+C shortcut as cancel-picker command");
yield startPicker(toolbox);
yield moveMouseOver("#ahoy");
let shortcutOpts = {key: "VK_C", options: {}};
if (IS_OSX) {
shortcutOpts.options.metaKey = true;
shortcutOpts.options.altKey = true;
} else {
shortcutOpts.options.ctrlKey = true;
shortcutOpts.options.shiftKey = true;
}
yield doKeyStop(shortcutOpts);
is(inspector.selection.nodeFront.id, "another",
"The #another DIV is still selected. Passed.");
function doKeyPick(args) {
info("Key pressed. Waiting for element to be picked");
testActor.synthesizeKey(args);
return promise.all([
inspector.selection.once("new-node-front"),
inspector.once("inspector-updated")
]);
}
function doKeyStop(args) {
info("Key pressed. Waiting for picker to be canceled");
testActor.synthesizeKey(args);
return inspector.toolbox.once("picker-stopped");
}
function moveMouseOver(selector) {
info("Waiting for element " + selector + " to be highlighted");
let onHighlighterReady = toolbox.once("highlighter-ready");
let onPickerNodeHovered = inspector.toolbox.once("picker-node-hovered");
testActor.synthesizeMouse({
options: {type: "mousemove"},
center: true,
selector: selector
});
return promise.all([onHighlighterReady, onPickerNodeHovered]);
}
});

View file

@ -0,0 +1,46 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that pressing ESC twice while in picker mode first stops the picker and
// then opens the split-console (see bug 988278).
const TEST_URL = "data:text/html;charset=utf8,<div></div>";
add_task(function* () {
let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
yield startPicker(toolbox);
info("Start using the picker by hovering over nodes");
let onHover = toolbox.once("picker-node-hovered");
testActor.synthesizeMouse({
options: {type: "mousemove"},
center: true,
selector: "div"
});
yield onHover;
info("Press escape and wait for the picker to stop");
let onPickerStopped = toolbox.once("picker-stopped");
testActor.synthesizeKey({
key: "VK_ESCAPE",
options: {}
});
yield onPickerStopped;
info("Press escape again and wait for the split console to open");
let onSplitConsole = toolbox.once("split-console");
let onConsoleReady = toolbox.once("webconsole-ready");
// The escape key is synthesized in the main process, which is where the focus
// should be after the picker was stopped.
EventUtils.synthesizeKey("VK_ESCAPE", {}, inspector.panelWin);
yield onSplitConsole;
yield onConsoleReady;
ok(toolbox.splitConsole, "The split console is shown.");
// Hide the split console.
yield toolbox.toggleSplitConsole();
});

View file

@ -0,0 +1,88 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const TEST_URL = `data:text/html;charset=utf-8,
<div style='
position:absolute;
left: 0;
top: 0;
width: 40000px;
height: 8000px'>
</div>`;
const PREFIX = "measuring-tool-highlighter-";
const HIGHLIGHTER_TYPE = "MeasuringToolHighlighter";
const X = 32;
const Y = 20;
add_task(function* () {
let helper = yield openInspectorForURL(TEST_URL)
.then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
let { finalize } = helper;
helper.prefix = PREFIX;
yield isHiddenByDefault(helper);
yield areLabelsHiddenByDefaultWhenShows(helper);
yield areLabelsProperlyDisplayedWhenMouseMoved(helper);
yield finalize();
});
function* isHiddenByDefault({isElementHidden}) {
info("Checking the highlighter is hidden by default");
let hidden = yield isElementHidden("elements");
ok(hidden, "highlighter's root is hidden by default");
hidden = yield isElementHidden("label-size");
ok(hidden, "highlighter's label size is hidden by default");
hidden = yield isElementHidden("label-position");
ok(hidden, "highlighter's label position is hidden by default");
}
function* areLabelsHiddenByDefaultWhenShows({isElementHidden, show}) {
info("Checking the highlighter is displayed when asked");
yield show();
let hidden = yield isElementHidden("elements");
is(hidden, false, "highlighter is visible after show");
hidden = yield isElementHidden("label-size");
ok(hidden, "label's size still hidden");
hidden = yield isElementHidden("label-position");
ok(hidden, "label's position still hidden");
}
function* areLabelsProperlyDisplayedWhenMouseMoved({isElementHidden,
synthesizeMouse, getElementTextContent}) {
info("Checking labels are properly displayed when mouse moved");
yield synthesizeMouse({
selector: ":root",
options: {type: "mousemove"},
x: X,
y: Y
});
let hidden = yield isElementHidden("label-position");
is(hidden, false, "label's position is displayed after the mouse is moved");
hidden = yield isElementHidden("label-size");
ok(hidden, "label's size still hidden");
let text = yield getElementTextContent("label-position");
let [x, y] = text.replace(/ /g, "").split(/\n/);
is(+x, X, "label's position shows the proper X coord");
is(+y, Y, "label's position shows the proper Y coord");
}

View file

@ -0,0 +1,130 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const TEST_URL = `data:text/html;charset=utf-8,
<div style='
position:absolute;
left: 0;
top: 0;
width: 40000px;
height: 8000px'>
</div>`;
const PREFIX = "measuring-tool-highlighter-";
const HIGHLIGHTER_TYPE = "MeasuringToolHighlighter";
const SIDES = ["top", "right", "bottom", "left"];
const X = 32;
const Y = 20;
const WIDTH = 160;
const HEIGHT = 100;
const HYPOTENUSE = Math.hypot(WIDTH, HEIGHT).toFixed(2);
add_task(function* () {
let helper = yield openInspectorForURL(TEST_URL)
.then(getHighlighterHelperFor(HIGHLIGHTER_TYPE));
let { show, finalize } = helper;
helper.prefix = PREFIX;
yield show();
yield hasNoLabelsWhenStarts(helper);
yield hasSizeLabelWhenMoved(helper);
yield hasCorrectSizeLabelValue(helper);
yield hasSizeLabelAndGuidesWhenStops(helper);
yield hasCorrectSizeLabelValue(helper);
yield finalize();
});
function* hasNoLabelsWhenStarts({isElementHidden, synthesizeMouse}) {
info("Checking highlighter has no labels when we start to select");
yield synthesizeMouse({
selector: ":root",
options: {type: "mousedown"},
x: X,
y: Y
});
let hidden = yield isElementHidden("label-size");
ok(hidden, "label's size still hidden");
hidden = yield isElementHidden("label-position");
ok(hidden, "label's position still hidden");
info("Checking highlighter has no guides when we start to select");
let guidesHidden = true;
for (let side of SIDES) {
guidesHidden = guidesHidden && (yield isElementHidden("guide-" + side));
}
ok(guidesHidden, "guides are hidden during dragging");
}
function* hasSizeLabelWhenMoved({isElementHidden, synthesizeMouse}) {
info("Checking highlighter has size label when we select the area");
yield synthesizeMouse({
selector: ":root",
options: {type: "mousemove"},
x: X + WIDTH,
y: Y + HEIGHT
});
let hidden = yield isElementHidden("label-size");
is(hidden, false, "label's size is visible during selection");
hidden = yield isElementHidden("label-position");
ok(hidden, "label's position still hidden");
info("Checking highlighter has no guides when we select the area");
let guidesHidden = true;
for (let side of SIDES) {
guidesHidden = guidesHidden && (yield isElementHidden("guide-" + side));
}
ok(guidesHidden, "guides are hidden during selection");
}
function* hasSizeLabelAndGuidesWhenStops({isElementHidden, synthesizeMouse}) {
info("Checking highlighter has size label and guides when we stop");
yield synthesizeMouse({
selector: ":root",
options: {type: "mouseup"},
x: X + WIDTH,
y: Y + HEIGHT
});
let hidden = yield isElementHidden("label-size");
is(hidden, false, "label's size is visible when the selection is done");
hidden = yield isElementHidden("label-position");
ok(hidden, "label's position still hidden");
let guidesVisible = true;
for (let side of SIDES) {
guidesVisible = guidesVisible && !(yield isElementHidden("guide-" + side));
}
ok(guidesVisible, "guides are visible when the selection is done");
}
function* hasCorrectSizeLabelValue({getElementTextContent}) {
let text = yield getElementTextContent("label-size");
let [width, height, hypot] = text.match(/\d.*px/g);
is(parseFloat(width), WIDTH, "width on label's size is correct");
is(parseFloat(height), HEIGHT, "height on label's size is correct");
is(parseFloat(hypot), HYPOTENUSE, "hypotenuse on label's size is correct");
}

View file

@ -0,0 +1,204 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Check that the box-model highlighter supports configuration options
const TEST_URL = `
<body style="padding:2em;">
<div style="width:100px;height:100px;padding:2em;
border:.5em solid black;margin:1em;">test</div>
</body>
`;
// Test data format:
// - desc: a string that will be output to the console.
// - options: json object to be passed as options to the highlighter.
// - checkHighlighter: a generator (async) function that should check the
// highlighter is correct.
const TEST_DATA = [
{
desc: "Guides and infobar should be shown by default",
options: {},
checkHighlighter: function* (testActor) {
let hidden = yield testActor.getHighlighterNodeAttribute(
"box-model-infobar-container", "hidden");
ok(!hidden, "Node infobar is visible");
hidden = yield testActor.getHighlighterNodeAttribute(
"box-model-elements", "hidden");
ok(!hidden, "SVG container is visible");
for (let side of ["top", "right", "bottom", "left"]) {
hidden = yield testActor.getHighlighterNodeAttribute(
"box-model-guide-" + side, "hidden");
ok(!hidden, side + " guide is visible");
}
}
},
{
desc: "All regions should be shown by default",
options: {},
checkHighlighter: function* (testActor) {
for (let region of ["margin", "border", "padding", "content"]) {
let {d} = yield testActor.getHighlighterRegionPath(region);
ok(d, "Region " + region + " has set coordinates");
}
}
},
{
desc: "Guides can be hidden",
options: {hideGuides: true},
checkHighlighter: function* (testActor) {
for (let side of ["top", "right", "bottom", "left"]) {
let hidden = yield testActor.getHighlighterNodeAttribute(
"box-model-guide-" + side, "hidden");
is(hidden, "true", side + " guide has been hidden");
}
}
},
{
desc: "Infobar can be hidden",
options: {hideInfoBar: true},
checkHighlighter: function* (testActor) {
let hidden = yield testActor.getHighlighterNodeAttribute(
"box-model-infobar-container", "hidden");
is(hidden, "true", "infobar has been hidden");
}
},
{
desc: "One region only can be shown (1)",
options: {showOnly: "content"},
checkHighlighter: function* (testActor) {
let {d} = yield testActor.getHighlighterRegionPath("margin");
ok(!d, "margin region is hidden");
({d} = yield testActor.getHighlighterRegionPath("border"));
ok(!d, "border region is hidden");
({d} = yield testActor.getHighlighterRegionPath("padding"));
ok(!d, "padding region is hidden");
({d} = yield testActor.getHighlighterRegionPath("content"));
ok(d, "content region is shown");
}
},
{
desc: "One region only can be shown (2)",
options: {showOnly: "margin"},
checkHighlighter: function* (testActor) {
let {d} = yield testActor.getHighlighterRegionPath("margin");
ok(d, "margin region is shown");
({d} = yield testActor.getHighlighterRegionPath("border"));
ok(!d, "border region is hidden");
({d} = yield testActor.getHighlighterRegionPath("padding"));
ok(!d, "padding region is hidden");
({d} = yield testActor.getHighlighterRegionPath("content"));
ok(!d, "content region is hidden");
}
},
{
desc: "Guides can be drawn around a given region (1)",
options: {region: "padding"},
checkHighlighter: function* (testActor) {
let topY1 = yield testActor.getHighlighterNodeAttribute(
"box-model-guide-top", "y1");
let rightX1 = yield testActor.getHighlighterNodeAttribute(
"box-model-guide-right", "x1");
let bottomY1 = yield testActor.getHighlighterNodeAttribute(
"box-model-guide-bottom", "y1");
let leftX1 = yield testActor.getHighlighterNodeAttribute(
"box-model-guide-left", "x1");
let {points} = yield testActor.getHighlighterRegionPath("padding");
points = points[0];
is(Math.ceil(topY1), points[0][1], "Top guide's y1 is correct");
is(Math.floor(rightX1), points[1][0], "Right guide's x1 is correct");
is(Math.floor(bottomY1), points[2][1], "Bottom guide's y1 is correct");
is(Math.ceil(leftX1), points[3][0], "Left guide's x1 is correct");
}
},
{
desc: "Guides can be drawn around a given region (2)",
options: {region: "margin"},
checkHighlighter: function* (testActor) {
let topY1 = yield testActor.getHighlighterNodeAttribute(
"box-model-guide-top", "y1");
let rightX1 = yield testActor.getHighlighterNodeAttribute(
"box-model-guide-right", "x1");
let bottomY1 = yield testActor.getHighlighterNodeAttribute(
"box-model-guide-bottom", "y1");
let leftX1 = yield testActor.getHighlighterNodeAttribute(
"box-model-guide-left", "x1");
let {points} = yield testActor.getHighlighterRegionPath("margin");
points = points[0];
is(Math.ceil(topY1), points[0][1], "Top guide's y1 is correct");
is(Math.floor(rightX1), points[1][0], "Right guide's x1 is correct");
is(Math.floor(bottomY1), points[2][1], "Bottom guide's y1 is correct");
is(Math.ceil(leftX1), points[3][0], "Left guide's x1 is correct");
}
},
{
desc: "When showOnly is used, other regions can be faded",
options: {showOnly: "margin", onlyRegionArea: true},
checkHighlighter: function* (testActor) {
for (let region of ["margin", "border", "padding", "content"]) {
let {d} = yield testActor.getHighlighterRegionPath(region);
ok(d, "Region " + region + " is shown (it has a d attribute)");
let faded = yield testActor.getHighlighterNodeAttribute(
"box-model-" + region, "faded");
if (region === "margin") {
ok(!faded, "The margin region is not faded");
} else {
is(faded, "true", "Region " + region + " is faded");
}
}
}
},
{
desc: "When showOnly is used, other regions can be faded (2)",
options: {showOnly: "padding", onlyRegionArea: true},
checkHighlighter: function* (testActor) {
for (let region of ["margin", "border", "padding", "content"]) {
let {d} = yield testActor.getHighlighterRegionPath(region);
ok(d, "Region " + region + " is shown (it has a d attribute)");
let faded = yield testActor.getHighlighterNodeAttribute(
"box-model-" + region, "faded");
if (region === "padding") {
ok(!faded, "The padding region is not faded");
} else {
is(faded, "true", "Region " + region + " is faded");
}
}
}
}
];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(
"data:text/html;charset=utf-8," + encodeURI(TEST_URL));
let divFront = yield getNodeFront("div", inspector);
for (let {desc, options, checkHighlighter} of TEST_DATA) {
info("Running test: " + desc);
info("Show the box-model highlighter with options " + options);
yield inspector.highlighter.showBoxModel(divFront, options);
yield checkHighlighter(testActor);
info("Hide the box-model highlighter");
yield inspector.highlighter.hideBoxModel();
}
});

View file

@ -0,0 +1,56 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the highlighter is correctly displayed and picker mode is not stopped after
// a shift-click (preview)
const TEST_URI = `data:text/html;charset=utf-8,
<p id="one">one</p><p id="two">two</p><p id="three">three</p>`;
add_task(function* () {
let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URI);
let body = yield getNodeFront("body", inspector);
is(inspector.selection.nodeFront, body, "By default the body node is selected");
info("Start the element picker");
yield startPicker(toolbox);
info("Shift-clicking element #one should select it but keep the picker ON");
yield clickElement("#one", testActor, inspector, true);
yield checkElementSelected("#one", inspector);
checkPickerMode(toolbox, true);
info("Shift-clicking element #two should select it but keep the picker ON");
yield clickElement("#two", testActor, inspector, true);
yield checkElementSelected("#two", inspector);
checkPickerMode(toolbox, true);
info("Clicking element #three should select it and turn the picker OFF");
yield clickElement("#three", testActor, inspector, false);
yield checkElementSelected("#three", inspector);
checkPickerMode(toolbox, false);
});
function* clickElement(selector, testActor, inspector, isShift) {
let onSelectionChanged = inspector.once("inspector-updated");
yield testActor.synthesizeMouse({
selector: selector,
center: true,
options: { shiftKey: isShift }
});
yield onSelectionChanged;
}
function* checkElementSelected(selector, inspector) {
let el = yield getNodeFront(selector, inspector);
is(inspector.selection.nodeFront, el, `The element ${selector} is now selected`);
}
function checkPickerMode(toolbox, isOn) {
let pickerButton = toolbox.doc.querySelector("#command-button-pick");
is(pickerButton.hasAttribute("checked"), isOn, "The picker mode is correct");
}

View file

@ -0,0 +1,121 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the custom rect highlighter provides the right API, ensures that
// the input is valid and that it does create a box with the right dimensions,
// at the right position.
const TEST_URL = "data:text/html;charset=utf-8,Rect Highlighter Test";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
let front = inspector.inspector;
let highlighter = yield front.getHighlighterByType("RectHighlighter");
let body = yield getNodeFront("body", inspector);
info("Make sure the highlighter returned is correct");
ok(highlighter, "The RectHighlighter custom type was created");
is(highlighter.typeName, "customhighlighter",
"The RectHighlighter has the right type");
ok(highlighter.show && highlighter.hide,
"The RectHighlighter has the expected show/hide methods");
info("Check that the highlighter is hidden by default");
let hidden = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "hidden", highlighter);
is(hidden, "true", "The highlighter is hidden by default");
info("Check that nothing is shown if no rect is passed");
yield highlighter.show(body);
hidden = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "hidden", highlighter);
is(hidden, "true", "The highlighter is hidden when no rect is passed");
info("Check that nothing is shown if rect is incomplete or invalid");
yield highlighter.show(body, {
rect: {x: 0, y: 0}
});
hidden = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "hidden", highlighter);
is(hidden, "true", "The highlighter is hidden when the rect is incomplete");
yield highlighter.show(body, {
rect: {x: 0, y: 0, width: -Infinity, height: 0}
});
hidden = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "hidden", highlighter);
is(hidden, "true", "The highlighter is hidden when the rect is invalid (1)");
yield highlighter.show(body, {
rect: {x: 0, y: 0, width: 5, height: -45}
});
hidden = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "hidden", highlighter);
is(hidden, "true", "The highlighter is hidden when the rect is invalid (2)");
yield highlighter.show(body, {
rect: {x: "test", y: 0, width: 5, height: 5}
});
hidden = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "hidden", highlighter);
is(hidden, "true", "The highlighter is hidden when the rect is invalid (3)");
info("Check that the highlighter is displayed when valid options are passed");
yield highlighter.show(body, {
rect: {x: 5, y: 5, width: 50, height: 50}
});
hidden = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "hidden", highlighter);
ok(!hidden, "The highlighter is displayed");
let style = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "style", highlighter);
is(style, "left:5px;top:5px;width:50px;height:50px;",
"The highlighter is positioned correctly");
info("Check that the highlighter can be displayed at x=0 y=0");
yield highlighter.show(body, {
rect: {x: 0, y: 0, width: 50, height: 50}
});
hidden = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "hidden", highlighter);
ok(!hidden, "The highlighter is displayed when x=0 and y=0");
style = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "style", highlighter);
is(style, "left:0px;top:0px;width:50px;height:50px;",
"The highlighter is positioned correctly");
info("Check that the highlighter is hidden when dimensions are 0");
yield highlighter.show(body, {
rect: {x: 0, y: 0, width: 0, height: 0}
});
hidden = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "hidden", highlighter);
is(hidden, "true", "The highlighter is hidden width and height are 0");
info("Check that a fill color can be passed");
yield highlighter.show(body, {
rect: {x: 100, y: 200, width: 500, height: 200},
fill: "red"
});
hidden = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "hidden", highlighter);
ok(!hidden, "The highlighter is displayed");
style = yield testActor.getHighlighterNodeAttribute(
"highlighted-rect", "style", highlighter);
is(style, "left:100px;top:200px;width:500px;height:200px;background:red;",
"The highlighter has the right background color");
yield highlighter.hide();
yield highlighter.finalize();
});

View file

@ -0,0 +1,37 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the custom rect highlighter positions the rectangle relative to the
// viewport of the context node we pass to it.
const TEST_URL = URL_ROOT + "doc_inspector_highlighter_rect.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
let front = inspector.inspector;
let highlighter = yield front.getHighlighterByType("RectHighlighter");
info("Showing the rect highlighter in the context of the iframe");
// Get the reference to a context node inside the iframe
let childBody = yield getNodeFrontInFrame("body", "iframe", inspector);
yield highlighter.show(childBody, {
rect: {x: 50, y: 50, width: 100, height: 100}
});
let style = yield testActor.getHighlighterNodeAttribute("highlighted-rect",
"style", highlighter);
// The parent body has margin=50px and border=10px
// The parent iframe also has margin=50px and border=10px
// = 50 + 10 + 50 + 10 = 120px
// The rect is aat x=50 and y=50, so left and top should be 170px
is(style, "left:170px;top:170px;width:100px;height:100px;",
"The highlighter is correctly positioned");
yield highlighter.hide();
yield highlighter.finalize();
});

View file

@ -0,0 +1,76 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test the creation of the geometry highlighter elements.
const TEST_URL = "data:text/html;charset=utf-8," +
"<div style='position:absolute;left: 0; top: 0; " +
"width: 40000px; height: 8000px'></div>";
const ID = "rulers-highlighter-";
// Maximum size, in pixel, for the horizontal ruler and vertical ruler
// used by RulersHighlighter
const RULERS_MAX_X_AXIS = 10000;
const RULERS_MAX_Y_AXIS = 15000;
// Number of steps after we add a text in RulersHighliter;
// currently the unit is in pixel.
const RULERS_TEXT_STEP = 100;
add_task(function* () {
let { inspector, testActor } = yield openInspectorForURL(TEST_URL);
let front = inspector.inspector;
let highlighter = yield front.getHighlighterByType("RulersHighlighter");
yield isHiddenByDefault(highlighter, inspector, testActor);
yield hasRightLabelsContent(highlighter, inspector, testActor);
yield highlighter.finalize();
});
function* isHiddenByDefault(highlighterFront, inspector, testActor) {
info("Checking the highlighter is hidden by default");
let hidden = yield testActor.getHighlighterNodeAttribute(
ID + "elements", "hidden", highlighterFront);
is(hidden, "true", "highlighter is hidden by default");
info("Checking the highlighter is displayed when asked");
// the rulers doesn't need any node, but as highligher it seems mandatory
// ones, so the body is given
let body = yield getNodeFront("body", inspector);
yield highlighterFront.show(body);
hidden = yield testActor.getHighlighterNodeAttribute(
ID + "elements", "hidden", highlighterFront);
isnot(hidden, "true", "highlighter is visible after show");
}
function* hasRightLabelsContent(highlighterFront, inspector, testActor) {
info("Checking the rulers have the proper text, based on rulers' size");
let contentX = yield testActor.getHighlighterNodeTextContent(
`${ID}x-axis-text`, highlighterFront);
let contentY = yield testActor.getHighlighterNodeTextContent(
`${ID}y-axis-text`, highlighterFront);
let expectedX = "";
for (let i = RULERS_TEXT_STEP; i < RULERS_MAX_X_AXIS; i += RULERS_TEXT_STEP) {
expectedX += i;
}
is(contentX, expectedX, "x axis text content is correct");
let expectedY = "";
for (let i = RULERS_TEXT_STEP; i < RULERS_MAX_Y_AXIS; i += RULERS_TEXT_STEP) {
expectedY += i;
}
is(contentY, expectedY, "y axis text content is correct");
}

View file

@ -0,0 +1,103 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test the creation of the geometry highlighter elements.
const TEST_URL = "data:text/html;charset=utf-8," +
"<div style='position:absolute;left: 0; top: 0; " +
"width: 40000px; height: 8000px'></div>";
const ID = "rulers-highlighter-";
add_task(function* () {
let { inspector, testActor } = yield openInspectorForURL(TEST_URL);
let front = inspector.inspector;
let highlighter = yield front.getHighlighterByType("RulersHighlighter");
// the rulers doesn't need any node, but as highligher it seems mandatory
// ones, so the body is given
let body = yield getNodeFront("body", inspector);
yield highlighter.show(body);
yield isUpdatedAfterScroll(highlighter, inspector, testActor);
yield highlighter.finalize();
});
function* isUpdatedAfterScroll(highlighterFront, inspector, testActor) {
info("Check the rulers' position by default");
let xAxisRulerTransform = yield testActor.getHighlighterNodeAttribute(
`${ID}x-axis-ruler`, "transform", highlighterFront);
let xAxisTextTransform = yield testActor.getHighlighterNodeAttribute(
`${ID}x-axis-text`, "transform", highlighterFront);
let yAxisRulerTransform = yield testActor.getHighlighterNodeAttribute(
`${ID}y-axis-ruler`, "transform", highlighterFront);
let yAxisTextTransform = yield testActor.getHighlighterNodeAttribute(
`${ID}y-axis-text`, "transform", highlighterFront);
is(xAxisRulerTransform, null, "x axis ruler is positioned properly");
is(xAxisTextTransform, null, "x axis text are positioned properly");
is(yAxisRulerTransform, null, "y axis ruler is positioned properly");
is(yAxisTextTransform, null, "y axis text are positioned properly");
info("Ask the content window to scroll to specific coords");
let x = 200, y = 300;
let data = yield testActor.scrollWindow(x, y);
is(data.x, x, "window scrolled properly horizontally");
is(data.y, y, "window scrolled properly vertically");
info("Check the rulers are properly positioned after the scrolling");
xAxisRulerTransform = yield testActor.getHighlighterNodeAttribute(
`${ID}x-axis-ruler`, "transform", highlighterFront);
xAxisTextTransform = yield testActor.getHighlighterNodeAttribute(
`${ID}x-axis-text`, "transform", highlighterFront);
yAxisRulerTransform = yield testActor.getHighlighterNodeAttribute(
`${ID}y-axis-ruler`, "transform", highlighterFront);
yAxisTextTransform = yield testActor.getHighlighterNodeAttribute(
`${ID}y-axis-text`, "transform", highlighterFront);
is(xAxisRulerTransform, `translate(-${x})`,
"x axis ruler is positioned properly");
is(xAxisTextTransform, `translate(-${x})`,
"x axis text are positioned properly");
is(yAxisRulerTransform, `translate(0, -${y})`,
"y axis ruler is positioned properly");
is(yAxisTextTransform, `translate(0, -${y})`,
"y axis text are positioned properly");
info("Ask the content window to scroll relative to the current position");
data = yield testActor.scrollWindow(-50, -60, true);
is(data.x, x - 50, "window scrolled properly horizontally");
is(data.y, y - 60, "window scrolled properly vertically");
info("Check the rulers are properly positioned after the relative scrolling");
xAxisRulerTransform = yield testActor.getHighlighterNodeAttribute(
`${ID}x-axis-ruler`, "transform", highlighterFront);
xAxisTextTransform = yield testActor.getHighlighterNodeAttribute(
`${ID}x-axis-text`, "transform", highlighterFront);
yAxisRulerTransform = yield testActor.getHighlighterNodeAttribute(
`${ID}y-axis-ruler`, "transform", highlighterFront);
yAxisTextTransform = yield testActor.getHighlighterNodeAttribute(
`${ID}y-axis-text`, "transform", highlighterFront);
is(xAxisRulerTransform, `translate(-${x - 50})`,
"x axis ruler is positioned properly");
is(xAxisTextTransform, `translate(-${x - 50})`,
"x axis text are positioned properly");
is(yAxisRulerTransform, `translate(0, -${y - 60})`,
"y axis ruler is positioned properly");
is(yAxisTextTransform, `translate(0, -${y - 60})`,
"y axis text are positioned properly");
}

View file

@ -0,0 +1,63 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the custom selector highlighter creates as many box-model
// highlighters as there are nodes that match the given selector
const TEST_URL = "data:text/html;charset=utf-8," +
"<div id='test-node'>test node</div>" +
"<ul>" +
" <li class='item'>item</li>" +
" <li class='item'>item</li>" +
" <li class='item'>item</li>" +
" <li class='item'>item</li>" +
" <li class='item'>item</li>" +
"</ul>";
const TEST_DATA = [{
selector: "#test-node",
containerCount: 1
}, {
selector: null,
containerCount: 0,
}, {
selector: undefined,
containerCount: 0,
}, {
selector: ".invalid-class",
containerCount: 0
}, {
selector: ".item",
containerCount: 5
}, {
selector: "#test-node, ul, .item",
containerCount: 7
}];
requestLongerTimeout(5);
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
let front = inspector.inspector;
let highlighter = yield front.getHighlighterByType("SelectorHighlighter");
let contextNode = yield getNodeFront("body", inspector);
for (let {selector, containerCount} of TEST_DATA) {
info("Showing the highlighter on " + selector + ". Expecting " +
containerCount + " highlighter containers");
yield highlighter.show(contextNode, {selector});
let nb = yield testActor.getSelectorHighlighterBoxNb(highlighter.actorID);
ok(nb !== null, "The number of highlighters was retrieved");
is(nb, containerCount, "The correct number of highlighers were created");
yield highlighter.hide();
}
yield highlighter.finalize();
});

View file

@ -0,0 +1,61 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the custom selector highlighter creates highlighters for nodes in
// the right frame.
const FRAME_SRC = "data:text/html;charset=utf-8," +
"<div class=sub-level-node></div>";
const TEST_URL = "data:text/html;charset=utf-8," +
"<div class=root-level-node></div>" +
"<iframe src=\"" + FRAME_SRC + "\" />";
const TEST_DATA = [{
selector: ".root-level-node",
containerCount: 1
}, {
selector: ".sub-level-node",
containerCount: 0
}, {
inIframe: true,
selector: ".root-level-node",
containerCount: 0
}, {
inIframe: true,
selector: ".sub-level-node",
containerCount: 1
}];
requestLongerTimeout(5);
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
let front = inspector.inspector;
let highlighter = yield front.getHighlighterByType("SelectorHighlighter");
for (let {inIframe, selector, containerCount} of TEST_DATA) {
info("Showing the highlighter on " + selector + ". Expecting " +
containerCount + " highlighter containers");
let contextNode;
if (inIframe) {
contextNode = yield getNodeFrontInFrame("body", "iframe", inspector);
} else {
contextNode = yield getNodeFront("body", inspector);
}
yield highlighter.show(contextNode, {selector});
let nb = yield testActor.getSelectorHighlighterBoxNb(highlighter.actorID);
ok(nb !== null, "The number of highlighters was retrieved");
is(nb, containerCount, "The correct number of highlighers were created");
yield highlighter.hide();
}
yield highlighter.finalize();
});

View file

@ -0,0 +1,39 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the picker works correctly with XBL anonymous nodes
const TEST_URL = URL_ROOT + "doc_inspector_highlighter_xbl.xul";
add_task(function* () {
let {inspector, toolbox, testActor} = yield openInspectorForURL(TEST_URL);
yield startPicker(toolbox);
info("Selecting the scale");
yield moveMouseOver("#scale");
yield doKeyPick({key: "VK_RETURN", options: {}});
is(inspector.selection.nodeFront.className, "scale-slider",
"The .scale-slider inside the scale was selected");
function doKeyPick(msg) {
info("Key pressed. Waiting for element to be picked");
testActor.synthesizeKey(msg);
return promise.all([
inspector.selection.once("new-node-front"),
inspector.once("inspector-updated")
]);
}
function moveMouseOver(selector) {
info("Waiting for element " + selector + " to be highlighted");
testActor.synthesizeMouse({
options: {type: "mousemove"},
center: true,
selector: selector
});
return inspector.toolbox.once("picker-node-hovered");
}
});

View file

@ -0,0 +1,72 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the highlighter stays correctly positioned and has the right aspect
// ratio even when the page is zoomed in or out.
const TEST_URL = "data:text/html;charset=utf-8,<div>zoom me</div>";
// TEST_LEVELS entries should contain the following properties:
// - level: the zoom level to test
// - expected: the style attribute value to check for on the root highlighter
// element.
const TEST_LEVELS = [{
level: 2,
expected: "position:absolute;transform-origin:top left;" +
"transform:scale(0.5);width:200%;height:200%;"
}, {
level: 1,
expected: "position:absolute;width:100%;height:100%;"
}, {
level: .5,
expected: "position:absolute;transform-origin:top left;" +
"transform:scale(2);width:50%;height:50%;"
}];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("Highlighting the test node");
yield hoverElement("div", inspector);
let isVisible = yield testActor.isHighlighting();
ok(isVisible, "The highlighter is visible");
for (let {level, expected} of TEST_LEVELS) {
info("Zoom to level " + level +
" and check that the highlighter is correct");
yield testActor.zoomPageTo(level);
isVisible = yield testActor.isHighlighting();
ok(isVisible, "The highlighter is still visible at zoom level " + level);
yield testActor.isNodeCorrectlyHighlighted("div", is);
info("Check that the highlighter root wrapper node was scaled down");
let style = yield getRootNodeStyle(testActor);
is(style, expected, "The style attribute of the root element is correct");
}
});
function* hoverElement(selector, inspector) {
info("Hovering node " + selector + " in the markup view");
let container = yield getContainerForSelector(selector, inspector);
yield hoverContainer(container, inspector);
}
function* hoverContainer(container, inspector) {
let onHighlight = inspector.toolbox.once("node-highlight");
EventUtils.synthesizeMouse(container.tagLine, 2, 2, {type: "mousemove"},
inspector.markup.doc.defaultView);
yield onHighlight;
}
function* getRootNodeStyle(testActor) {
let value = yield testActor.getHighlighterNodeAttribute(
"box-model-root", "style");
return value;
}

View file

@ -0,0 +1,43 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the highlighter element picker still works through iframe
// navigations.
const TEST_URI = "data:text/html;charset=utf-8," +
"<p>bug 699308 - test iframe navigation</p>" +
"<iframe src='data:text/html;charset=utf-8,hello world'></iframe>";
add_task(function* () {
let { toolbox, testActor } = yield openInspectorForURL(TEST_URI);
info("Starting element picker.");
yield startPicker(toolbox);
info("Waiting for highlighter to activate.");
let highlighterShowing = toolbox.once("highlighter-ready");
testActor.synthesizeMouse({
selector: "body",
options: {type: "mousemove"},
x: 1,
y: 1
});
yield highlighterShowing;
let isVisible = yield testActor.isHighlighting();
ok(isVisible, "Inspector is highlighting.");
yield testActor.reloadFrame("iframe");
info("Frame reloaded. Reloading again.");
yield testActor.reloadFrame("iframe");
info("Frame reloaded twice.");
isVisible = yield testActor.isHighlighting();
ok(isVisible, "Inspector is highlighting after iframe nav.");
info("Stopping element picker.");
yield toolbox.highlighterUtils.stopPicker();
});

View file

@ -0,0 +1,89 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Check the position and text content of the highlighter nodeinfo bar.
const TEST_URI = URL_ROOT + "doc_inspector_infobar_01.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URI);
let testData = [
{
selector: "#top",
position: "bottom",
tag: "div",
id: "top",
classes: ".class1.class2",
dims: "500" + " \u00D7 " + "100"
},
{
selector: "#vertical",
position: "overlap",
tag: "div",
id: "vertical",
classes: ""
// No dims as they will vary between computers
},
{
selector: "#bottom",
position: "top",
tag: "div",
id: "bottom",
classes: "",
dims: "500" + " \u00D7 " + "100"
},
{
selector: "body",
position: "bottom",
tag: "body",
classes: ""
// No dims as they will vary between computers
},
{
selector: "clipPath",
position: "bottom",
tag: "clipPath",
id: "clip",
classes: ""
// No dims as element is not displayed and we just want to test tag name
},
];
for (let currTest of testData) {
yield testPosition(currTest, inspector, testActor);
}
});
function* testPosition(test, inspector, testActor) {
info("Testing " + test.selector);
yield selectAndHighlightNode(test.selector, inspector);
let position = yield testActor.getHighlighterNodeAttribute(
"box-model-infobar-container", "position");
is(position, test.position, "Node " + test.selector + ": position matches");
let tag = yield testActor.getHighlighterNodeTextContent(
"box-model-infobar-tagname");
is(tag, test.tag, "node " + test.selector + ": tagName matches.");
if (test.id) {
let id = yield testActor.getHighlighterNodeTextContent(
"box-model-infobar-id");
is(id, "#" + test.id, "node " + test.selector + ": id matches.");
}
let classes = yield testActor.getHighlighterNodeTextContent(
"box-model-infobar-classes");
is(classes, test.classes, "node " + test.selector + ": classes match.");
if (test.dims) {
let dims = yield testActor.getHighlighterNodeTextContent(
"box-model-infobar-dimensions");
is(dims, test.dims, "node " + test.selector + ": dims match.");
}
}

View file

@ -0,0 +1,50 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Check the text content of the highlighter info bar for namespaced elements.
const XHTML = `
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:svg="http://www.w3.org/2000/svg">
<body>
<svg:svg width="100" height="100">
<svg:circle cx="0" cy="0" r="5"></svg:circle>
</svg:svg>
</body>
</html>
`;
const TEST_URI = "data:application/xhtml+xml;charset=utf-8," + encodeURI(XHTML);
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URI);
let testData = [
{
selector: "svg",
tag: "svg:svg"
},
{
selector: "circle",
tag: "svg:circle"
},
];
for (let currTest of testData) {
yield testNode(currTest, inspector, testActor);
}
});
function* testNode(test, inspector, testActor) {
info("Testing " + test.selector);
yield selectAndHighlightNode(test.selector, inspector);
let tag = yield testActor.getHighlighterNodeTextContent(
"box-model-infobar-tagname");
is(tag, test.tag, "node " + test.selector + ": tagName matches.");
}

View file

@ -0,0 +1,41 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Bug 1102269 - Make sure info-bar never gets outside of visible area after scrolling
const TEST_URI = URL_ROOT + "doc_inspector_infobar_03.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URI);
let testData = {
selector: "body",
position: "overlap",
style: "top:0px",
};
yield testPositionAndStyle(testData, inspector, testActor);
});
function* testPositionAndStyle(test, inspector, testActor) {
info("Testing " + test.selector);
yield selectAndHighlightNode(test.selector, inspector);
let style = yield testActor.getHighlighterNodeAttribute(
"box-model-infobar-container", "style");
is(style.split(";")[0], test.style,
"Infobar shows on top of the page when page isn't scrolled");
yield testActor.scrollWindow(0, 500);
style = yield testActor.getHighlighterNodeAttribute(
"box-model-infobar-container", "style");
is(style.split(";")[0], test.style,
"Infobar shows on top of the page even if the page is scrolled");
}

View file

@ -0,0 +1,46 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Bug 1309212 - Make sure info-bar is displayed with dimensions for text nodes.
const TEST_URI = URL_ROOT + "doc_inspector_infobar_textnode.html";
add_task(function* () {
let { inspector, testActor } = yield openInspectorForURL(TEST_URI);
let { walker } = inspector;
info("Retrieve the children of #textnode-container");
let div = yield walker.querySelector(walker.rootNode, "#textnode-container");
let { nodes } = yield inspector.walker.children(div);
// Children 0, 2 and 4 are text nodes, for which we expect to see an infobar containing
// dimensions.
// Regular text node.
info("Select the first text node");
yield selectNode(nodes[0], inspector, "test-highlight");
yield checkTextNodeInfoBar(testActor);
// Whitespace-only text node.
info("Select the second text node");
yield selectNode(nodes[2], inspector, "test-highlight");
yield checkTextNodeInfoBar(testActor);
// Regular text node.
info("Select the third text node");
yield selectNode(nodes[4], inspector, "test-highlight");
yield checkTextNodeInfoBar(testActor);
});
function* checkTextNodeInfoBar(testActor) {
let tag = yield testActor.getHighlighterNodeTextContent(
"box-model-infobar-tagname");
is(tag, "#text", "node display name is #text");
let dims = yield testActor.getHighlighterNodeTextContent(
"box-model-infobar-dimensions");
// Do not assert dimensions as they might be platform specific.
ok(!!dims, "node has dims");
}

View file

@ -0,0 +1,112 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* globals getTestActorWithoutToolbox */
"use strict";
// Tests for different ways to initialize the inspector.
const HTML = `
<div id="first" style="margin: 10em; font-size: 14pt;
font-family: helvetica, sans-serif; color: gray">
<h1>Some header text</h1>
<p id="salutation" style="font-size: 12pt">hi.</p>
<p id="body" style="font-size: 12pt">I am a test-case. This text exists
solely to provide some things to test the inspector initialization.</p>
<p>If you are reading this, you should go do something else instead. Maybe
read a book. Or better yet, write some test-cases for another bit of code.
<span style="font-style: italic">Inspector's!</span>
</p>
<p id="closing">end transmission</p>
</div>
`;
const TEST_URI = "data:text/html;charset=utf-8," + encodeURI(HTML);
add_task(function* () {
let tab = yield addTab(TEST_URI);
let testActor = yield getTestActorWithoutToolbox(tab);
yield testToolboxInitialization(testActor, tab);
yield testContextMenuInitialization(testActor);
yield testContextMenuInspectorAlreadyOpen(testActor);
});
function* testToolboxInitialization(testActor, tab) {
let target = TargetFactory.forTab(tab);
info("Opening inspector with gDevTools.");
let toolbox = yield gDevTools.showToolbox(target, "inspector");
let inspector = toolbox.getCurrentPanel();
ok(true, "Inspector started, and notification received.");
ok(inspector, "Inspector instance is accessible.");
ok(inspector.isReady, "Inspector instance is ready.");
is(inspector.target.tab, tab, "Valid target.");
yield selectNode("p", inspector);
yield testMarkupView("p", inspector);
yield testBreadcrumbs("p", inspector);
yield testActor.scrollIntoView("span");
yield selectNode("span", inspector);
yield testMarkupView("span", inspector);
yield testBreadcrumbs("span", inspector);
info("Destroying toolbox");
let destroyed = toolbox.once("destroyed");
toolbox.destroy();
yield destroyed;
ok("true", "'destroyed' notification received.");
ok(!gDevTools.getToolbox(target), "Toolbox destroyed.");
}
function* testContextMenuInitialization(testActor) {
info("Opening inspector by clicking on 'Inspect Element' context menu item");
yield clickOnInspectMenuItem(testActor, "#salutation");
info("Checking inspector state.");
yield testMarkupView("#salutation");
yield testBreadcrumbs("#salutation");
}
function* testContextMenuInspectorAlreadyOpen(testActor) {
info("Changing node by clicking on 'Inspect Element' context menu item");
let inspector = getActiveInspector();
ok(inspector, "Inspector is active");
yield clickOnInspectMenuItem(testActor, "#closing");
ok(true, "Inspector was updated when 'Inspect Element' was clicked.");
yield testMarkupView("#closing", inspector);
yield testBreadcrumbs("#closing", inspector);
}
function* testMarkupView(selector, inspector) {
inspector = inspector || getActiveInspector();
let nodeFront = yield getNodeFront(selector, inspector);
try {
is(inspector.selection.nodeFront, nodeFront,
"Right node is selected in the markup view");
} catch (ex) {
ok(false, "Got exception while resolving selected node of markup view.");
console.error(ex);
}
}
function* testBreadcrumbs(selector, inspector) {
inspector = inspector || getActiveInspector();
let nodeFront = yield getNodeFront(selector, inspector);
let b = inspector.breadcrumbs;
let expectedText = b.prettyPrintNodeAsText(nodeFront);
let button = b.container.querySelector("button[checked=true]");
ok(button, "A crumbs is checked=true");
is(button.getAttribute("title"), expectedText,
"Crumb refers to the right node");
}

View file

@ -0,0 +1,18 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// A regression test for bug 665880 to make sure elements inside <object> can
// be inspected without exceptions.
const TEST_URI = "data:text/html;charset=utf-8," +
"<object><p>browser_inspector_inspect-object-element.js</p></object>";
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URI);
yield selectNode("object", inspector);
ok(true, "Selected <object> without throwing");
});

View file

@ -0,0 +1,35 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that highlighter handles geometry changes correctly.
const TEST_URI = "data:text/html;charset=utf-8," +
"browser_inspector_invalidate.js\n" +
"<div style=\"width: 100px; height: 100px; background:yellow;\"></div>";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URI);
let divFront = yield getNodeFront("div", inspector);
info("Waiting for highlighter to activate");
yield inspector.highlighter.showBoxModel(divFront);
let rect = yield testActor.getSimpleBorderRect();
is(rect.width, 100, "The highlighter has the right width.");
info("Changing the test element's size and waiting for the highlighter " +
"to update");
yield testActor.changeHighlightedNodeWaitForUpdate(
"style",
"width: 200px; height: 100px; background:yellow;"
);
rect = yield testActor.getSimpleBorderRect();
is(rect.width, 200, "The highlighter has the right width after update");
info("Waiting for highlighter to hide");
yield inspector.highlighter.hideBoxModel();
});

View file

@ -0,0 +1,52 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test copy outer HTML from the keyboard/copy event
const TEST_URL = URL_ROOT + "doc_inspector_outerhtml.html";
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URL);
let root = inspector.markup._elt;
info("Test copy outerHTML for COMMENT node");
let comment = getElementByType(inspector, Ci.nsIDOMNode.COMMENT_NODE);
yield setSelectionNodeFront(comment, inspector);
yield checkClipboard("<!-- Comment -->", root);
info("Test copy outerHTML for DOCTYPE node");
let doctype = getElementByType(inspector, Ci.nsIDOMNode.DOCUMENT_TYPE_NODE);
yield setSelectionNodeFront(doctype, inspector);
yield checkClipboard("<!DOCTYPE html>", root);
info("Test copy outerHTML for ELEMENT node");
yield selectAndHighlightNode("div", inspector);
yield checkClipboard("<div><p>Test copy OuterHTML</p></div>", root);
});
function* setSelectionNodeFront(node, inspector) {
let updated = inspector.once("inspector-updated");
inspector.selection.setNodeFront(node);
yield updated;
}
function* checkClipboard(expectedText, node) {
try {
yield waitForClipboardPromise(() => fireCopyEvent(node), expectedText);
ok(true, "Clipboard successfully filled with : " + expectedText);
} catch (e) {
ok(false, "Clipboard could not be filled with the expected text : " +
expectedText);
}
}
function getElementByType(inspector, type) {
for (let [node] of inspector.markup._containers) {
if (node.nodeType === type) {
return node;
}
}
return null;
}

View file

@ -0,0 +1,48 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests that the keybindings for highlighting different elements work as
// intended.
const TEST_URI = "data:text/html;charset=utf-8," +
"<html><head><title>Test for the highlighter keybindings</title></head>" +
"<body><p><strong>Greetings, earthlings!</strong>" +
" I come in peace.</p></body></html>";
const TEST_DATA = [
{ key: "VK_LEFT", selectedNode: "p" },
{ key: "VK_LEFT", selectedNode: "body" },
{ key: "VK_LEFT", selectedNode: "html" },
{ key: "VK_RIGHT", selectedNode: "body" },
{ key: "VK_RIGHT", selectedNode: "p" },
{ key: "VK_RIGHT", selectedNode: "strong" },
];
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URI);
info("Selecting the deepest element to start with");
yield selectNode("strong", inspector);
let nodeFront = yield getNodeFront("strong", inspector);
is(inspector.selection.nodeFront, nodeFront,
"<strong> should be selected initially");
info("Focusing the currently active breadcrumb button");
let bc = inspector.breadcrumbs;
bc.nodeHierarchy[bc.currentIndex].button.focus();
for (let { key, selectedNode } of TEST_DATA) {
info("Pressing " + key + " to select " + selectedNode);
let updated = inspector.once("inspector-updated");
EventUtils.synthesizeKey(key, {});
yield updated;
let selectedNodeFront = yield getNodeFront(selectedNode, inspector);
is(inspector.selection.nodeFront, selectedNodeFront,
selectedNode + " is selected.");
}
});

View file

@ -0,0 +1,278 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that context menu items are enabled / disabled correctly.
const TEST_URL = URL_ROOT + "doc_inspector_menu.html";
const PASTE_MENU_ITEMS = [
"node-menu-pasteinnerhtml",
"node-menu-pasteouterhtml",
"node-menu-pastebefore",
"node-menu-pasteafter",
"node-menu-pastefirstchild",
"node-menu-pastelastchild",
];
const ACTIVE_ON_DOCTYPE_ITEMS = [
"node-menu-showdomproperties",
"node-menu-useinconsole"
];
const ALL_MENU_ITEMS = [
"node-menu-edithtml",
"node-menu-copyinner",
"node-menu-copyouter",
"node-menu-copyuniqueselector",
"node-menu-copyimagedatauri",
"node-menu-delete",
"node-menu-pseudo-hover",
"node-menu-pseudo-active",
"node-menu-pseudo-focus",
"node-menu-scrollnodeintoview",
"node-menu-screenshotnode",
"node-menu-add-attribute",
"node-menu-edit-attribute",
"node-menu-remove-attribute"
].concat(PASTE_MENU_ITEMS, ACTIVE_ON_DOCTYPE_ITEMS);
const INACTIVE_ON_DOCTYPE_ITEMS =
ALL_MENU_ITEMS.filter(item => ACTIVE_ON_DOCTYPE_ITEMS.indexOf(item) === -1);
/**
* Test cases, each item of this array may define the following properties:
* desc: string that will be logged
* selector: selector of the node to be selected
* disabled: items that should have disabled state
* clipboardData: clipboard content
* clipboardDataType: clipboard content type
* attributeTrigger: attribute that will be used as context menu trigger
*/
const TEST_CASES = [
{
desc: "doctype node with empty clipboard",
selector: null,
disabled: INACTIVE_ON_DOCTYPE_ITEMS,
},
{
desc: "doctype node with html on clipboard",
clipboardData: "<p>some text</p>",
clipboardDataType: "html",
selector: null,
disabled: INACTIVE_ON_DOCTYPE_ITEMS,
},
{
desc: "element node HTML on the clipboard",
clipboardData: "<p>some text</p>",
clipboardDataType: "html",
disabled: [
"node-menu-copyimagedatauri",
"node-menu-edit-attribute",
"node-menu-remove-attribute"
],
selector: "#sensitivity",
},
{
desc: "<html> element",
clipboardData: "<p>some text</p>",
clipboardDataType: "html",
selector: "html",
disabled: [
"node-menu-copyimagedatauri",
"node-menu-pastebefore",
"node-menu-pasteafter",
"node-menu-pastefirstchild",
"node-menu-pastelastchild",
"node-menu-edit-attribute",
"node-menu-remove-attribute"
],
},
{
desc: "<body> with HTML on clipboard",
clipboardData: "<p>some text</p>",
clipboardDataType: "html",
selector: "body",
disabled: [
"node-menu-copyimagedatauri",
"node-menu-pastebefore",
"node-menu-pasteafter",
"node-menu-edit-attribute",
"node-menu-remove-attribute"
]
},
{
desc: "<img> with HTML on clipboard",
clipboardData: "<p>some text</p>",
clipboardDataType: "html",
selector: "img",
disabled: [
"node-menu-edit-attribute",
"node-menu-remove-attribute"
]
},
{
desc: "<head> with HTML on clipboard",
clipboardData: "<p>some text</p>",
clipboardDataType: "html",
selector: "head",
disabled: [
"node-menu-copyimagedatauri",
"node-menu-pastebefore",
"node-menu-pasteafter",
"node-menu-screenshotnode",
"node-menu-edit-attribute",
"node-menu-remove-attribute"
],
},
{
desc: "<head> with no html on clipboard",
selector: "head",
disabled: PASTE_MENU_ITEMS.concat([
"node-menu-copyimagedatauri",
"node-menu-screenshotnode",
"node-menu-edit-attribute",
"node-menu-remove-attribute"
]),
},
{
desc: "<element> with text on clipboard",
clipboardData: "some text",
clipboardDataType: undefined,
selector: "#paste-area",
disabled: [
"node-menu-copyimagedatauri",
"node-menu-edit-attribute",
"node-menu-remove-attribute"
]
},
{
desc: "<element> with base64 encoded image data uri on clipboard",
clipboardData:
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABC" +
"AAAAAA6fptVAAAACklEQVQYV2P4DwABAQEAWk1v8QAAAABJRU5ErkJggg==",
clipboardDataType: undefined,
selector: "#paste-area",
disabled: PASTE_MENU_ITEMS.concat([
"node-menu-copyimagedatauri",
"node-menu-edit-attribute",
"node-menu-remove-attribute"
]),
},
{
desc: "<element> with empty string on clipboard",
clipboardData: "",
clipboardDataType: undefined,
selector: "#paste-area",
disabled: PASTE_MENU_ITEMS.concat([
"node-menu-copyimagedatauri",
"node-menu-edit-attribute",
"node-menu-remove-attribute"
]),
},
{
desc: "<element> with whitespace only on clipboard",
clipboardData: " \n\n\t\n\n \n",
clipboardDataType: undefined,
selector: "#paste-area",
disabled: PASTE_MENU_ITEMS.concat([
"node-menu-copyimagedatauri",
"node-menu-edit-attribute",
"node-menu-remove-attribute"
]),
},
{
desc: "<element> that isn't visible on the page, empty clipboard",
selector: "#hiddenElement",
disabled: PASTE_MENU_ITEMS.concat([
"node-menu-copyimagedatauri",
"node-menu-screenshotnode",
"node-menu-edit-attribute",
"node-menu-remove-attribute"
]),
},
{
desc: "<element> nested in another hidden element, empty clipboard",
selector: "#nestedHiddenElement",
disabled: PASTE_MENU_ITEMS.concat([
"node-menu-copyimagedatauri",
"node-menu-screenshotnode",
"node-menu-edit-attribute",
"node-menu-remove-attribute"
]),
},
{
desc: "<element> with context menu triggered on attribute, empty clipboard",
selector: "#attributes",
disabled: PASTE_MENU_ITEMS.concat(["node-menu-copyimagedatauri"]),
attributeTrigger: "data-edit"
}
];
var clipboard = require("sdk/clipboard");
registerCleanupFunction(() => {
clipboard = null;
});
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URL);
for (let test of TEST_CASES) {
let { desc, disabled, selector, attributeTrigger } = test;
info(`Test ${desc}`);
setupClipboard(test.clipboardData, test.clipboardDataType);
let front = yield getNodeFrontForSelector(selector, inspector);
info("Selecting the specified node.");
yield selectNode(front, inspector);
info("Simulating context menu click on the selected node container.");
let nodeFrontContainer = getContainerForNodeFront(front, inspector);
let contextMenuTrigger = attributeTrigger
? nodeFrontContainer.tagLine.querySelector(
`[data-attr="${attributeTrigger}"]`)
: nodeFrontContainer.tagLine;
let allMenuItems = openContextMenuAndGetAllItems(inspector, {
target: contextMenuTrigger,
});
for (let id of ALL_MENU_ITEMS) {
let menuItem = allMenuItems.find(item => item.id === id);
let shouldBeDisabled = disabled.indexOf(id) !== -1;
is(menuItem.disabled, shouldBeDisabled,
`#${id} should be ${shouldBeDisabled ? "disabled" : "enabled"} `);
}
}
});
/**
* A helper that fetches a front for a node that matches the given selector or
* doctype node if the selector is falsy.
*/
function* getNodeFrontForSelector(selector, inspector) {
if (selector) {
info("Retrieving front for selector " + selector);
return getNodeFront(selector, inspector);
}
info("Retrieving front for doctype node");
let {nodes} = yield inspector.walker.children(inspector.walker.rootNode);
return nodes[0];
}
/**
* A helper that populates the clipboard with data of given type. Clears the
* clipboard if data is falsy.
*/
function setupClipboard(data, type) {
if (data) {
info("Populating clipboard with " + type + " data.");
clipboard.set(data, type);
} else {
info("Clearing clipboard.");
clipboard.set("", "text");
}
}

View file

@ -0,0 +1,49 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the various copy items in the context menu works correctly.
const TEST_URL = URL_ROOT + "doc_inspector_menu.html";
const COPY_ITEMS_TEST_DATA = [
{
desc: "copy inner html",
id: "node-menu-copyinner",
selector: "[data-id=\"copy\"]",
text: "Paragraph for testing copy",
},
{
desc: "copy outer html",
id: "node-menu-copyouter",
selector: "[data-id=\"copy\"]",
text: "<p data-id=\"copy\">Paragraph for testing copy</p>",
},
{
desc: "copy unique selector",
id: "node-menu-copyuniqueselector",
selector: "[data-id=\"copy\"]",
text: "body > div:nth-child(1) > p:nth-child(2)",
},
{
desc: "copy image data uri",
id: "node-menu-copyimagedatauri",
selector: "#copyimage",
text: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABC" +
"AAAAAA6fptVAAAACklEQVQYV2P4DwABAQEAWk1v8QAAAABJRU5ErkJggg==",
},
];
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URL);
for (let {desc, id, selector, text} of COPY_ITEMS_TEST_DATA) {
info("Testing " + desc);
yield selectNode(selector, inspector);
let allMenuItems = openContextMenuAndGetAllItems(inspector);
let item = allMenuItems.find(i => i.id === id);
ok(item, "The popup has a " + desc + " menu item.");
yield waitForClipboardPromise(() => item.click(), text);
}
});

View file

@ -0,0 +1,42 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that HTML can be pasted in SVG elements.
const TEST_URL = URL_ROOT + "doc_inspector_svg.svg";
const PASTE_AS_FIRST_CHILD = '<circle xmlns="http://www.w3.org/2000/svg" cx="42" cy="42" r="5"/>';
const PASTE_AS_LAST_CHILD = '<circle xmlns="http://www.w3.org/2000/svg" cx="42" cy="42" r="15"/>';
add_task(function* () {
let clipboard = require("sdk/clipboard");
let { inspector, testActor } = yield openInspectorForURL(TEST_URL);
let refSelector = "svg";
let oldHTML = yield testActor.getProperty(refSelector, "innerHTML");
yield selectNode(refSelector, inspector);
let markupTagLine = getContainerForSelector(refSelector, inspector).tagLine;
yield pasteContent("node-menu-pastefirstchild", PASTE_AS_FIRST_CHILD);
yield pasteContent("node-menu-pastelastchild", PASTE_AS_LAST_CHILD);
let html = yield testActor.getProperty(refSelector, "innerHTML");
let expectedHtml = PASTE_AS_FIRST_CHILD + oldHTML + PASTE_AS_LAST_CHILD;
is(html, expectedHtml, "The innerHTML of the SVG node is correct");
// Helpers
function* pasteContent(menuId, clipboardData) {
let allMenuItems = openContextMenuAndGetAllItems(inspector, {
target: markupTagLine,
});
info(`Testing ${menuId} for ${clipboardData}`);
clipboard.set(clipboardData);
let onMutation = inspector.once("markupmutation");
allMenuItems.find(item => item.id === menuId).click();
info("Waiting for mutation to occur");
yield onMutation;
}
});

View file

@ -0,0 +1,128 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that different paste items work in the context menu
const TEST_URL = URL_ROOT + "doc_inspector_menu.html";
const PASTE_ADJACENT_HTML_DATA = [
{
desc: "As First Child",
clipboardData: "2",
menuId: "node-menu-pastefirstchild",
},
{
desc: "As Last Child",
clipboardData: "4",
menuId: "node-menu-pastelastchild",
},
{
desc: "Before",
clipboardData: "1",
menuId: "node-menu-pastebefore",
},
{
desc: "After",
clipboardData: "<span>5</span>",
menuId: "node-menu-pasteafter",
},
];
var clipboard = require("sdk/clipboard");
registerCleanupFunction(() => {
clipboard = null;
});
add_task(function* () {
let { inspector, testActor } = yield openInspectorForURL(TEST_URL);
yield testPasteOuterHTMLMenu();
yield testPasteInnerHTMLMenu();
yield testPasteAdjacentHTMLMenu();
function* testPasteOuterHTMLMenu() {
info("Testing that 'Paste Outer HTML' menu item works.");
clipboard.set("this was pasted (outerHTML)");
let outerHTMLSelector = "#paste-area h1";
let nodeFront = yield getNodeFront(outerHTMLSelector, inspector);
yield selectNode(nodeFront, inspector);
let allMenuItems = openContextMenuAndGetAllItems(inspector, {
target: getContainerForNodeFront(nodeFront, inspector).tagLine,
});
let onNodeReselected = inspector.markup.once("reselectedonremoved");
allMenuItems.find(item => item.id === "node-menu-pasteouterhtml").click();
info("Waiting for inspector selection to update");
yield onNodeReselected;
let outerHTML = yield testActor.getProperty("body", "outerHTML");
ok(outerHTML.includes(clipboard.get()),
"Clipboard content was pasted into the node's outer HTML.");
ok(!(yield testActor.hasNode(outerHTMLSelector)),
"The original node was removed.");
}
function* testPasteInnerHTMLMenu() {
info("Testing that 'Paste Inner HTML' menu item works.");
clipboard.set("this was pasted (innerHTML)");
let innerHTMLSelector = "#paste-area .inner";
let getInnerHTML = () => testActor.getProperty(innerHTMLSelector,
"innerHTML");
let origInnerHTML = yield getInnerHTML();
let nodeFront = yield getNodeFront(innerHTMLSelector, inspector);
yield selectNode(nodeFront, inspector);
let allMenuItems = openContextMenuAndGetAllItems(inspector, {
target: getContainerForNodeFront(nodeFront, inspector).tagLine,
});
let onMutation = inspector.once("markupmutation");
allMenuItems.find(item => item.id === "node-menu-pasteinnerhtml").click();
info("Waiting for mutation to occur");
yield onMutation;
ok((yield getInnerHTML()) === clipboard.get(),
"Clipboard content was pasted into the node's inner HTML.");
ok((yield testActor.hasNode(innerHTMLSelector)),
"The original node has been preserved.");
yield undoChange(inspector);
ok((yield getInnerHTML()) === origInnerHTML,
"Previous innerHTML has been restored after undo");
}
function* testPasteAdjacentHTMLMenu() {
let refSelector = "#paste-area .adjacent .ref";
let adjacentNodeSelector = "#paste-area .adjacent";
let nodeFront = yield getNodeFront(refSelector, inspector);
yield selectNode(nodeFront, inspector);
let markupTagLine = getContainerForNodeFront(nodeFront, inspector).tagLine;
for (let { clipboardData, menuId } of PASTE_ADJACENT_HTML_DATA) {
let allMenuItems = openContextMenuAndGetAllItems(inspector, {
target: markupTagLine,
});
info(`Testing ${menuId} for ${clipboardData}`);
clipboard.set(clipboardData);
let onMutation = inspector.once("markupmutation");
allMenuItems.find(item => item.id === menuId).click();
info("Waiting for mutation to occur");
yield onMutation;
}
let html = yield testActor.getProperty(adjacentNodeSelector, "innerHTML");
ok(html.trim() === "1<span class=\"ref\">234</span><span>5</span>",
"The Paste as Last Child / as First Child / Before / After worked as " +
"expected");
yield undoChange(inspector);
html = yield testActor.getProperty(adjacentNodeSelector, "innerHTML");
ok(html.trim() === "1<span class=\"ref\">234</span>",
"Undo works for paste adjacent HTML");
}
});

View file

@ -0,0 +1,61 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests "Use in Console" menu item
const TEST_URL = URL_ROOT + "doc_inspector_menu.html";
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.toolbox.splitconsoleEnabled");
});
// Use the old webconsole since the node isn't being rendered as an HTML tag
// in the new one (Bug 1304794)
Services.prefs.setBoolPref("devtools.webconsole.new-frontend-enabled", false);
registerCleanupFunction(function* () {
Services.prefs.clearUserPref("devtools.webconsole.new-frontend-enabled");
});
add_task(function* () {
let { inspector, toolbox } = yield openInspectorForURL(TEST_URL);
yield testUseInConsole();
function* testUseInConsole() {
info("Testing 'Use in Console' menu item.");
yield selectNode("#console-var", inspector);
let container = yield getContainerForSelector("#console-var", inspector);
let allMenuItems = openContextMenuAndGetAllItems(inspector, {
target: container.tagLine,
});
let menuItem = allMenuItems.find(i => i.id === "node-menu-useinconsole");
menuItem.click();
yield inspector.once("console-var-ready");
let hud = toolbox.getPanel("webconsole").hud;
let jsterm = hud.jsterm;
let jstermInput = jsterm.hud.document.querySelector(".jsterm-input-node");
is(jstermInput.value, "temp0", "first console variable is named temp0");
let result = yield jsterm.execute();
isnot(result.textContent.indexOf('<p id="console-var">'), -1,
"variable temp0 references correct node");
yield selectNode("#console-var-multi", inspector);
menuItem.click();
yield inspector.once("console-var-ready");
is(jstermInput.value, "temp1", "second console variable is named temp1");
result = yield jsterm.execute();
isnot(result.textContent.indexOf('<p id="console-var-multi">'), -1,
"variable temp1 references correct node");
jsterm.clearHistory();
}
});

View file

@ -0,0 +1,79 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that attribute items work in the context menu
const TEST_URL = URL_ROOT + "doc_inspector_menu.html";
add_task(function* () {
let { inspector, testActor } = yield openInspectorForURL(TEST_URL);
yield selectNode("#attributes", inspector);
yield testAddAttribute();
yield testEditAttribute();
yield testRemoveAttribute();
function* testAddAttribute() {
info("Triggering 'Add Attribute' and waiting for mutation to occur");
let addAttribute = getMenuItem("node-menu-add-attribute");
addAttribute.click();
EventUtils.synthesizeKey('class="u-hidden"', {});
let onMutation = inspector.once("markupmutation");
EventUtils.synthesizeKey("VK_RETURN", {});
yield onMutation;
let hasAttribute = testActor.hasNode("#attributes.u-hidden");
ok(hasAttribute, "attribute was successfully added");
}
function* testEditAttribute() {
info("Testing 'Edit Attribute' menu item");
let editAttribute = getMenuItem("node-menu-edit-attribute");
info("Triggering 'Edit Attribute' and waiting for mutation to occur");
inspector.nodeMenuTriggerInfo = {
type: "attribute",
name: "data-edit"
};
editAttribute.click();
EventUtils.synthesizeKey("data-edit='edited'", {});
let onMutation = inspector.once("markupmutation");
EventUtils.synthesizeKey("VK_RETURN", {});
yield onMutation;
let isAttributeChanged =
yield testActor.hasNode("#attributes[data-edit='edited']");
ok(isAttributeChanged, "attribute was successfully edited");
}
function* testRemoveAttribute() {
info("Testing 'Remove Attribute' menu item");
let removeAttribute = getMenuItem("node-menu-remove-attribute");
info("Triggering 'Remove Attribute' and waiting for mutation to occur");
inspector.nodeMenuTriggerInfo = {
type: "attribute",
name: "data-remove"
};
let onMutation = inspector.once("markupmutation");
removeAttribute.click();
yield onMutation;
let hasAttribute = yield testActor.hasNode("#attributes[data-remove]");
ok(!hasAttribute, "attribute was successfully removed");
}
function getMenuItem(id) {
let allMenuItems = openContextMenuAndGetAllItems(inspector, {
target: getContainerForSelector("#attributes", inspector).tagLine,
});
let menuItem = allMenuItems.find(i => i.id === id);
ok(menuItem, "Menu item '" + id + "' found");
// Close the menu so synthesizing future keys won't select menu items.
EventUtils.synthesizeKey("VK_ESCAPE", {});
return menuItem;
}
});

View file

@ -0,0 +1,95 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Tests for menuitem functionality that doesn't fit into any specific category
const TEST_URL = URL_ROOT + "doc_inspector_menu.html";
add_task(function* () {
let { inspector, toolbox, testActor } = yield openInspectorForURL(TEST_URL);
yield testShowDOMProperties();
yield testDuplicateNode();
yield testDeleteNode();
yield testDeleteRootNode();
yield testScrollIntoView();
function* testShowDOMProperties() {
info("Testing 'Show DOM Properties' menu item.");
let allMenuItems = openContextMenuAndGetAllItems(inspector);
let showDOMPropertiesNode =
allMenuItems.find(item => item.id === "node-menu-showdomproperties");
ok(showDOMPropertiesNode, "the popup menu has a show dom properties item");
let consoleOpened = toolbox.once("webconsole-ready");
info("Triggering 'Show DOM Properties' and waiting for inspector open");
showDOMPropertiesNode.click();
yield consoleOpened;
let webconsoleUI = toolbox.getPanel("webconsole").hud.ui;
let messagesAdded = webconsoleUI.once("new-messages");
yield messagesAdded;
info("Checking if 'inspect($0)' was evaluated");
ok(webconsoleUI.jsterm.history[0] === "inspect($0)");
yield toolbox.toggleSplitConsole();
}
function* testDuplicateNode() {
info("Testing 'Duplicate Node' menu item for normal elements.");
yield selectNode(".duplicate", inspector);
is((yield testActor.getNumberOfElementMatches(".duplicate")), 1,
"There should initially be 1 .duplicate node");
let allMenuItems = openContextMenuAndGetAllItems(inspector);
let menuItem =
allMenuItems.find(item => item.id === "node-menu-duplicatenode");
ok(menuItem, "'Duplicate node' menu item should exist");
info("Triggering 'Duplicate Node' and waiting for inspector to update");
let updated = inspector.once("markupmutation");
menuItem.click();
yield updated;
is((yield testActor.getNumberOfElementMatches(".duplicate")), 2,
"The duplicated node should be in the markup.");
let container = yield getContainerForSelector(".duplicate + .duplicate",
inspector);
ok(container, "A MarkupContainer should be created for the new node");
}
function* testDeleteNode() {
info("Testing 'Delete Node' menu item for normal elements.");
yield selectNode("#delete", inspector);
let allMenuItems = openContextMenuAndGetAllItems(inspector);
let deleteNode = allMenuItems.find(item => item.id === "node-menu-delete");
ok(deleteNode, "the popup menu has a delete menu item");
let updated = inspector.once("inspector-updated");
info("Triggering 'Delete Node' and waiting for inspector to update");
deleteNode.click();
yield updated;
ok(!(yield testActor.hasNode("#delete")), "Node deleted");
}
function* testDeleteRootNode() {
info("Testing 'Delete Node' menu item does not delete root node.");
yield selectNode("html", inspector);
let allMenuItems = openContextMenuAndGetAllItems(inspector);
let deleteNode = allMenuItems.find(item => item.id === "node-menu-delete");
deleteNode.click();
let deferred = defer();
executeSoon(deferred.resolve);
yield deferred.promise;
ok((yield testActor.eval("!!content.document.documentElement")),
"Document element still alive.");
}
function* testScrollIntoView() {
// Follow up bug to add this test - https://bugzilla.mozilla.org/show_bug.cgi?id=1154107
todo(false, "Verify that node is scrolled into the viewport.");
}
});

View file

@ -0,0 +1,50 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that inspector works when navigating to error pages.
const TEST_URL_1 = "data:text/html,<html><body id=\"test-doc-1\">page</body></html>";
const TEST_URL_2 = "http://127.0.0.1:36325/";
const TEST_URL_3 = "http://www.wronguri.wronguri/";
const TEST_URL_4 = "data:text/html,<html><body>test-doc-4</body></html>";
add_task(function* () {
// Open the inspector on a valid URL
let { inspector, testActor } = yield openInspectorForURL(TEST_URL_1);
info("Navigate to closed port");
yield navigateTo(inspector, TEST_URL_2);
let documentURI = yield testActor.eval("document.documentURI;");
ok(documentURI.startsWith("about:neterror"), "content is correct.");
let hasPage = yield getNodeFront("#test-doc-1", inspector);
ok(!hasPage, "Inspector actor is no longer able to reach previous page DOM node");
let hasNetErrorNode = yield getNodeFront("#errorShortDesc", inspector);
ok(hasNetErrorNode, "Inspector actor is able to reach error page DOM node");
let bundle = Services.strings.createBundle("chrome://global/locale/appstrings.properties");
let domain = TEST_URL_2.match(/^http:\/\/(.*)\/$/)[1];
let errorMsg = bundle.formatStringFromName("connectionFailure",
[domain], 1);
is(yield getDisplayedNodeTextContent("#errorShortDescText", inspector), errorMsg,
"Inpector really inspects the error page");
info("Navigate to unknown domain");
yield navigateTo(inspector, TEST_URL_3);
domain = TEST_URL_3.match(/^http:\/\/(.*)\/$/)[1];
errorMsg = bundle.formatStringFromName("dnsNotFound",
[domain], 1);
is(yield getDisplayedNodeTextContent("#errorShortDescText", inspector), errorMsg,
"Inspector really inspects the new error page");
info("Navigate to a valid url");
yield navigateTo(inspector, TEST_URL_4);
is(yield getDisplayedNodeTextContent("body", inspector), "test-doc-4",
"Inspector really inspects the valid url");
});

View file

@ -0,0 +1,43 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that inspector updates when page is navigated.
const TEST_URL_FILE = "browser/devtools/client/inspector/test/" +
"doc_inspector_breadcrumbs.html";
const TEST_URL_1 = "http://test1.example.org/" + TEST_URL_FILE;
const TEST_URL_2 = "http://test2.example.org/" + TEST_URL_FILE;
add_task(function* () {
let { inspector, testActor } = yield openInspectorForURL(TEST_URL_1);
yield selectNode("#i1", inspector);
info("Navigating to a different page.");
yield navigateTo(inspector, TEST_URL_2);
ok(true, "New page loaded");
yield selectNode("#i1", inspector);
let markuploaded = inspector.once("markuploaded");
let onUpdated = inspector.once("inspector-updated");
info("Going back in history");
yield testActor.eval("history.go(-1)");
info("Waiting for markup view to load after going back in history.");
yield markuploaded;
info("Check that the inspector updates");
yield onUpdated;
ok(true, "Old page loaded");
is((yield testActor.eval("location.href;")), TEST_URL_1, "URL is correct.");
yield selectNode("#i1", inspector);
});

View file

@ -0,0 +1,37 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that inspector works correctly when opened against a net error page
const TEST_URL_1 = "http://127.0.0.1:36325/";
const TEST_URL_2 = "data:text/html,<html><body>test-doc-2</body></html>";
add_task(function* () {
// Unfortunately, net error page are not firing load event, so that we can't
// use addTab helper and have to do that:
let tab = gBrowser.selectedTab = gBrowser.addTab("data:text/html,empty");
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
yield ContentTask.spawn(tab.linkedBrowser, { url: TEST_URL_1 }, function* ({ url }) {
// Also, the neterror being privileged, the DOMContentLoaded only fires on
// the chromeEventHandler.
let { chromeEventHandler } = docShell; // eslint-disable-line no-undef
let onDOMContentLoaded = ContentTaskUtils.waitForEvent(chromeEventHandler,
"DOMContentLoaded", true);
content.location = url;
yield onDOMContentLoaded;
});
let { inspector, testActor } = yield openInspector();
ok(true, "Inspector loaded on the already opened net error");
let documentURI = yield testActor.eval("document.documentURI;");
ok(documentURI.startsWith("about:neterror"), "content is really a net error page.");
info("Navigate to a valid url");
yield navigateTo(inspector, TEST_URL_2);
is(yield getDisplayedNodeTextContent("body", inspector), "test-doc-2",
"Inspector really inspects the valid url");
});

View file

@ -0,0 +1,27 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the inspector panel has a sidebar pane toggle button, and that
// this button is visible both in BOTTOM and SIDE hosts.
add_task(function* () {
info("Open the inspector in a bottom toolbox host");
let {toolbox, inspector} = yield openInspectorForURL("about:blank", "bottom");
let button = inspector.panelDoc.querySelector(".sidebar-toggle");
ok(button, "The toggle button exists in the DOM");
is(button.parentNode.id, "inspector-sidebar-toggle-box",
"The toggle button has the right parent");
ok(button.getAttribute("title"), "The tool tip has initial state");
ok(!button.classList.contains("pane-collapsed"), "The button is in expanded state");
ok(!!button.getClientRects().length, "The button is visible");
info("Switch the host to side type");
yield toolbox.switchHost("side");
ok(!!button.getClientRects().length, "The button is still visible");
ok(!button.classList.contains("pane-collapsed"),
"The button is still in expanded state");
});

View file

@ -0,0 +1,43 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the inspector toggled panel is visible by default, is hidden after
// clicking on the toggle button and remains expanded/collapsed when switching
// hosts.
add_task(function* () {
info("Open the inspector in a side toolbox host");
let {toolbox, inspector} = yield openInspectorForURL("about:blank", "side");
let panel = inspector.panelDoc.querySelector("#inspector-splitter-box .controlled");
let button = inspector.panelDoc.querySelector(".sidebar-toggle");
ok(!panel.classList.contains("pane-collapsed"), "The panel is in expanded state");
info("Listen to the end of the animation on the sidebar panel");
let onTransitionEnd = once(panel, "transitionend");
info("Click on the toggle button");
EventUtils.synthesizeMouseAtCenter(button, {},
inspector.panelDoc.defaultView);
yield onTransitionEnd;
ok(panel.classList.contains("pane-collapsed"), "The panel is in collapsed state");
ok(!panel.hasAttribute("animated"),
"The collapsed panel will not perform unwanted animations");
info("Switch the host to bottom type");
yield toolbox.switchHost("bottom");
ok(panel.classList.contains("pane-collapsed"), "The panel is in collapsed state");
info("Click on the toggle button to expand the panel again");
onTransitionEnd = once(panel, "transitionend");
EventUtils.synthesizeMouseAtCenter(button, {},
inspector.panelDoc.defaultView);
yield onTransitionEnd;
ok(!panel.classList.contains("pane-collapsed"), "The panel is in expanded state");
});

View file

@ -0,0 +1,38 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the toggle button can collapse and expand the inspector side/bottom
// panel, and that the appropriate attributes are updated in the process.
add_task(function* () {
let {inspector} = yield openInspectorForURL("about:blank");
let button = inspector.panelDoc.querySelector(".sidebar-toggle");
let panel = inspector.panelDoc.querySelector("#inspector-splitter-box .controlled");
ok(!button.classList.contains("pane-collapsed"), "The button is in expanded state");
info("Listen to the end of the animation on the sidebar panel");
let onTransitionEnd = once(panel, "transitionend");
info("Click on the toggle button");
EventUtils.synthesizeMouseAtCenter(button, {},
inspector.panelDoc.defaultView);
yield onTransitionEnd;
ok(button.classList.contains("pane-collapsed"), "The button is in collapsed state");
ok(panel.classList.contains("pane-collapsed"), "The panel is in collapsed state");
info("Listen again to the end of the animation on the sidebar panel");
onTransitionEnd = once(panel, "transitionend");
info("Click on the toggle button again");
EventUtils.synthesizeMouseAtCenter(button, {},
inspector.panelDoc.defaultView);
yield onTransitionEnd;
ok(!button.classList.contains("pane-collapsed"), "The button is in expanded state");
ok(!panel.classList.contains("pane-collapsed"), "The panel is in expanded state");
});

View file

@ -0,0 +1,33 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Test the keyboard navigation for the pane toggle using
* space and enter
*/
add_task(function* () {
let {inspector} = yield openInspectorForURL("about:blank", "side");
let panel = inspector.panelDoc.querySelector("#inspector-splitter-box .controlled");
let button = inspector.panelDoc.querySelector(".sidebar-toggle");
ok(!panel.classList.contains("pane-collapsed"), "The panel is in expanded state");
yield togglePane(button, "Press on the toggle button", panel, "VK_RETURN");
ok(panel.classList.contains("pane-collapsed"), "The panel is in collapsed state");
yield togglePane(button, "Press on the toggle button to expand the panel again",
panel, "VK_SPACE");
ok(!panel.classList.contains("pane-collapsed"), "The panel is in expanded state");
});
function* togglePane(button, message, panel, keycode) {
let onTransitionEnd = once(panel, "transitionend");
info(message);
button.focus();
EventUtils.synthesizeKey(keycode, {});
yield onTransitionEnd;
}

View file

@ -0,0 +1,30 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the highlighter's picker should be stopped when the toolbox is
// closed
const TEST_URI = "data:text/html;charset=utf-8," +
"<p>testing the highlighter goes away on destroy</p>";
add_task(function* () {
let { inspector, toolbox } = yield openInspectorForURL(TEST_URI);
let pickerStopped = toolbox.once("picker-stopped");
yield selectNode("p", inspector);
info("Inspector displayed and ready, starting the picker.");
yield startPicker(toolbox);
info("Destroying the toolbox.");
yield toolbox.destroy();
info("Waiting for the picker-stopped event that should be fired when the " +
"toolbox is destroyed.");
yield pickerStopped;
ok(true, "picker-stopped event fired after switch tools so picker is closed");
});

View file

@ -0,0 +1,27 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the highlighter's picker is stopped when a different tool is
// selected
const TEST_URI = "data:text/html;charset=UTF-8," +
"testing the highlighter goes away on tool selection";
add_task(function* () {
let { toolbox } = yield openInspectorForURL(TEST_URI);
let pickerStopped = toolbox.once("picker-stopped");
info("Starting the inspector picker");
yield startPicker(toolbox);
info("Selecting another tool than the inspector in the toolbox");
yield toolbox.selectNextTool();
info("Waiting for the picker-stopped event to be fired");
yield pickerStopped;
ok(true, "picker-stopped event fired after switch tools; picker is closed");
});

View file

@ -0,0 +1,78 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// Test that the inspector splitter is properly initialized in horizontal mode if the
// inspector starts in portrait mode.
add_task(function* () {
let { inspector, toolbox } = yield openInspectorForURL(
"data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>", "window");
let hostWindow = toolbox.win.parent;
let originalWidth = hostWindow.outerWidth;
let originalHeight = hostWindow.outerHeight;
let splitter = inspector.panelDoc.querySelector(".inspector-sidebar-splitter");
// If the inspector is not already in landscape mode.
if (!splitter.classList.contains("vert")) {
info("Resize toolbox window to force inspector to landscape mode");
let onClassnameMutation = waitForClassMutation(splitter);
hostWindow.resizeTo(800, 500);
yield onClassnameMutation;
ok(splitter.classList.contains("vert"), "Splitter is in vertical mode");
}
info("Resize toolbox window to force inspector to portrait mode");
let onClassnameMutation = waitForClassMutation(splitter);
hostWindow.resizeTo(500, 500);
yield onClassnameMutation;
ok(splitter.classList.contains("horz"), "Splitter is in horizontal mode");
info("Close the inspector");
yield gDevTools.closeToolbox(toolbox.target);
info("Reopen inspector");
({ inspector, toolbox } = yield openInspector("window"));
// Devtools window should still be 500px * 500px, inspector should still be in portrait.
splitter = inspector.panelDoc.querySelector(".inspector-sidebar-splitter");
ok(splitter.classList.contains("horz"), "Splitter is in horizontal mode");
info("Restore original window size");
toolbox.win.parent.resizeTo(originalWidth, originalHeight);
});
/**
* Helper waiting for a class attribute mutation on the provided target. Returns a
* promise.
*
* @param {Node} target
*   Node to observe
* @return {Promise} promise that will resolve upon receiving a mutation for the class
* attribute on the target.
*/
function waitForClassMutation(target) {
return new Promise(resolve => {
let observer = new MutationObserver((mutations) => {
for (let mutation of mutations) {
if (mutation.attributeName === "class") {
observer.disconnect();
resolve();
return;
}
}
});
observer.observe(target, { attributes: true });
});
}
registerCleanupFunction(function () {
// Restore the host type for other tests.
Services.prefs.clearUserPref("devtools.toolbox.host");
});

View file

@ -0,0 +1,160 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* globals getTestActorWithoutToolbox */
"use strict";
// Test that locking the pseudoclass displays correctly in the ruleview
const PSEUDO = ":hover";
const TEST_URL = "data:text/html;charset=UTF-8," +
"<head>" +
" <style>div {color:red;} div:hover {color:blue;}</style>" +
"</head>" +
"<body>" +
' <div id="parent-div">' +
' <div id="div-1">test div</div>' +
' <div id="div-2">test div2</div>' +
" </div>" +
"</body>";
add_task(function* () {
info("Creating the test tab and opening the rule-view");
let {toolbox, inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("Selecting the ruleview sidebar");
inspector.sidebar.select("ruleview");
let view = inspector.ruleview.view;
info("Selecting the test node");
yield selectNode("#div-1", inspector);
yield togglePseudoClass(inspector);
yield assertPseudoAddedToNode(inspector, testActor, view, "#div-1");
yield togglePseudoClass(inspector);
yield assertPseudoRemovedFromNode(testActor, "#div-1");
yield assertPseudoRemovedFromView(inspector, testActor, view, "#div-1");
yield togglePseudoClass(inspector);
yield testNavigate(inspector, testActor, view);
info("Toggle pseudo on the parent and ensure everything is toggled off");
yield selectNode("#parent-div", inspector);
yield togglePseudoClass(inspector);
yield assertPseudoRemovedFromNode(testActor, "#div-1");
yield assertPseudoRemovedFromView(inspector, testActor, view, "#div-1");
yield togglePseudoClass(inspector);
info("Assert pseudo is dismissed when toggling it on a sibling node");
yield selectNode("#div-2", inspector);
yield togglePseudoClass(inspector);
yield assertPseudoAddedToNode(inspector, testActor, view, "#div-2");
let hasLock = yield testActor.hasPseudoClassLock("#div-1", PSEUDO);
ok(!hasLock, "pseudo-class lock has been removed for the previous locked node");
info("Destroying the toolbox");
let tab = toolbox.target.tab;
yield toolbox.destroy();
// As the toolbox get detroyed, we need to fetch a new test-actor
testActor = yield getTestActorWithoutToolbox(tab);
yield assertPseudoRemovedFromNode(testActor, "#div-1");
yield assertPseudoRemovedFromNode(testActor, "#div-2");
});
function* togglePseudoClass(inspector) {
info("Toggle the pseudoclass, wait for it to be applied");
// Give the inspector panels a chance to update when the pseudoclass changes
let onPseudo = inspector.selection.once("pseudoclass");
let onRefresh = inspector.once("rule-view-refreshed");
// Walker uses SDK-events so calling walker.once does not return a promise.
let onMutations = once(inspector.walker, "mutations");
yield inspector.togglePseudoClass(PSEUDO);
yield onPseudo;
yield onRefresh;
yield onMutations;
}
function* testNavigate(inspector, testActor, ruleview) {
yield selectNode("#parent-div", inspector);
info("Make sure the pseudoclass is still on after navigating to a parent");
ok((yield testActor.hasPseudoClassLock("#div-1", PSEUDO)),
"pseudo-class lock is still applied after inspecting ancestor");
yield selectNode("#div-2", inspector);
info("Make sure the pseudoclass is still set after navigating to a " +
"non-hierarchy node");
ok(yield testActor.hasPseudoClassLock("#div-1", PSEUDO),
"pseudo-class lock is still on after inspecting sibling node");
yield selectNode("#div-1", inspector);
}
function* showPickerOn(selector, inspector) {
let nodeFront = yield getNodeFront(selector, inspector);
yield inspector.highlighter.showBoxModel(nodeFront);
}
function* assertPseudoAddedToNode(inspector, testActor, ruleview, selector) {
info("Make sure the pseudoclass lock is applied to " + selector + " and its ancestors");
let hasLock = yield testActor.hasPseudoClassLock(selector, PSEUDO);
ok(hasLock, "pseudo-class lock has been applied");
hasLock = yield testActor.hasPseudoClassLock("#parent-div", PSEUDO);
ok(hasLock, "pseudo-class lock has been applied");
hasLock = yield testActor.hasPseudoClassLock("body", PSEUDO);
ok(hasLock, "pseudo-class lock has been applied");
info("Check that the ruleview contains the pseudo-class rule");
let rules = ruleview.element.querySelectorAll(
".ruleview-rule.theme-separator");
is(rules.length, 3,
"rule view is showing 3 rules for pseudo-class locked div");
is(rules[1]._ruleEditor.rule.selectorText, "div:hover",
"rule view is showing " + PSEUDO + " rule");
info("Show the highlighter on " + selector);
yield showPickerOn(selector, inspector);
info("Check that the infobar selector contains the pseudo-class");
let value = yield testActor.getHighlighterNodeTextContent(
"box-model-infobar-pseudo-classes");
is(value, PSEUDO, "pseudo-class in infobar selector");
yield inspector.highlighter.hideBoxModel();
}
function* assertPseudoRemovedFromNode(testActor, selector) {
info("Make sure the pseudoclass lock is removed from #div-1 and its " +
"ancestors");
let hasLock = yield testActor.hasPseudoClassLock(selector, PSEUDO);
ok(!hasLock, "pseudo-class lock has been removed");
hasLock = yield testActor.hasPseudoClassLock("#parent-div", PSEUDO);
ok(!hasLock, "pseudo-class lock has been removed");
hasLock = yield testActor.hasPseudoClassLock("body", PSEUDO);
ok(!hasLock, "pseudo-class lock has been removed");
}
function* assertPseudoRemovedFromView(inspector, testActor, ruleview, selector) {
info("Check that the ruleview no longer contains the pseudo-class rule");
let rules = ruleview.element.querySelectorAll(
".ruleview-rule.theme-separator");
is(rules.length, 2, "rule view is showing 2 rules after removing lock");
yield showPickerOn(selector, inspector);
let value = yield testActor.getHighlighterNodeTextContent(
"box-model-infobar-pseudo-classes");
is(value, "", "pseudo-class removed from infobar selector");
yield inspector.highlighter.hideBoxModel();
}

View file

@ -0,0 +1,46 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the inspector has the correct pseudo-class locking menu items and
// that these items actually work
const TEST_URI = "data:text/html;charset=UTF-8," +
"pseudo-class lock node menu tests" +
"<div>test div</div>";
const PSEUDOS = ["hover", "active", "focus"];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URI);
yield selectNode("div", inspector);
let allMenuItems = openContextMenuAndGetAllItems(inspector);
yield testMenuItems(testActor, allMenuItems, inspector);
});
function* testMenuItems(testActor, allMenuItems, inspector) {
for (let pseudo of PSEUDOS) {
let menuItem =
allMenuItems.find(item => item.id === "node-menu-pseudo-" + pseudo);
ok(menuItem, ":" + pseudo + " menuitem exists");
is(menuItem.disabled, false, ":" + pseudo + " menuitem is enabled");
// Give the inspector panels a chance to update when the pseudoclass changes
let onPseudo = inspector.selection.once("pseudoclass");
let onRefresh = inspector.once("rule-view-refreshed");
// Walker uses SDK-events so calling walker.once does not return a promise.
let onMutations = once(inspector.walker, "mutations");
menuItem.click();
yield onPseudo;
yield onRefresh;
yield onMutations;
let hasLock = yield testActor.hasPseudoClassLock("div", ":" + pseudo);
ok(hasLock, "pseudo-class lock has been applied");
}
}

View file

@ -0,0 +1,32 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// A test to ensure reloading a page doesn't break the inspector.
// Reload should reselect the currently selected markup view element.
// This should work even when an element whose selector needs escaping
// is selected (bug 1002280).
const TEST_URI = "data:text/html,<p id='1'>p</p>";
add_task(function* () {
let { inspector, testActor } = yield openInspectorForURL(TEST_URI);
yield selectNode("p", inspector);
let markupLoaded = inspector.once("markuploaded");
info("Reloading page.");
yield testActor.eval("location.reload()");
info("Waiting for markupview to load after reload.");
yield markupLoaded;
let nodeFront = yield getNodeFront("p", inspector);
is(inspector.selection.nodeFront, nodeFront, "<p> selected after reload.");
info("Selecting a node to see that inspector still works.");
yield selectNode("body", inspector);
});

View file

@ -0,0 +1,48 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// A test to ensure reloading a page doesn't break the inspector.
// Reload should reselect the currently selected markup view element.
// This should work even when an element whose selector is inaccessible
// is selected (bug 1038651).
const TEST_URI = 'data:text/xml,<?xml version="1.0" standalone="no"?>' +
'<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"' +
' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' +
'<svg width="4cm" height="4cm" viewBox="0 0 400 400"' +
' xmlns="http://www.w3.org/2000/svg" version="1.1">' +
" <title>Example triangle01- simple example of a path</title>" +
" <desc>A path that draws a triangle</desc>" +
' <rect x="1" y="1" width="398" height="398"' +
' fill="none" stroke="blue" />' +
' <path d="M 100 100 L 300 100 L 200 300 z"' +
' fill="red" stroke="blue" stroke-width="3" />' +
"</svg>";
add_task(function* () {
let { inspector, testActor } = yield openInspectorForURL(TEST_URI);
let markupLoaded = inspector.once("markuploaded");
info("Reloading page.");
yield testActor.eval("location.reload()");
info("Waiting for markupview to load after reload.");
yield markupLoaded;
let svgFront = yield getNodeFront("svg", inspector);
is(inspector.selection.nodeFront, svgFront, "<svg> selected after reload.");
info("Selecting a node to see that inspector still works.");
yield selectNode("rect", inspector);
info("Reloading page.");
yield testActor.eval("location.reload");
let rectFront = yield getNodeFront("rect", inspector);
is(inspector.selection.nodeFront, rectFront, "<rect> selected after reload.");
});

View file

@ -0,0 +1,48 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Testing that the inspector doesn't go blank when navigating to a page that
// deletes an iframe while loading.
const TEST_URL = URL_ROOT + "doc_inspector_remove-iframe-during-load.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL("about:blank");
yield selectNode("body", inspector);
// We do not want to wait for the inspector to be fully ready before testing
// so we load TEST_URL and just wait for the content window to be done loading
yield testActor.loadAndWaitForCustomEvent(TEST_URL);
// The content doc contains a script that creates iframes and deletes them
// immediately after. It does this before the load event, after
// DOMContentLoaded and after load. This is what used to make the inspector go
// blank when navigating to that page.
// At this stage, there should be no iframes in the page anymore.
ok(!(yield testActor.hasNode("iframe")),
"Iframes added by the content page should have been removed");
// Create/remove an extra one now, after the load event.
info("Creating and removing an iframe.");
let onMarkupLoaded = inspector.once("markuploaded");
testActor.eval("new " + function () {
let iframe = document.createElement("iframe");
document.body.appendChild(iframe);
iframe.remove();
});
ok(!(yield testActor.hasNode("iframe")),
"The after-load iframe should have been removed.");
info("Waiting for markup-view to load.");
yield onMarkupLoaded;
// Assert that the markup-view is displayed and works
ok(!(yield testActor.hasNode("iframe")), "Iframe has been removed.");
is((yield testActor.getProperty("#yay", "textContent")), "load",
"Load event fired.");
yield selectNode("#yay", inspector);
});

View file

@ -0,0 +1,96 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint no-inline-comments: 0 */
"use strict";
requestLongerTimeout(2);
// Test that searching for nodes in the search field actually selects those
// nodes.
const TEST_URL = URL_ROOT + "doc_inspector_search.html";
// The various states of the inspector: [key, id, isValid]
// [
// what key to press,
// what id should be selected after the keypress,
// is the searched text valid selector
// ]
const KEY_STATES = [
["#", "b1", true], // #
["d", "b1", true], // #d
["1", "b1", true], // #d1
["VK_RETURN", "d1", true], // #d1
["VK_BACK_SPACE", "d1", true], // #d
["2", "d1", true], // #d2
["VK_RETURN", "d2", true], // #d2
["2", "d2", true], // #d22
["VK_RETURN", "d2", false], // #d22
["VK_BACK_SPACE", "d2", false], // #d2
["VK_RETURN", "d2", true], // #d2
["VK_BACK_SPACE", "d2", true], // #d
["1", "d2", true], // #d1
["VK_RETURN", "d1", true], // #d1
["VK_BACK_SPACE", "d1", true], // #d
["VK_BACK_SPACE", "d1", true], // #
["VK_BACK_SPACE", "d1", true], //
["d", "d1", true], // d
["i", "d1", true], // di
["v", "d1", true], // div
[".", "d1", true], // div.
["c", "d1", true], // div.c
["VK_UP", "d1", true], // div.c1
["VK_TAB", "d1", true], // div.c1
["VK_RETURN", "d2", true], // div.c1
["VK_BACK_SPACE", "d2", true], // div.c
["VK_BACK_SPACE", "d2", true], // div.
["VK_BACK_SPACE", "d2", true], // div
["VK_BACK_SPACE", "d2", true], // di
["VK_BACK_SPACE", "d2", true], // d
["VK_BACK_SPACE", "d2", true], //
[".", "d2", true], // .
["c", "d2", true], // .c
["1", "d2", true], // .c1
["VK_RETURN", "d2", true], // .c1
["VK_RETURN", "s2", true], // .c1
["VK_RETURN", "p1", true], // .c1
["P", "p1", true], // .c1P
["VK_RETURN", "p1", false], // .c1P
];
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URL);
let { searchBox } = inspector;
yield selectNode("#b1", inspector);
yield focusSearchBoxUsingShortcut(inspector.panelWin);
let index = 0;
for (let [ key, id, isValid ] of KEY_STATES) {
info(index + ": Pressing key " + key + " to get id " + id + ".");
let done = inspector.searchSuggestions.once("processing-done");
EventUtils.synthesizeKey(key, {}, inspector.panelWin);
yield done;
info("Got processing-done event");
if (key === "VK_RETURN") {
info("Waiting for " + (isValid ? "NO " : "") + "results");
yield inspector.search.once("search-result");
}
info("Waiting for search query to complete");
yield inspector.searchSuggestions._lastQuery;
info(inspector.selection.nodeFront.id + " is selected with text " +
searchBox.value);
let nodeFront = yield getNodeFront("#" + id, inspector);
is(inspector.selection.nodeFront, nodeFront,
"Correct node is selected for state " + index);
is(!searchBox.classList.contains("devtools-style-searchbox-no-match"), isValid,
"Correct searchbox result state for state " + index);
index++;
}
});

View file

@ -0,0 +1,169 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Testing that searching for combining selectors using the inspector search
// field produces correct suggestions.
const TEST_URL = URL_ROOT + "doc_inspector_search-suggestions.html";
// An array of (key, suggestions) pairs where key is a key to press and
// suggestions is an array of suggestions that should be shown in the popup.
// Suggestion is an object with label of the entry and optional count
// (defaults to 1)
const TEST_DATA = [
{
key: "d",
suggestions: [
{label: "div"},
{label: "#d1"},
{label: "#d2"}
]
},
{
key: "i",
suggestions: [{label: "div"}]
},
{
key: "v",
suggestions: []
},
{
key: " ",
suggestions: [
{label: "div div"},
{label: "div span"}
]
},
{
key: ">",
suggestions: [
{label: "div >div"},
{label: "div >span"}
]
},
{
key: "VK_BACK_SPACE",
suggestions: [
{label: "div div"},
{label: "div span"}
]
},
{
key: "+",
suggestions: [{label: "div +span"}]
},
{
key: "VK_BACK_SPACE",
suggestions: [
{label: "div div"},
{label: "div span"}
]
},
{
key: "VK_BACK_SPACE",
suggestions: []
},
{
key: "VK_BACK_SPACE",
suggestions: [{label: "div"}]
},
{
key: "VK_BACK_SPACE",
suggestions: [
{label: "div"},
{label: "#d1"},
{label: "#d2"}
]
},
{
key: "VK_BACK_SPACE",
suggestions: []
},
{
key: "p",
suggestions: [
{label: "p"},
{label: "#p1"},
{label: "#p2"},
{label: "#p3"},
]
},
{
key: " ",
suggestions: [{label: "p strong"}]
},
{
key: "+",
suggestions: [
{label: "p +button" },
{label: "p +p"}
]
},
{
key: "b",
suggestions: [{label: "p +button"}]
},
{
key: "u",
suggestions: [{label: "p +button"}]
},
{
key: "t",
suggestions: [{label: "p +button"}]
},
{
key: "t",
suggestions: [{label: "p +button"}]
},
{
key: "o",
suggestions: [{label: "p +button"}]
},
{
key: "n",
suggestions: []
},
{
key: "+",
suggestions: [{label: "p +button+p"}]
}
];
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URL);
let searchBox = inspector.searchBox;
let popup = inspector.searchSuggestions.searchPopup;
yield focusSearchBoxUsingShortcut(inspector.panelWin);
for (let { key, suggestions } of TEST_DATA) {
info("Pressing " + key + " to get " + formatSuggestions(suggestions));
let command = once(searchBox, "input");
EventUtils.synthesizeKey(key, {}, inspector.panelWin);
yield command;
info("Waiting for search query to complete");
yield inspector.searchSuggestions._lastQuery;
info("Query completed. Performing checks for input '" + searchBox.value +
"' - key pressed: " + key);
let actualSuggestions = popup.getItems().reverse();
is(popup.isOpen ? actualSuggestions.length : 0, suggestions.length,
"There are expected number of suggestions.");
for (let i = 0; i < suggestions.length; i++) {
is(actualSuggestions[i].label, suggestions[i].label,
"The suggestion at " + i + "th index is correct.");
}
}
});
function formatSuggestions(suggestions) {
return "[" + suggestions
.map(s => "'" + s.label + "'")
.join(", ") + "]";
}

View file

@ -0,0 +1,250 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Testing that searching for elements using the inspector search field
// produces correct suggestions.
const TEST_URL = URL_ROOT + "doc_inspector_search.html";
// An array of (key, suggestions) pairs where key is a key to press and
// suggestions is an array of suggestions that should be shown in the popup.
// Suggestion is an object with label of the entry and optional count
// (defaults to 1)
var TEST_DATA = [
{
key: "d",
suggestions: [
{label: "div"},
{label: "#d1"},
{label: "#d2"}
]
},
{
key: "i",
suggestions: [{label: "div"}]
},
{
key: "v",
suggestions: []
},
{
key: ".",
suggestions: [{label: "div.c1"}]
},
{
key: "VK_BACK_SPACE",
suggestions: []
},
{
key: "#",
suggestions: [
{label: "div#d1"},
{label: "div#d2"}
]
},
{
key: "VK_BACK_SPACE",
suggestions: []
},
{
key: "VK_BACK_SPACE",
suggestions: [{label: "div"}]
},
{
key: "VK_BACK_SPACE",
suggestions: [
{label: "div"},
{label: "#d1"},
{label: "#d2"}
]
},
{
key: "VK_BACK_SPACE",
suggestions: []
},
{
key: ".",
suggestions: [
{label: ".c1"},
{label: ".c2"}
]
},
{
key: "c",
suggestions: [
{label: ".c1"},
{label: ".c2"}
]
},
{
key: "2",
suggestions: []
},
{
key: "VK_BACK_SPACE",
suggestions: [
{label: ".c1"},
{label: ".c2"}
]
},
{
key: "1",
suggestions: []
},
{
key: "#",
suggestions: [
{label: "#d2"},
{label: "#p1"},
{label: "#s2"}
]
},
{
key: "VK_BACK_SPACE",
suggestions: []
},
{
key: "VK_BACK_SPACE",
suggestions: [
{label: ".c1"},
{label: ".c2"}
]
},
{
key: "VK_BACK_SPACE",
suggestions: [
{label: ".c1"},
{label: ".c2"}
]
},
{
key: "VK_BACK_SPACE",
suggestions: []
},
{
key: "#",
suggestions: [
{label: "#b1"},
{label: "#d1"},
{label: "#d2"},
{label: "#p1"},
{label: "#p2"},
{label: "#p3"},
{label: "#s1"},
{label: "#s2"}
]
},
{
key: "p",
suggestions: [
{label: "#p1"},
{label: "#p2"},
{label: "#p3"}
]
},
{
key: "VK_BACK_SPACE",
suggestions: [
{label: "#b1"},
{label: "#d1"},
{label: "#d2"},
{label: "#p1"},
{label: "#p2"},
{label: "#p3"},
{label: "#s1"},
{label: "#s2"}
]
},
{
key: "VK_BACK_SPACE",
suggestions: []
},
{
key: "p",
suggestions: [
{label: "p"},
{label: "#p1"},
{label: "#p2"},
{label: "#p3"}
]
},
{
key: "[", suggestions: []
},
{
key: "i", suggestions: []
},
{
key: "d", suggestions: []
},
{
key: "*", suggestions: []
},
{
key: "=", suggestions: []
},
{
key: "p", suggestions: []
},
{
key: "]", suggestions: []
},
{
key: ".",
suggestions: [
{label: "p[id*=p].c1"},
{label: "p[id*=p].c2"}
]
},
{
key: "VK_BACK_SPACE",
suggestions: []
},
{
key: "#",
suggestions: [
{label: "p[id*=p]#p1"},
{label: "p[id*=p]#p2"},
{label: "p[id*=p]#p3"}
]
}
];
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URL);
let searchBox = inspector.searchBox;
let popup = inspector.searchSuggestions.searchPopup;
yield focusSearchBoxUsingShortcut(inspector.panelWin);
for (let { key, suggestions } of TEST_DATA) {
info("Pressing " + key + " to get " + formatSuggestions(suggestions));
let command = once(searchBox, "input");
EventUtils.synthesizeKey(key, {}, inspector.panelWin);
yield command;
info("Waiting for search query to complete");
yield inspector.searchSuggestions._lastQuery;
info("Query completed. Performing checks for input '" +
searchBox.value + "'");
let actualSuggestions = popup.getItems().reverse();
is(popup.isOpen ? actualSuggestions.length : 0, suggestions.length,
"There are expected number of suggestions.");
for (let i = 0; i < suggestions.length; i++) {
is(actualSuggestions[i].label, suggestions[i].label,
"The suggestion at " + i + "th index is correct.");
}
}
});
function formatSuggestions(suggestions) {
return "[" + suggestions
.map(s => "'" + s.label + "'")
.join(", ") + "]";
}

Some files were not shown because too many files have changed in this diff Show more