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,62 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// This test actor is used for testing the addition of custom form data
// on NodeActor. Custom form property is set when 'form' event is sent
// by NodeActor actor (see 'onNodeActorForm' method).
const Events = require("sdk/event/core");
const {ActorClassWithSpec, Actor, FrontClassWithSpec, Front, generateActorSpec} =
require("devtools/shared/protocol");
const {NodeActor} = require("devtools/server/actors/inspector");
var eventsSpec = generateActorSpec({
typeName: "eventsFormActor",
methods: {
attach: {
request: {},
response: {}
},
detach: {
request: {},
response: {}
}
}
});
var EventsFormActor = ActorClassWithSpec(eventsSpec, {
initialize: function () {
Actor.prototype.initialize.apply(this, arguments);
},
attach: function () {
Events.on(NodeActor, "form", this.onNodeActorForm);
},
detach: function () {
Events.off(NodeActor, "form", this.onNodeActorForm);
},
onNodeActorForm: function (event) {
let nodeActor = event.target;
if (nodeActor.rawNode.id == "container") {
let form = event.data;
form.setFormProperty("test-property", "test-value");
}
}
});
var EventsFormFront = FrontClassWithSpec(eventsSpec, {
initialize: function (client, form) {
Front.prototype.initialize.apply(this, arguments);
this.actorID = form[EventsFormActor.prototype.typeName];
this.manage(this);
}
});
exports.EventsFormFront = EventsFormFront;

View file

@ -0,0 +1,155 @@
[DEFAULT]
tags = devtools
subsuite = devtools
support-files =
actor_events_form.js
doc_markup_anonymous.html
doc_markup_dragdrop.html
doc_markup_dragdrop_autoscroll_01.html
doc_markup_dragdrop_autoscroll_02.html
doc_markup_edit.html
doc_markup_events1.html
doc_markup_events2.html
doc_markup_events3.html
doc_markup_events_form.html
doc_markup_events_jquery.html
doc_markup_events-overflow.html
doc_markup_flashing.html
doc_markup_html_mixed_case.html
doc_markup_image_and_canvas.html
doc_markup_image_and_canvas_2.html
doc_markup_links.html
doc_markup_mutation.html
doc_markup_navigation.html
doc_markup_not_displayed.html
doc_markup_pagesize_01.html
doc_markup_pagesize_02.html
doc_markup_search.html
doc_markup_svg_attributes.html
doc_markup_toggle.html
doc_markup_tooltip.png
doc_markup_void_elements.html
doc_markup_void_elements.xhtml
doc_markup_whitespace.html
doc_markup_xul.xul
head.js
helper_attributes_test_runner.js
helper_events_test_runner.js
helper_markup_accessibility_navigation.js
helper_outerhtml_test_runner.js
helper_style_attr_test_runner.js
lib_jquery_1.0.js
lib_jquery_1.1.js
lib_jquery_1.2_min.js
lib_jquery_1.3_min.js
lib_jquery_1.4_min.js
lib_jquery_1.6_min.js
lib_jquery_1.7_min.js
lib_jquery_1.11.1_min.js
lib_jquery_2.1.1_min.js
!/devtools/client/commandline/test/helpers.js
!/devtools/client/framework/test/shared-head.js
!/devtools/client/inspector/test/head.js
!/devtools/client/inspector/test/shared-head.js
!/devtools/client/shared/test/test-actor.js
!/devtools/client/shared/test/test-actor-registry.js
[browser_markup_accessibility_focus_blur.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_markup_accessibility_navigation.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_markup_accessibility_navigation_after_edit.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_markup_accessibility_semantics.js]
[browser_markup_anonymous_01.js]
[browser_markup_anonymous_02.js]
skip-if = e10s # scratchpad.xul is not loading in e10s window
[browser_markup_anonymous_03.js]
[browser_markup_anonymous_04.js]
[browser_markup_copy_image_data.js]
subsuite = clipboard
[browser_markup_css_completion_style_attribute_01.js]
[browser_markup_css_completion_style_attribute_02.js]
[browser_markup_css_completion_style_attribute_03.js]
[browser_markup_dragdrop_autoscroll_01.js]
[browser_markup_dragdrop_autoscroll_02.js]
[browser_markup_dragdrop_distance.js]
[browser_markup_dragdrop_draggable.js]
[browser_markup_dragdrop_dragRootNode.js]
[browser_markup_dragdrop_escapeKeyPress.js]
[browser_markup_dragdrop_invalidNodes.js]
[browser_markup_dragdrop_reorder.js]
[browser_markup_dragdrop_tooltip.js]
[browser_markup_events1.js]
[browser_markup_events2.js]
[browser_markup_events3.js]
[browser_markup_events_form.js]
[browser_markup_events_jquery_1.0.js]
[browser_markup_events_jquery_1.1.js]
[browser_markup_events_jquery_1.2.js]
[browser_markup_events_jquery_1.3.js]
[browser_markup_events_jquery_1.4.js]
[browser_markup_events_jquery_1.6.js]
[browser_markup_events_jquery_1.7.js]
[browser_markup_events_jquery_1.11.1.js]
[browser_markup_events_jquery_2.1.1.js]
[browser_markup_events-overflow.js]
skip-if = true # Bug 1177550
[browser_markup_events-windowed-host.js]
[browser_markup_links_01.js]
[browser_markup_links_02.js]
[browser_markup_links_03.js]
[browser_markup_links_04.js]
subsuite = clipboard
[browser_markup_links_05.js]
[browser_markup_links_06.js]
[browser_markup_links_07.js]
[browser_markup_load_01.js]
[browser_markup_html_edit_01.js]
[browser_markup_html_edit_02.js]
[browser_markup_html_edit_03.js]
[browser_markup_image_tooltip.js]
[browser_markup_image_tooltip_mutations.js]
[browser_markup_keybindings_01.js]
[browser_markup_keybindings_02.js]
[browser_markup_keybindings_03.js]
[browser_markup_keybindings_04.js]
[browser_markup_keybindings_delete_attributes.js]
[browser_markup_keybindings_scrolltonode.js]
[browser_markup_mutation_01.js]
[browser_markup_mutation_02.js]
[browser_markup_navigation.js]
[browser_markup_node_names.js]
[browser_markup_node_names_namespaced.js]
[browser_markup_node_not_displayed_01.js]
[browser_markup_node_not_displayed_02.js]
[browser_markup_pagesize_01.js]
[browser_markup_pagesize_02.js]
[browser_markup_remove_xul_attributes.js]
skip-if = e10s # Bug 1036409 - The last selected node isn't reselected
[browser_markup_search_01.js]
[browser_markup_tag_edit_01.js]
[browser_markup_tag_edit_02.js]
[browser_markup_tag_edit_03.js]
[browser_markup_tag_edit_04-backspace.js]
[browser_markup_tag_edit_04-delete.js]
[browser_markup_tag_edit_05.js]
[browser_markup_tag_edit_06.js]
[browser_markup_tag_edit_07.js]
[browser_markup_tag_edit_08.js]
[browser_markup_tag_edit_09.js]
[browser_markup_tag_edit_10.js]
[browser_markup_tag_edit_11.js]
[browser_markup_tag_edit_12.js]
[browser_markup_tag_edit_13-other.js]
[browser_markup_tag_edit_long-classname.js]
[browser_markup_textcontent_display.js]
[browser_markup_textcontent_edit_01.js]
[browser_markup_textcontent_edit_02.js]
[browser_markup_toggle_01.js]
[browser_markup_toggle_02.js]
[browser_markup_toggle_03.js]
[browser_markup_update-on-navigtion.js]
[browser_markup_void_elements_html.js]
[browser_markup_void_elements_xhtml.js]
[browser_markup_whitespace.js]

View file

@ -0,0 +1,59 @@
/* 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 inspector markup view handling focus and blur when moving between markup
// view, its root and other containers, and other parts of inspector.
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(
"data:text/html;charset=utf-8,<h1>foo</h1><span>bar</span>");
let markup = inspector.markup;
let doc = markup.doc;
let win = doc.defaultView;
let spanContainer = yield getContainerForSelector("span", inspector);
let rootContainer = markup.getContainer(markup._rootNode);
is(doc.activeElement, doc.body,
"Keyboard focus by default is on document body");
yield selectNode("span", inspector);
is(doc.activeElement, doc.body,
"Keyboard focus is still on document body");
info("Focusing on the test span node using 'Return' key");
// Focus on the tree element.
rootContainer.elt.focus();
EventUtils.synthesizeKey("VK_RETURN", {}, win);
is(doc.activeElement, spanContainer.editor.tag,
"Keyboard focus should be on tag element of focused container");
info("Focusing on search box, external to markup view document");
yield focusSearchBoxUsingShortcut(inspector.panelWin);
is(doc.activeElement, doc.body,
"Keyboard focus should be removed from focused container");
info("Selecting the test span node again");
yield selectNode("span", inspector);
is(doc.activeElement, doc.body,
"Keyboard focus should again be on document body");
info("Focusing on the test span node using 'Space' key");
// Focus on the tree element.
rootContainer.elt.focus();
EventUtils.synthesizeKey("VK_SPACE", {}, win);
is(doc.activeElement, spanContainer.editor.tag,
"Keyboard focus should again be on tag element of focused container");
yield clickOnInspectMenuItem(testActor, "h1");
is(doc.activeElement, rootContainer.elt,
"When inspect menu item is used keyboard focus should move to tree.");
});

View file

@ -0,0 +1,277 @@
/* 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/. */
/* import-globals-from helper_markup_accessibility_navigation.js */
"use strict";
// Test keyboard navigation accessibility of inspector's markup view.
loadHelperScript("helper_markup_accessibility_navigation.js");
/**
* Test data has the format of:
* {
* desc {String} description for better logging
* key {String} key event's key
* options {?Object} optional event data such as shiftKey, etc
* focused {String} path to expected focused element relative to
* its container
* activedescendant {String} path to expected aria-activedescendant element
* relative to its container
* waitFor {String} optional event to wait for if keyboard actions
* result in asynchronous updates
* }
*/
const TESTS = [
{
desc: "Collapse body container",
focused: "root.elt",
activedescendant: "body.tagLine",
key: "VK_LEFT",
options: { },
waitFor: "collapsed"
},
{
desc: "Expand body container",
focused: "root.elt",
activedescendant: "body.tagLine",
key: "VK_RIGHT",
options: { },
waitFor: "expanded"
},
{
desc: "Select header container",
focused: "root.elt",
activedescendant: "header.tagLine",
key: "VK_DOWN",
options: { },
waitFor: "inspector-updated"
},
{
desc: "Expand header container",
focused: "root.elt",
activedescendant: "header.tagLine",
key: "VK_RIGHT",
options: { },
waitFor: "expanded"
},
{
desc: "Select text container",
focused: "root.elt",
activedescendant: "container-0.tagLine",
key: "VK_DOWN",
options: { },
waitFor: "inspector-updated"
},
{
desc: "Select header container again",
focused: "root.elt",
activedescendant: "header.tagLine",
key: "VK_UP",
options: { },
waitFor: "inspector-updated"
},
{
desc: "Collapse header container",
focused: "root.elt",
activedescendant: "header.tagLine",
key: "VK_LEFT",
options: { },
waitFor: "collapsed"
},
{
desc: "Focus on header container tag",
focused: "header.focusableElms.0",
activedescendant: "header.tagLine",
key: "VK_RETURN",
options: { }
},
{
desc: "Remove focus from header container tag",
focused: "root.elt",
activedescendant: "header.tagLine",
key: "VK_ESCAPE",
options: { }
},
{
desc: "Focus on header container tag again",
focused: "header.focusableElms.0",
activedescendant: "header.tagLine",
key: "VK_SPACE",
options: { }
},
{
desc: "Focus on header id attribute",
focused: "header.focusableElms.1",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Focus on header class attribute",
focused: "header.focusableElms.2",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Focus on header new attribute",
focused: "header.focusableElms.3",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Circle back and focus on header tag again",
focused: "header.focusableElms.0",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Circle back and focus on header new attribute again",
focused: "header.focusableElms.3",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { shiftKey: true }
},
{
desc: "Tab back and focus on header class attribute",
focused: "header.focusableElms.2",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { shiftKey: true }
},
{
desc: "Tab back and focus on header id attribute",
focused: "header.focusableElms.1",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { shiftKey: true }
},
{
desc: "Tab back and focus on header tag",
focused: "header.focusableElms.0",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { shiftKey: true }
},
{
desc: "Expand header container, ensure that focus is still on header tag",
focused: "header.focusableElms.0",
activedescendant: "header.tagLine",
key: "VK_RIGHT",
options: { },
waitFor: "expanded"
},
{
desc: "Activate header tag editor",
focused: "header.editor.tag.inplaceEditor.input",
activedescendant: "header.tagLine",
key: "VK_RETURN",
options: { }
},
{
desc: "Activate header id attribute editor",
focused: "header.editor.attrList.children.0.children.1.inplaceEditor.input",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Deselect text in header id attribute editor",
focused: "header.editor.attrList.children.0.children.1.inplaceEditor.input",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Activate header class attribute editor",
focused: "header.editor.attrList.children.1.children.1.inplaceEditor.input",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Deselect text in header class attribute editor",
focused: "header.editor.attrList.children.1.children.1.inplaceEditor.input",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Activate header new attribute editor",
focused: "header.editor.newAttr.inplaceEditor.input",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Circle back and activate header tag editor again",
focused: "header.editor.tag.inplaceEditor.input",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Circle back and activate header new attribute editor again",
focused: "header.editor.newAttr.inplaceEditor.input",
activedescendant: "header.tagLine",
key: "VK_TAB",
options: { shiftKey: true }
},
{
desc: "Exit edit mode and keep focus on header new attribute",
focused: "header.focusableElms.3",
activedescendant: "header.tagLine",
key: "VK_ESCAPE",
options: { }
},
{
desc: "Move the selection to body and reset focus to container tree",
focused: "docBody",
activedescendant: "body.tagLine",
key: "VK_UP",
options: { },
waitFor: "inspector-updated"
},
];
let containerID = 0;
let elms = {};
add_task(function* () {
let { inspector } = yield openInspectorForURL(`data:text/html;charset=utf-8,
<h1 id="some-id" class="some-class">foo<span>Child span<span></h1>`);
// Record containers that are created after inspector is initialized to be
// useful in testing.
inspector.on("container-created", memorizeContainer);
registerCleanupFunction(() => {
inspector.off("container-created", memorizeContainer);
});
elms.docBody = inspector.markup.doc.body;
elms.root = inspector.markup.getContainer(inspector.markup._rootNode);
elms.header = yield getContainerForSelector("h1", inspector);
elms.body = yield getContainerForSelector("body", inspector);
// Initial focus is on root element and active descendant should be set on
// body tag line.
testNavigationState(inspector, elms, elms.docBody, elms.body.tagLine);
// Focus on the tree element.
elms.root.elt.focus();
for (let testData of TESTS) {
yield runAccessibilityNavigationTest(inspector, elms, testData);
}
elms = null;
});
// Record all containers that are created dynamically into elms object.
function memorizeContainer(event, container) {
elms[`container-${containerID++}`] = container;
}

View file

@ -0,0 +1,126 @@
/* 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/. */
/* import-globals-from helper_markup_accessibility_navigation.js */
"use strict";
// Test keyboard navigation accessibility is preserved after editing attributes.
loadHelperScript("helper_markup_accessibility_navigation.js");
const TEST_URI = '<div id="some-id" class="some-class"></div>';
/**
* Test data has the format of:
* {
* desc {String} description for better logging
* key {String} key event's key
* options {?Object} optional event data such as shiftKey, etc
* focused {String} path to expected focused element relative to
* its container
* activedescendant {String} path to expected aria-activedescendant element
* relative to its container
* waitFor {String} optional event to wait for if keyboard actions
* result in asynchronous updates
* }
*/
const TESTS = [
{
desc: "Select header container",
focused: "root.elt",
activedescendant: "div.tagLine",
key: "VK_DOWN",
options: { },
waitFor: "inspector-updated"
},
{
desc: "Focus on header tag",
focused: "div.focusableElms.0",
activedescendant: "div.tagLine",
key: "VK_RETURN",
options: { }
},
{
desc: "Activate header tag editor",
focused: "div.editor.tag.inplaceEditor.input",
activedescendant: "div.tagLine",
key: "VK_RETURN",
options: { }
},
{
desc: "Activate header id attribute editor",
focused: "div.editor.attrList.children.0.children.1.inplaceEditor.input",
activedescendant: "div.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Deselect text in header id attribute editor",
focused: "div.editor.attrList.children.0.children.1.inplaceEditor.input",
activedescendant: "div.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Move the cursor to the left",
focused: "div.editor.attrList.children.0.children.1.inplaceEditor.input",
activedescendant: "div.tagLine",
key: "VK_LEFT",
options: { }
},
{
desc: "Modify the attribute",
focused: "div.editor.attrList.children.0.children.1.inplaceEditor.input",
activedescendant: "div.tagLine",
key: "A",
options: { }
},
{
desc: "Commit the attribute change",
focused: "div.focusableElms.1",
activedescendant: "div.tagLine",
key: "VK_RETURN",
options: { },
waitFor: "inspector-updated"
},
{
desc: "Tab and focus on header class attribute",
focused: "div.focusableElms.2",
activedescendant: "div.tagLine",
key: "VK_TAB",
options: { }
},
{
desc: "Tab and focus on header new attribute node",
focused: "div.focusableElms.3",
activedescendant: "div.tagLine",
key: "VK_TAB",
options: { }
},
];
let elms = {};
add_task(function* () {
let url = `data:text/html;charset=utf-8,${TEST_URI}`;
let { inspector } = yield openInspectorForURL(url);
elms.docBody = inspector.markup.doc.body;
elms.root = inspector.markup.getContainer(inspector.markup._rootNode);
elms.div = yield getContainerForSelector("div", inspector);
elms.body = yield getContainerForSelector("body", inspector);
// Initial focus is on root element and active descendant should be set on
// body tag line.
testNavigationState(inspector, elms, elms.docBody, elms.body.tagLine);
// Focus on the tree element.
elms.root.elt.focus();
for (let testData of TESTS) {
yield runAccessibilityNavigationTest(inspector, elms, testData);
}
elms = null;
});

View file

@ -0,0 +1,100 @@
/* 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 markup view has all expected ARIA properties set and
// updated.
const TOP_CONTAINER_LEVEL = 3;
add_task(function* () {
let {inspector} = yield openInspectorForURL(`
data:text/html;charset=utf-8,
<h1>foo</h1>
<span>bar</span>
<ul>
<li></li>
</ul>`);
let markup = inspector.markup;
let doc = markup.doc;
let win = doc.defaultView;
let rootElt = markup.getContainer(markup._rootNode).elt;
let bodyContainer = yield getContainerForSelector("body", inspector);
let spanContainer = yield getContainerForSelector("span", inspector);
let headerContainer = yield getContainerForSelector("h1", inspector);
let listContainer = yield getContainerForSelector("ul", inspector);
// Focus on the tree element.
rootElt.focus();
// Test tree related semantics
is(rootElt.getAttribute("role"), "tree",
"Root container should have tree semantics");
is(rootElt.getAttribute("aria-dropeffect"), "none",
"By default root container's drop effect should be set to none");
is(rootElt.getAttribute("aria-activedescendant"),
bodyContainer.tagLine.getAttribute("id"),
"Default active descendant should be set to body");
is(bodyContainer.tagLine.getAttribute("aria-level"), TOP_CONTAINER_LEVEL - 1,
"Body container tagLine should have nested level up to date");
[spanContainer, headerContainer, listContainer].forEach(container => {
let treeitem = container.tagLine;
is(treeitem.getAttribute("role"), "treeitem",
"Child container tagLine elements should have tree item semantics");
is(treeitem.getAttribute("aria-level"), TOP_CONTAINER_LEVEL,
"Child container tagLine should have nested level up to date");
is(treeitem.getAttribute("aria-grabbed"), "false",
"Child container should be draggable but not grabbed by default");
is(container.children.getAttribute("role"), "group",
"Container with children should have its children element have group " +
"semantics");
ok(treeitem.id, "Tree item should have id assigned");
if (container.closeTagLine) {
is(container.closeTagLine.getAttribute("role"), "presentation",
"Ignore closing tag");
}
if (container.expander) {
is(container.expander.getAttribute("role"), "presentation",
"Ignore expander");
}
});
// Test expanding/expandable semantics
ok(!spanContainer.tagLine.hasAttribute("aria-expanded"),
"Non expandable tree items should not have aria-expanded attribute");
ok(!headerContainer.tagLine.hasAttribute("aria-expanded"),
"Non expandable tree items should not have aria-expanded attribute");
is(listContainer.tagLine.getAttribute("aria-expanded"), "false",
"Closed tree item should have aria-expanded unset");
info("Selecting and expanding list container");
let updated = waitForMultipleChildrenUpdates(inspector);
yield selectNode("ul", inspector);
EventUtils.synthesizeKey("VK_RIGHT", {}, win);
yield updated;
is(rootElt.getAttribute("aria-activedescendant"),
listContainer.tagLine.getAttribute("id"),
"Active descendant should not be set to list container tagLine");
is(listContainer.tagLine.getAttribute("aria-expanded"), "true",
"Open tree item should have aria-expanded set");
let listItemContainer = yield getContainerForSelector("li", inspector);
is(listItemContainer.tagLine.getAttribute("aria-level"),
TOP_CONTAINER_LEVEL + 1,
"Grand child container tagLine should have nested level up to date");
is(listItemContainer.children.getAttribute("role"), "presentation",
"Container with no children should have its children element ignored by " +
"accessibility");
info("Collapsing list container");
updated = waitForMultipleChildrenUpdates(inspector);
EventUtils.synthesizeKey("VK_LEFT", {}, win);
yield updated;
is(listContainer.tagLine.getAttribute("aria-expanded"), "false",
"Closed tree item should have aria-expanded unset");
});

View file

@ -0,0 +1,44 @@
/* 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 native anonymous content in the markupview.
const TEST_URL = URL_ROOT + "doc_markup_anonymous.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
let pseudo = yield getNodeFront("#pseudo", inspector);
// Markup looks like: <div><::before /><span /><::after /></div>
let children = yield inspector.walker.children(pseudo);
is(children.nodes.length, 3, "Children returned from walker");
info("Checking the ::before pseudo element");
let before = children.nodes[0];
yield isEditingMenuDisabled(before, inspector);
info("Checking the normal child element");
let span = children.nodes[1];
yield isEditingMenuEnabled(span, inspector);
info("Checking the ::after pseudo element");
let after = children.nodes[2];
yield isEditingMenuDisabled(after, inspector);
let native = yield getNodeFront("#native", inspector);
// Markup looks like: <div><video controls /></div>
let nativeChildren = yield inspector.walker.children(native);
is(nativeChildren.nodes.length, 1, "Children returned from walker");
info("Checking the video element");
let video = nativeChildren.nodes[0];
ok(!video.isAnonymous, "<video> is not anonymous");
let videoChildren = yield inspector.walker.children(video);
is(videoChildren.nodes.length, 0,
"No native children returned from walker for <video> by default");
});

View file

@ -0,0 +1,31 @@
/* 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";
requestLongerTimeout(2);
// Test XBL anonymous content in the markupview
const TEST_URL = "chrome://devtools/content/scratchpad/scratchpad.xul";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
let toolbarbutton = yield getNodeFront("toolbarbutton", inspector);
let children = yield inspector.walker.children(toolbarbutton);
is(toolbarbutton.numChildren, 3, "Correct number of children");
is(children.nodes.length, 3, "Children returned from walker");
is(toolbarbutton.isAnonymous, false, "Toolbarbutton is not anonymous");
yield isEditingMenuEnabled(toolbarbutton, inspector);
for (let node of children.nodes) {
ok(node.isAnonymous, "Child is anonymous");
ok(node._form.isXBLAnonymous, "Child is XBL anonymous");
ok(!node._form.isShadowAnonymous, "Child is not shadow anonymous");
ok(!node._form.isNativeAnonymous, "Child is not native anonymous");
yield isEditingMenuDisabled(node, inspector);
}
});

View file

@ -0,0 +1,34 @@
/* 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 shadow DOM content in the markupview.
// Note that many features are not yet enabled, but basic listing
// of elements should be working.
const TEST_URL = URL_ROOT + "doc_markup_anonymous.html";
add_task(function* () {
Services.prefs.setBoolPref("dom.webcomponents.enabled", true);
let {inspector} = yield openInspectorForURL(TEST_URL);
let shadow = yield getNodeFront("#shadow", inspector.markup);
let children = yield inspector.walker.children(shadow);
is(shadow.numChildren, 3, "Children of the shadow root are counted");
is(children.nodes.length, 3, "Children returned from walker");
info("Checking the ::before pseudo element");
let before = children.nodes[0];
yield isEditingMenuDisabled(before, inspector);
info("Checking the <h3> shadow element");
let shadowChild1 = children.nodes[1];
yield isEditingMenuDisabled(shadowChild1, inspector);
info("Checking the <select> shadow element");
let shadowChild2 = children.nodes[2];
yield isEditingMenuDisabled(shadowChild2, inspector);
});

View file

@ -0,0 +1,37 @@
/* 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 native anonymous content in the markupview with
// devtools.inspector.showAllAnonymousContent set to true
const TEST_URL = URL_ROOT + "doc_markup_anonymous.html";
const PREF = "devtools.inspector.showAllAnonymousContent";
add_task(function* () {
Services.prefs.setBoolPref(PREF, true);
let {inspector} = yield openInspectorForURL(TEST_URL);
let native = yield getNodeFront("#native", inspector);
// Markup looks like: <div><video controls /></div>
let nativeChildren = yield inspector.walker.children(native);
is(nativeChildren.nodes.length, 1, "Children returned from walker");
info("Checking the video element");
let video = nativeChildren.nodes[0];
ok(!video.isAnonymous, "<video> is not anonymous");
let videoChildren = yield inspector.walker.children(video);
is(videoChildren.nodes.length, 3, "<video> has native anonymous children");
for (let node of videoChildren.nodes) {
ok(node.isAnonymous, "Child is anonymous");
ok(!node._form.isXBLAnonymous, "Child is not XBL anonymous");
ok(!node._form.isShadowAnonymous, "Child is not shadow anonymous");
ok(node._form.isNativeAnonymous, "Child is native anonymous");
yield isEditingMenuDisabled(node, inspector);
}
});

View file

@ -0,0 +1,67 @@
/* 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 image nodes have the "copy data-uri" contextual menu item enabled
// and that clicking it puts the image data into the clipboard
add_task(function* () {
yield addTab(URL_ROOT + "doc_markup_image_and_canvas.html");
let {inspector, testActor} = yield openInspector();
yield selectNode("div", inspector);
yield assertCopyImageDataNotAvailable(inspector);
yield selectNode("img", inspector);
yield assertCopyImageDataAvailable(inspector);
let expectedSrc = yield testActor.getAttribute("img", "src");
yield triggerCopyImageUrlAndWaitForClipboard(expectedSrc, inspector);
yield selectNode("canvas", inspector);
yield assertCopyImageDataAvailable(inspector);
let expectedURL = yield testActor.eval(`
content.document.querySelector(".canvas").toDataURL();`);
yield triggerCopyImageUrlAndWaitForClipboard(expectedURL, inspector);
// Check again that the menu isn't available on the DIV (to make sure our
// menu updating mechanism works)
yield selectNode("div", inspector);
yield assertCopyImageDataNotAvailable(inspector);
});
function* assertCopyImageDataNotAvailable(inspector) {
let allMenuItems = openContextMenuAndGetAllItems(inspector);
let item = allMenuItems.find(i => i.id === "node-menu-copyimagedatauri");
ok(item, "The menu item was found in the contextual menu");
ok(item.disabled, "The menu item is disabled");
}
function* assertCopyImageDataAvailable(inspector) {
let allMenuItems = openContextMenuAndGetAllItems(inspector);
let item = allMenuItems.find(i => i.id === "node-menu-copyimagedatauri");
ok(item, "The menu item was found in the contextual menu");
ok(!item.disabled, "The menu item is enabled");
}
function triggerCopyImageUrlAndWaitForClipboard(expected, inspector) {
let def = defer();
SimpleTest.waitForClipboard(expected, () => {
inspector.markup.getContainer(inspector.selection.nodeFront)
.copyImageDataUri();
}, () => {
ok(true, "The clipboard contains the expected value " +
expected.substring(0, 50) + "...");
def.resolve();
}, () => {
ok(false, "The clipboard doesn't contain the expected value " +
expected.substring(0, 50) + "...");
def.resolve();
});
return def.promise;
}

View file

@ -0,0 +1,76 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_style_attr_test_runner.js */
"use strict";
// Test CSS state is correctly determined and the corresponding suggestions are
// displayed. i.e. CSS property suggestions are shown when cursor is like:
// ```style="di|"``` where | is the cursor; And CSS value suggestion is
// displayed when the cursor is like: ```style="display:n|"``` properly. No
// suggestions should ever appear when the attribute is not a style attribute.
// The correctness and cycling of the suggestions is covered in the ruleview
// tests.
loadHelperScript("helper_style_attr_test_runner.js");
const TEST_URL = URL_ROOT + "doc_markup_edit.html";
// test data format :
// [
// what key to press,
// expected input box value after keypress,
// expected input.selectionStart,
// expected input.selectionEnd,
// is popup expected to be open ?
// ]
const TEST_DATA = [
["s", "s", 1, 1, false],
["t", "st", 2, 2, false],
["y", "sty", 3, 3, false],
["l", "styl", 4, 4, false],
["e", "style", 5, 5, false],
["=", "style=", 6, 6, false],
["\"", "style=\"", 7, 7, false],
["d", "style=\"display", 8, 14, true],
["VK_TAB", "style=\"display", 14, 14, true],
["VK_TAB", "style=\"dominant-baseline", 24, 24, true],
["VK_TAB", "style=\"direction", 16, 16, true],
["click_1", "style=\"display", 14, 14, false],
[":", "style=\"display:block", 15, 20, true],
["n", "style=\"display:none", 16, 19, false],
["VK_BACK_SPACE", "style=\"display:n", 16, 16, false],
["VK_BACK_SPACE", "style=\"display:", 15, 15, false],
[" ", "style=\"display: block", 16, 21, true],
[" ", "style=\"display: block", 17, 22, true],
["i", "style=\"display: inherit", 18, 24, true],
["VK_RIGHT", "style=\"display: inherit", 24, 24, false],
[";", "style=\"display: inherit;", 25, 25, false],
[" ", "style=\"display: inherit; ", 26, 26, false],
[" ", "style=\"display: inherit; ", 27, 27, false],
["VK_LEFT", "style=\"display: inherit; ", 26, 26, false],
["c", "style=\"display: inherit; color ", 27, 31, true],
["VK_RIGHT", "style=\"display: inherit; color ", 31, 31, false],
[" ", "style=\"display: inherit; color ", 32, 32, false],
["c", "style=\"display: inherit; color c ", 33, 33, false],
["VK_BACK_SPACE", "style=\"display: inherit; color ", 32, 32, false],
[":", "style=\"display: inherit; color :aliceblue ", 33, 42, true],
["c", "style=\"display: inherit; color :cadetblue ", 34, 42, true],
["VK_DOWN", "style=\"display: inherit; color :chartreuse ", 34, 43, true],
["VK_RIGHT", "style=\"display: inherit; color :chartreuse ", 43, 43, false],
[" ", "style=\"display: inherit; color :chartreuse aliceblue ",
44, 53, true],
["!", "style=\"display: inherit; color :chartreuse !important; ",
45, 55, false],
["VK_RIGHT", "style=\"display: inherit; color :chartreuse !important; ",
55, 55, false],
["VK_RETURN", "style=\"display: inherit; color :chartreuse !important;\"",
-1, -1, false]
];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
yield runStyleAttributeAutocompleteTests(inspector, TEST_DATA);
});

View file

@ -0,0 +1,106 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_style_attr_test_runner.js */
"use strict";
// Test CSS autocompletion of the style attributes stops after closing the
// attribute using a matching quote.
loadHelperScript("helper_style_attr_test_runner.js");
const TEST_URL = URL_ROOT + "doc_markup_edit.html";
// test data format :
// [
// what key to press,
// expected input box value after keypress,
// expected input.selectionStart,
// expected input.selectionEnd,
// is popup expected to be open ?
// ]
const TEST_DATA_DOUBLE = [
["s", "s", 1, 1, false],
["t", "st", 2, 2, false],
["y", "sty", 3, 3, false],
["l", "styl", 4, 4, false],
["e", "style", 5, 5, false],
["=", "style=", 6, 6, false],
["\"", "style=\"", 7, 7, false],
["c", "style=\"color", 8, 12, true],
["VK_RIGHT", "style=\"color", 12, 12, false],
[":", "style=\"color:aliceblue", 13, 22, true],
["b", "style=\"color:beige", 14, 18, true],
["VK_RIGHT", "style=\"color:beige", 18, 18, false],
["\"", "style=\"color:beige\"", 19, 19, false],
[" ", "style=\"color:beige\" ", 20, 20, false],
["d", "style=\"color:beige\" d", 21, 21, false],
["a", "style=\"color:beige\" da", 22, 22, false],
["t", "style=\"color:beige\" dat", 23, 23, false],
["a", "style=\"color:beige\" data", 24, 24, false],
["VK_RETURN", "style=\"color:beige\"",
-1, -1, false]
];
// Check that single quote attribute is also supported
const TEST_DATA_SINGLE = [
["s", "s", 1, 1, false],
["t", "st", 2, 2, false],
["y", "sty", 3, 3, false],
["l", "styl", 4, 4, false],
["e", "style", 5, 5, false],
["=", "style=", 6, 6, false],
["'", "style='", 7, 7, false],
["c", "style='color", 8, 12, true],
["VK_RIGHT", "style='color", 12, 12, false],
[":", "style='color:aliceblue", 13, 22, true],
["b", "style='color:beige", 14, 18, true],
["VK_RIGHT", "style='color:beige", 18, 18, false],
["'", "style='color:beige'", 19, 19, false],
[" ", "style='color:beige' ", 20, 20, false],
["d", "style='color:beige' d", 21, 21, false],
["a", "style='color:beige' da", 22, 22, false],
["t", "style='color:beige' dat", 23, 23, false],
["a", "style='color:beige' data", 24, 24, false],
["VK_RETURN", "style=\"color:beige\"",
-1, -1, false]
];
// Check that autocompletion is still enabled after using url('1)
const TEST_DATA_INNER = [
["s", "s", 1, 1, false],
["t", "st", 2, 2, false],
["y", "sty", 3, 3, false],
["l", "styl", 4, 4, false],
["e", "style", 5, 5, false],
["=", "style=", 6, 6, false],
["\"", "style=\"", 7, 7, false],
["b", "style=\"border", 8, 13, true],
["a", "style=\"background", 9, 17, true],
["VK_RIGHT", "style=\"background", 17, 17, false],
[":", "style=\"background:aliceblue", 18, 27, true],
["u", "style=\"background:unset", 19, 23, true],
["r", "style=\"background:url", 20, 21, false],
["l", "style=\"background:url", 21, 21, false],
["(", "style=\"background:url(", 22, 22, false],
["'", "style=\"background:url('", 23, 23, false],
["1", "style=\"background:url('1", 24, 24, false],
["'", "style=\"background:url('1'", 25, 25, false],
[")", "style=\"background:url('1')", 26, 26, false],
[";", "style=\"background:url('1');", 27, 27, false],
[" ", "style=\"background:url('1'); ", 28, 28, false],
["c", "style=\"background:url('1'); color", 29, 33, true],
["VK_RIGHT", "style=\"background:url('1'); color", 33, 33, false],
[":", "style=\"background:url('1'); color:aliceblue", 34, 43, true],
["b", "style=\"background:url('1'); color:beige", 35, 39, true],
["VK_RETURN", "style=\"background:url('1'); color:beige\"", -1, -1, false]
];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
yield runStyleAttributeAutocompleteTests(inspector, TEST_DATA_DOUBLE);
yield runStyleAttributeAutocompleteTests(inspector, TEST_DATA_SINGLE);
yield runStyleAttributeAutocompleteTests(inspector, TEST_DATA_INNER);
});

View file

@ -0,0 +1,54 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_style_attr_test_runner.js */
"use strict";
// Test CSS autocompletion of the style attribute can be triggered when the
// caret is before a non-word character.
loadHelperScript("helper_style_attr_test_runner.js");
const TEST_URL = URL_ROOT + "doc_markup_edit.html";
// test data format :
// [
// what key to press,
// expected input box value after keypress,
// expected input.selectionStart,
// expected input.selectionEnd,
// is popup expected to be open ?
// ]
const TEST_DATA = [
["s", "s", 1, 1, false],
["t", "st", 2, 2, false],
["y", "sty", 3, 3, false],
["l", "styl", 4, 4, false],
["e", "style", 5, 5, false],
["=", "style=", 6, 6, false],
["\"", "style=\"", 7, 7, false],
["\"", "style=\"\"", 8, 8, false],
["VK_LEFT", "style=\"\"", 7, 7, false],
["c", "style=\"color\"", 8, 12, true],
["o", "style=\"color\"", 9, 12, true],
["VK_RIGHT", "style=\"color\"", 12, 12, false],
[":", "style=\"color:aliceblue\"", 13, 22, true],
["b", "style=\"color:beige\"", 14, 18, true],
["VK_RIGHT", "style=\"color:beige\"", 18, 18, false],
[";", "style=\"color:beige;\"", 19, 19, false],
[";", "style=\"color:beige;;\"", 20, 20, false],
["VK_LEFT", "style=\"color:beige;;\"", 19, 19, false],
["p", "style=\"color:beige;padding;\"", 20, 26, true],
["VK_RIGHT", "style=\"color:beige;padding;\"", 26, 26, false],
[":", "style=\"color:beige;padding:calc;\"", 27, 31, true],
["0", "style=\"color:beige;padding:0;\"", 28, 28, false],
["VK_RETURN", "style=\"color:beige;padding:0;\"",
-1, -1, false]
];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
yield runStyleAttributeAutocompleteTests(inspector, TEST_DATA);
});

View file

@ -0,0 +1,51 @@
/* 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 dragging a node near the top or bottom edge of the markup-view
// auto-scrolls the view on a large toolbox.
const TEST_URL = URL_ROOT + "doc_markup_dragdrop_autoscroll_01.html";
add_task(function* () {
// Set the toolbox as large as it would get. The toolbox automatically shrinks
// to not overflow to window.
yield pushPref("devtools.toolbox.footer.height", 10000);
let {inspector} = yield openInspectorForURL(TEST_URL);
let markup = inspector.markup;
let viewHeight = markup.doc.documentElement.clientHeight;
info("Pretend the markup-view is dragging");
markup.isDragging = true;
info("Simulate a mousemove on the view, at the bottom, and expect scrolling");
let onScrolled = waitForScrollStop(markup.doc);
markup._onMouseMove({
preventDefault: () => {},
target: markup.doc.body,
pageY: viewHeight + markup.doc.defaultView.scrollY
});
let bottomScrollPos = yield onScrolled;
ok(bottomScrollPos > 0, "The view was scrolled down");
info("Simulate a mousemove at the top and expect more scrolling");
onScrolled = waitForScrollStop(markup.doc);
markup._onMouseMove({
preventDefault: () => {},
target: markup.doc.body,
pageY: markup.doc.defaultView.scrollY
});
let topScrollPos = yield onScrolled;
ok(topScrollPos < bottomScrollPos, "The view was scrolled up");
is(topScrollPos, 0, "The view was scrolled up to the top");
info("Simulate a mouseup to stop dragging");
markup._onMouseUp();
});

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 dragging a node near the top or bottom edge of the markup-view
// auto-scrolls the view on a small toolbox.
const TEST_URL = URL_ROOT + "doc_markup_dragdrop_autoscroll_02.html";
add_task(function* () {
// Set the toolbox to very small in size.
yield pushPref("devtools.toolbox.footer.height", 150);
let {inspector} = yield openInspectorForURL(TEST_URL);
let markup = inspector.markup;
let viewHeight = markup.doc.documentElement.clientHeight;
info("Pretend the markup-view is dragging");
markup.isDragging = true;
info("Simulate a mousemove on the view, at the bottom, and expect scrolling");
let onScrolled = waitForScrollStop(markup.doc);
markup._onMouseMove({
preventDefault: () => {},
target: markup.doc.body,
pageY: viewHeight + markup.doc.defaultView.scrollY
});
let bottomScrollPos = yield onScrolled;
ok(bottomScrollPos > 0, "The view was scrolled down");
info("Simulate a mousemove at the top and expect more scrolling");
onScrolled = waitForScrollStop(markup.doc);
markup._onMouseMove({
preventDefault: () => {},
target: markup.doc.body,
pageY: markup.doc.defaultView.scrollY
});
let topScrollPos = yield onScrolled;
ok(topScrollPos < bottomScrollPos, "The view was scrolled up");
is(topScrollPos, 0, "The view was scrolled up to the top");
info("Simulate a mouseup to stop dragging");
markup._onMouseUp();
});

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 nodes don't start dragging before the mouse has moved by at least
// the minimum vertical distance defined in markup-view.js by
// DRAG_DROP_MIN_INITIAL_DISTANCE.
const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html";
const TEST_NODE = "#test";
// Keep this in sync with DRAG_DROP_MIN_INITIAL_DISTANCE in markup-view.js
const MIN_DISTANCE = 10;
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Drag the test node by half of the minimum distance");
yield simulateNodeDrag(inspector, TEST_NODE, 0, MIN_DISTANCE / 2);
yield checkIsDragging(inspector, TEST_NODE, false);
info("Drag the test node by exactly the minimum distance");
yield simulateNodeDrag(inspector, TEST_NODE, 0, MIN_DISTANCE);
yield checkIsDragging(inspector, TEST_NODE, true);
inspector.markup.cancelDragging();
info("Drag the test node by more than the minimum distance");
yield simulateNodeDrag(inspector, TEST_NODE, 0, MIN_DISTANCE * 2);
yield checkIsDragging(inspector, TEST_NODE, true);
inspector.markup.cancelDragging();
info("Drag the test node by minus the minimum distance");
yield simulateNodeDrag(inspector, TEST_NODE, 0, MIN_DISTANCE * -1);
yield checkIsDragging(inspector, TEST_NODE, true);
inspector.markup.cancelDragging();
});
function* checkIsDragging(inspector, selector, isDragging) {
let container = yield getContainerForSelector(selector, inspector);
if (isDragging) {
ok(container.isDragging, "The container is being dragged");
ok(inspector.markup.isDragging, "And the markup-view knows it");
} else {
ok(!container.isDragging, "The container hasn't been marked as dragging");
ok(!inspector.markup.isDragging, "And the markup-view either");
}
}

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 root node isn't draggable (as well as head and body).
const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html";
const TEST_DATA = ["html", "head", "body"];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
for (let selector of TEST_DATA) {
info("Try to drag/drop node " + selector);
yield simulateNodeDrag(inspector, selector);
let container = yield getContainerForSelector(selector, inspector);
ok(!container.isDragging, "The container hasn't been marked as dragging");
}
});

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 which nodes are consider draggable by the markup-view.
const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html";
// Test cases should be objects with the following properties:
// - node {String|Function} A CSS selector that uniquely identifies the node to
// be tested. Or a generator function called in a Task that should return the
// corresponding MarkupContainer object to be tested.
// - draggable {Boolean} Whether or not the node should be draggable.
const TEST_DATA = [
{ node: "head", draggable: false },
{ node: "body", draggable: false },
{ node: "html", draggable: false },
{ node: "style", draggable: true },
{ node: "a", draggable: true },
{ node: "p", draggable: true },
{ node: "input", draggable: true },
{ node: "div", draggable: true },
{
node: function* (inspector) {
let parentFront = yield getNodeFront("#before", inspector);
let {nodes} = yield inspector.walker.children(parentFront);
// Getting the comment node.
return getContainerForNodeFront(nodes[1], inspector);
},
draggable: true
},
{
node: function* (inspector) {
let parentFront = yield getNodeFront("#test", inspector);
let {nodes} = yield inspector.walker.children(parentFront);
// Getting the ::before pseudo element.
return getContainerForNodeFront(nodes[0], inspector);
},
draggable: false
}
];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
yield inspector.markup.expandAll();
for (let {node, draggable} of TEST_DATA) {
let container;
let name;
if (typeof node === "string") {
container = yield getContainerForSelector(node, inspector);
name = node;
} else {
container = yield node(inspector);
name = container.toString();
}
let status = draggable ? "draggable" : "not draggable";
info(`Testing ${name}, expecting it to be ${status}`);
is(container.isDraggable(), draggable, `The node is ${status}`);
}
});

View file

@ -0,0 +1,34 @@
/* 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 whether ESCAPE keypress cancels dragging of an element.
const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
let {markup} = inspector;
info("Get a test container");
yield selectNode("#test", inspector);
let container = yield getContainerForSelector("#test", inspector);
info("Simulate a drag/drop on this container");
yield simulateNodeDrag(inspector, "#test");
ok(container.isDragging && markup.isDragging,
"The container is being dragged");
ok(markup.doc.body.classList.contains("dragging"),
"The dragging css class was added");
info("Simulate ESCAPE keypress");
EventUtils.sendKey("escape", inspector.panelWin);
ok(!container.isDragging && !markup.isDragging,
"The dragging has stopped");
ok(!markup.doc.body.classList.contains("dragging"),
"The dragging css class was removed");
});

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";
// Check that pseudo-elements and anonymous nodes are not draggable.
const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html";
const PREF = "devtools.inspector.showAllAnonymousContent";
add_task(function* () {
Services.prefs.setBoolPref(PREF, true);
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Expanding nodes below #test");
let parentFront = yield getNodeFront("#test", inspector);
yield inspector.markup.expandNode(parentFront);
yield waitForMultipleChildrenUpdates(inspector);
info("Getting the ::before pseudo element and selecting it");
let parentContainer = yield getContainerForNodeFront(parentFront, inspector);
let beforePseudo = parentContainer.elt.children[1].firstChild.container;
parentContainer.elt.scrollIntoView(true);
yield selectNode(beforePseudo.node, inspector);
info("Simulate dragging the ::before pseudo element");
yield simulateNodeDrag(inspector, beforePseudo);
ok(!beforePseudo.isDragging, "::before pseudo element isn't dragging");
info("Expanding nodes below #anonymousParent");
let inputFront = yield getNodeFront("#anonymousParent", inspector);
yield inspector.markup.expandNode(inputFront);
yield waitForMultipleChildrenUpdates(inspector);
info("Getting the anonymous node and selecting it");
let inputContainer = yield getContainerForNodeFront(inputFront, inspector);
let anonymousDiv = inputContainer.elt.children[1].firstChild.container;
inputContainer.elt.scrollIntoView(true);
yield selectNode(anonymousDiv.node, inspector);
info("Simulate dragging the anonymous node");
yield simulateNodeDrag(inspector, anonymousDiv);
ok(!anonymousDiv.isDragging, "anonymous node isn't dragging");
});

View file

@ -0,0 +1,109 @@
/* 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";
requestLongerTimeout(2);
// Test different kinds of drag and drop node re-ordering.
const TEST_URL = URL_ROOT + "doc_markup_dragdrop.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
let ids;
info("Expand #test node");
let parentFront = yield getNodeFront("#test", inspector);
yield inspector.markup.expandNode(parentFront);
yield waitForMultipleChildrenUpdates(inspector);
info("Scroll #test into view");
let parentContainer = yield getContainerForNodeFront(parentFront, inspector);
parentContainer.elt.scrollIntoView(true);
info("Test putting an element back at its original place");
yield dragElementToOriginalLocation("#firstChild", inspector);
ids = yield getChildrenIDsOf(parentFront, inspector);
is(ids[0], "firstChild",
"#firstChild is still the first child of #test");
is(ids[1], "middleChild",
"#middleChild is still the second child of #test");
info("Testing switching elements inside their parent");
yield moveElementDown("#firstChild", "#middleChild", inspector);
ids = yield getChildrenIDsOf(parentFront, inspector);
is(ids[0], "middleChild",
"#firstChild is now the second child of #test");
is(ids[1], "firstChild",
"#middleChild is now the first child of #test");
info("Testing switching elements with a last child");
yield moveElementDown("#firstChild", "#lastChild", inspector);
ids = yield getChildrenIDsOf(parentFront, inspector);
is(ids[1], "lastChild",
"#lastChild is now the second child of #test");
is(ids[2], "firstChild",
"#firstChild is now the last child of #test");
info("Testing appending element to a parent");
yield moveElementDown("#before", "#test", inspector);
ids = yield getChildrenIDsOf(parentFront, inspector);
is(ids.length, 4,
"New element appended to #test");
is(ids[0], "before",
"New element is appended at the right place (currently first child)");
info("Testing moving element to after it's parent");
yield moveElementDown("#firstChild", "#test", inspector);
ids = yield getChildrenIDsOf(parentFront, inspector);
is(ids.length, 3,
"#firstChild is no longer #test's child");
let siblingFront = yield inspector.walker.nextSibling(parentFront);
is(siblingFront.id, "firstChild",
"#firstChild is now #test's nextElementSibling");
});
function* dragElementToOriginalLocation(selector, inspector) {
info("Picking up and putting back down " + selector);
function onMutation() {
ok(false, "Mutation received from dragging a node back to its location");
}
inspector.on("markupmutation", onMutation);
yield simulateNodeDragAndDrop(inspector, selector, 0, 0);
// Wait a bit to make sure the event never fires.
// This doesn't need to catch *all* cases, since the mutation
// will cause failure later in the test when it checks element ordering.
yield wait(500);
inspector.off("markupmutation", onMutation);
}
function* moveElementDown(selector, next, inspector) {
info("Switching " + selector + " with " + next);
let container = yield getContainerForSelector(next, inspector);
let height = container.tagLine.getBoundingClientRect().height;
let onMutated = inspector.once("markupmutation");
let uiUpdate = inspector.once("inspector-updated");
yield simulateNodeDragAndDrop(inspector, selector, 0, Math.round(height) + 2);
let mutations = yield onMutated;
yield uiUpdate;
is(mutations.length, 2, "2 mutations were received");
}
function* getChildrenIDsOf(parentFront, {walker}) {
let {nodes} = yield walker.children(parentFront);
// Filter out non-element nodes since children also returns pseudo-elements.
return nodes.filter(node => {
return !node.isPseudoElement;
}).map(node => {
return node.id;
});
}

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 tooltips don't appear when dragging over tooltip targets.
const TEST_URL = "data:text/html;charset=utf8,<img src=\"about:logo\" /><div>";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
let {markup} = inspector;
info("Get the tooltip target element for the image's src attribute");
let img = yield getContainerForSelector("img", inspector);
let target = img.editor.getAttributeElement("src").querySelector(".link");
info("Check that the src attribute of the image is a valid tooltip target");
let isValid = yield isHoverTooltipTarget(markup.imagePreviewTooltip, target);
ok(isValid, "The element is a valid tooltip target");
info("Start dragging the test div");
yield simulateNodeDrag(inspector, "div");
info("Now check that the src attribute of the image isn't a valid target");
isValid = yield isHoverTooltipTarget(markup.imagePreviewTooltip, target);
ok(!isValid, "The element is not a valid tooltip target");
info("Stop dragging the test div");
yield simulateNodeDrop(inspector, "div");
info("Check again the src attribute of the image");
isValid = yield isHoverTooltipTarget(markup.imagePreviewTooltip, target);
ok(isValid, "The element is a valid tooltip target");
});

View file

@ -0,0 +1,91 @@
/* 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_URL = URL_ROOT + "doc_markup_events-overflow.html";
const TEST_DATA = [
{
desc: "editor overflows container",
// scroll to bottom
initialScrollTop: -1,
// last header
headerToClick: 49,
alignBottom: true,
alignTop: false,
},
{
desc: "header overflows the container",
initialScrollTop: 2,
headerToClick: 0,
alignBottom: false,
alignTop: true,
},
{
desc: "neither header nor editor overflows the container",
initialScrollTop: 2,
headerToClick: 5,
alignBottom: false,
alignTop: false,
},
];
add_task(function* () {
let { inspector } = yield openInspectorForURL(TEST_URL);
let markupContainer = yield getContainerForSelector("#events", inspector);
let evHolder = markupContainer.elt.querySelector(".markupview-events");
let tooltip = inspector.markup.eventDetailsTooltip;
info("Clicking to open event tooltip.");
EventUtils.synthesizeMouseAtCenter(evHolder, {},
inspector.markup.doc.defaultView);
yield tooltip.once("shown");
info("EventTooltip visible.");
let container = tooltip.panel;
let containerRect = container.getBoundingClientRect();
let headers = container.querySelectorAll(".event-header");
for (let data of TEST_DATA) {
info("Testing scrolling when " + data.desc);
if (data.initialScrollTop < 0) {
info("Scrolling container to the bottom.");
let newScrollTop = container.scrollHeight - container.clientHeight;
data.initialScrollTop = container.scrollTop = newScrollTop;
} else {
info("Scrolling container by " + data.initialScrollTop + "px");
container.scrollTop = data.initialScrollTop;
}
is(container.scrollTop, data.initialScrollTop, "Container scrolled.");
info("Clicking on header #" + data.headerToClick);
let header = headers[data.headerToClick];
let ready = tooltip.once("event-tooltip-ready");
EventUtils.synthesizeMouseAtCenter(header, {}, header.ownerGlobal);
yield ready;
info("Event handler expanded.");
// Wait for any scrolling to finish.
yield promiseNextTick();
if (data.alignTop) {
let headerRect = header.getBoundingClientRect();
is(Math.round(headerRect.top), Math.round(containerRect.top),
"Clicked header is aligned with the container top.");
} else if (data.alignBottom) {
let editorRect = header.nextElementSibling.getBoundingClientRect();
is(Math.round(editorRect.bottom), Math.round(containerRect.bottom),
"Clicked event handler code is aligned with the container bottom.");
} else {
is(container.scrollTop, data.initialScrollTop,
"Container did not scroll, as expected.");
}
}
});

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";
/*
* Test that the event details tooltip can be hidden by clicking outside of the tooltip
* after switching hosts.
*/
const TEST_URL = URL_ROOT + "doc_markup_events-overflow.html";
registerCleanupFunction(() => {
// Restore the default Toolbox host position after the test.
Services.prefs.clearUserPref("devtools.toolbox.host");
});
add_task(function* () {
let { inspector, toolbox } = yield openInspectorForURL(TEST_URL);
yield runTests(inspector);
yield toolbox.switchHost("window");
yield runTests(inspector);
yield toolbox.switchHost("bottom");
yield runTests(inspector);
yield toolbox.destroy();
});
function* runTests(inspector) {
let markupContainer = yield getContainerForSelector("#events", inspector);
let evHolder = markupContainer.elt.querySelector(".markupview-events");
let tooltip = inspector.markup.eventDetailsTooltip;
info("Clicking to open event tooltip.");
let onInspectorUpdated = inspector.once("inspector-updated");
let onTooltipShown = tooltip.once("shown");
EventUtils.synthesizeMouseAtCenter(evHolder, {}, inspector.markup.doc.defaultView);
yield onTooltipShown;
// New node is selected when clicking on the events bubble, wait for inspector-updated.
yield onInspectorUpdated;
ok(tooltip.isVisible(), "EventTooltip visible.");
onInspectorUpdated = inspector.once("inspector-updated");
let onTooltipHidden = tooltip.once("hidden");
info("Click on another tag to hide the event tooltip");
let h1 = yield getContainerForSelector("h1", inspector);
let tag = h1.elt.querySelector(".tag");
EventUtils.synthesizeMouseAtCenter(tag, {}, inspector.markup.doc.defaultView);
yield onTooltipHidden;
// New node is selected, wait for inspector-updated.
yield onInspectorUpdated;
ok(!tooltip.isVisible(), "EventTooltip hidden.");
}

View file

@ -0,0 +1,149 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
// Test that markup view event bubbles show the correct event info for DOM
// events.
const TEST_URL = URL_ROOT + "doc_markup_events1.html";
loadHelperScript("helper_events_test_runner.js");
const TEST_DATA = [ // eslint-disable-line
{
selector: "html",
expected: [
{
type: "load",
filename: TEST_URL,
attributes: [
"Bubbling",
"DOM0"
],
handler: "init();"
}
]
},
{
selector: "#container",
expected: [
{
type: "mouseover",
filename: TEST_URL + ":45",
attributes: [
"Capturing",
"DOM2"
],
handler: "function mouseoverHandler(event) {\n" +
" if (event.target.id !== \"container\") {\n" +
" let output = document.getElementById(\"output\");\n" +
" output.textContent = event.target.textContent;\n" +
" }\n" +
"}"
}
]
},
{
selector: "#multiple",
expected: [
{
type: "click",
filename: TEST_URL + ":52",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function clickHandler(event) {\n" +
" let output = document.getElementById(\"output\");\n" +
" output.textContent = \"click\";\n" +
"}"
},
{
type: "mouseup",
filename: TEST_URL + ":57",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function mouseupHandler(event) {\n" +
" let output = document.getElementById(\"output\");\n" +
" output.textContent = \"mouseup\";\n" +
"}"
}
]
},
// #noevents tests check that dynamically added events are properly displayed
// in the markupview
{
selector: "#noevents",
expected: []
},
{
selector: "#noevents",
beforeTest: function* (inspector, testActor) {
let nodeMutated = inspector.once("markupmutation");
yield testActor.eval("window.wrappedJSObject.addNoeventsClickHandler();");
yield nodeMutated;
},
expected: [
{
type: "click",
filename: TEST_URL + ":72",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function noeventsClickHandler(event) {\n" +
" alert(\"noevents has an event listener\");\n" +
"}"
}
]
},
{
selector: "#noevents",
beforeTest: function* (inspector, testActor) {
let nodeMutated = inspector.once("markupmutation");
yield testActor.eval(
"window.wrappedJSObject.removeNoeventsClickHandler();");
yield nodeMutated;
},
expected: []
},
{
selector: "#DOM0",
expected: [
{
type: "click",
filename: TEST_URL,
attributes: [
"Bubbling",
"DOM0"
],
handler: "alert('DOM0')"
}
]
},
{
selector: "#handleevent",
expected: [
{
type: "click",
filename: TEST_URL + ":67",
attributes: [
"Bubbling",
"DOM2"
],
handler: "handleEvent: function(blah) {\n" +
" alert(\"handleEvent\");\n" +
"}"
}
]
}
];
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

View file

@ -0,0 +1,163 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
// Test that markup view event bubbles show the correct event info for DOM
// events.
const TEST_URL = URL_ROOT + "doc_markup_events2.html";
loadHelperScript("helper_events_test_runner.js");
const TEST_DATA = [ // eslint-disable-line
{
selector: "#fatarrow",
expected: [
{
type: "click",
filename: TEST_URL + ":39",
attributes: [
"Bubbling",
"DOM2"
],
handler: "() => {\n" +
" alert(\"Fat arrow without params!\");\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":43",
attributes: [
"Bubbling",
"DOM2"
],
handler: "event => {\n" +
" alert(\"Fat arrow with 1 param!\");\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":47",
attributes: [
"Bubbling",
"DOM2"
],
handler: "(event, foo, bar) => {\n" +
" alert(\"Fat arrow with 3 params!\");\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":51",
attributes: [
"Bubbling",
"DOM2"
],
handler: "b => b"
}
]
},
{
selector: "#bound",
expected: [
{
type: "click",
filename: TEST_URL + ":62",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function boundClickHandler(event) {\n" +
" alert(\"Bound event\");\n" +
"}"
}
]
},
{
selector: "#boundhe",
expected: [
{
type: "click",
filename: TEST_URL + ":85",
attributes: [
"Bubbling",
"DOM2"
],
handler: "handleEvent: function() {\n" +
" alert(\"boundHandleEvent\");\n" +
"}"
}
]
},
{
selector: "#comment-inline",
expected: [
{
type: "click",
filename: TEST_URL + ":91",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function functionProceededByInlineComment() {\n" +
" alert(\"comment-inline\");\n" +
"}"
}
]
},
{
selector: "#comment-streaming",
expected: [
{
type: "click",
filename: TEST_URL + ":96",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function functionProceededByStreamingComment() {\n" +
" alert(\"comment-streaming\");\n" +
"}"
}
]
},
{
selector: "#anon-object-method",
expected: [
{
type: "click",
filename: TEST_URL + ":71",
attributes: [
"Bubbling",
"DOM2"
],
handler: "anonObjectMethod: function() {\n" +
" alert(\"obj.anonObjectMethod\");\n" +
"}"
}
]
},
{
selector: "#object-method",
expected: [
{
type: "click",
filename: TEST_URL + ":75",
attributes: [
"Bubbling",
"DOM2"
],
handler: "objectMethod: function kay() {\n" +
" alert(\"obj.objectMethod\");\n" +
"}"
}
]
}
];
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

View file

@ -0,0 +1,161 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
// Test that markup view event bubbles show the correct event info for DOM
// events.
const TEST_URL = URL_ROOT + "doc_markup_events3.html";
loadHelperScript("helper_events_test_runner.js");
const TEST_DATA = [ // eslint-disable-line
{
selector: "#es6-method",
expected: [
{
type: "click",
filename: TEST_URL + ":91",
attributes: [
"Bubbling",
"DOM2"
],
handler: "es6Method() {\n" +
" alert(\"obj.es6Method\");\n" +
"}"
}
]
},
{
selector: "#generator",
expected: [
{
type: "click",
filename: TEST_URL + ":96",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function* generator() {\n" +
" alert(\"generator\");\n" +
"}"
}
]
},
{
selector: "#anon-generator",
expected: [
{
type: "click",
filename: TEST_URL + ":55",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function*() {\n" +
" alert(\"anonGenerator\");\n" +
"}"
}
]
},
{
selector: "#named-function-expression",
expected: [
{
type: "click",
filename: TEST_URL + ":23",
attributes: [
"Bubbling",
"DOM2"
],
handler: "let namedFunctionExpression =\n" +
" function foo() {\n" +
" alert(\"namedFunctionExpression\");\n" +
" }"
}
]
},
{
selector: "#anon-function-expression",
expected: [
{
type: "click",
filename: TEST_URL + ":27",
attributes: [
"Bubbling",
"DOM2"
],
handler: "let anonFunctionExpression = function() {\n" +
" alert(\"anonFunctionExpression\");\n" +
"}"
}
]
},
{
selector: "#returned-function",
expected: [
{
type: "click",
filename: TEST_URL + ":32",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function bar() {\n" +
" alert(\"returnedFunction\");\n" +
"}"
}
]
},
{
selector: "#constructed-function",
expected: [
{
type: "click",
filename: TEST_URL + ":1",
attributes: [
"Bubbling",
"DOM2"
],
handler: ""
}
]
},
{
selector: "#constructed-function-with-body-string",
expected: [
{
type: "click",
filename: TEST_URL + ":1",
attributes: [
"Bubbling",
"DOM2"
],
handler: "alert(\"constructedFuncWithBodyString\");"
}
]
},
{
selector: "#multiple-assignment",
expected: [
{
type: "click",
filename: TEST_URL + ":42",
attributes: [
"Bubbling",
"DOM2"
],
handler: "let multipleAssignment = foo = bar = function multi() {\n" +
" alert(\"multipleAssignment\");\n" +
"}"
}
]
},
];
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

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";
// Testing the feature whereby custom registered actors can listen to
// 'form' events sent by the NodeActor to hook custom data to it.
// The test registers one backend actor providing custom form data
// and checks that the value is properly sent to the client (NodeFront).
const TEST_PAGE_URL = URL_ROOT + "doc_markup_events_form.html";
const TEST_ACTOR_URL = CHROME_URL_ROOT + "actor_events_form.js";
var {EventsFormFront} = require(TEST_ACTOR_URL);
add_task(function* () {
info("Opening the Toolbox");
let tab = yield addTab(TEST_PAGE_URL);
let toolbox = yield openToolboxForTab(tab, "webconsole");
info("Registering test actor");
let {registrar, front} = yield registerTestActor(toolbox);
info("Selecting the Inspector panel");
let inspector = yield toolbox.selectTool("inspector");
let container = yield getContainerForSelector("#container", inspector);
isnot(container, null, "There must be requested container");
let nodeFront = container.node;
let value = nodeFront.getFormProperty("test-property");
is(value, "test-value", "There must be custom property");
info("Unregistering actor");
yield unregisterActor(registrar, front);
});
function registerTestActor(toolbox) {
let deferred = defer();
let options = {
prefix: "eventsFormActor",
actorClass: "EventsFormActor",
moduleUrl: TEST_ACTOR_URL,
};
// Register as a tab actor
let client = toolbox.target.client;
registerTabActor(client, options).then(({registrar, form}) => {
// Attach to the registered actor
let front = EventsFormFront(client, form);
front.attach().then(() => {
deferred.resolve({
front: front,
registrar: registrar,
});
});
});
return deferred.promise;
}

View file

@ -0,0 +1,237 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
// Test that markup view event bubbles show the correct event info for jQuery
// and jQuery Live events (jQuery version 1.0).
const TEST_LIB = "lib_jquery_1.0.js";
const TEST_URL = URL_ROOT + "doc_markup_events_jquery.html?" + TEST_LIB;
loadHelperScript("helper_events_test_runner.js");
/*eslint-disable */
const TEST_DATA = [
{
selector: "html",
expected: [
{
type: "load",
filename: URL_ROOT + TEST_LIB,
attributes: [
"jQuery"
],
handler: "ready: function() {\n" +
" // Make sure that the DOM is not already loaded\n" +
" if (!jQuery.isReady) {\n" +
" // Remember that the DOM is ready\n" +
" jQuery.isReady = true;\n" +
"\n" +
" // If there are functions bound, to execute\n" +
" if (jQuery.readyList) {\n" +
" // Execute all of them\n" +
" for (var i = 0; i < jQuery.readyList.length; i++)\n" +
" jQuery.readyList[i].apply(document);\n" +
"\n" +
" // Reset the list of functions\n" +
" jQuery.readyList = null;\n" +
" }\n" +
" }\n" +
"}"
},
{
type: "load",
filename: TEST_URL,
attributes: [
"Bubbling",
"DOM0"
],
handler: "() => {\n" +
" var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
" };\n" +
" var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
" };\n" +
" var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
" };\n" +
" var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
" };\n" +
" var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
" };\n" +
" var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
" };\n" +
" var handler7 = function divClick1() {\n" +
" alert(7);\n" +
" };\n" +
" var handler8 = function divClick2() {\n" +
" alert(8);\n" +
" };\n" +
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
" $(\"#livediv\").live(\"dragstart\", handler2);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").delegate) {\n" +
" $(document).delegate(\"#livediv\", \"dragleave\", handler3);\n" +
" $(document).delegate(\"#livediv\", \"dragend\", handler4);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +
" $(div).click(handler7);\n" +
" $(div).click(handler8);\n" +
" $(div).keydown(handler9);\n" +
"}"
},
{
type: "load",
filename: URL_ROOT + TEST_LIB,
attributes: [
"Bubbling",
"DOM0"
],
handler: "handle: function(event) {\n" +
" if (typeof jQuery == \"undefined\") return;\n" +
"\n" +
" event = event || jQuery.event.fix(window.event);\n" +
"\n" +
" // If no correct event was found, fail\n" +
" if (!event) return;\n" +
"\n" +
" var returnValue = true;\n" +
"\n" +
" var c = this.events[event.type];\n" +
"\n" +
" for (var j in c) {\n" +
" if (c[j].apply(this, [event]) === false) {\n" +
" event.preventDefault();\n" +
" event.stopPropagation();\n" +
" returnValue = false;\n" +
" }\n" +
" }\n" +
"\n" +
" return returnValue;\n" +
"}"
}
]
},
{
selector: "#testdiv",
expected: [
{
type: "click",
filename: TEST_URL + ":34",
attributes: [
"jQuery"
],
handler: "var handler7 = function divClick1() {\n" +
" alert(7);\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":35",
attributes: [
"jQuery"
],
handler: "var handler8 = function divClick2() {\n" +
" alert(8);\n" +
"}"
},
{
type: "click",
filename: URL_ROOT + TEST_LIB + ":894",
attributes: [
"Bubbling",
"DOM2"
],
handler: "handle: function(event) {\n" +
" if (typeof jQuery == \"undefined\") return;\n" +
"\n" +
" event = event || jQuery.event.fix(window.event);\n" +
"\n" +
" // If no correct event was found, fail\n" +
" if (!event) return;\n" +
"\n" +
" var returnValue = true;\n" +
"\n" +
" var c = this.events[event.type];\n" +
"\n" +
" for (var j in c) {\n" +
" if (c[j].apply(this, [event]) === false) {\n" +
" event.preventDefault();\n" +
" event.stopPropagation();\n" +
" returnValue = false;\n" +
" }\n" +
" }\n" +
"\n" +
" return returnValue;\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: URL_ROOT + TEST_LIB + ":894",
attributes: [
"Bubbling",
"DOM2"
],
handler: "handle: function(event) {\n" +
" if (typeof jQuery == \"undefined\") return;\n" +
"\n" +
" event = event || jQuery.event.fix(window.event);\n" +
"\n" +
" // If no correct event was found, fail\n" +
" if (!event) return;\n" +
"\n" +
" var returnValue = true;\n" +
"\n" +
" var c = this.events[event.type];\n" +
"\n" +
" for (var j in c) {\n" +
" if (c[j].apply(this, [event]) === false) {\n" +
" event.preventDefault();\n" +
" event.stopPropagation();\n" +
" returnValue = false;\n" +
" }\n" +
" }\n" +
"\n" +
" return returnValue;\n" +
"}"
}
]
},
];
/*eslint-enable */
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

View file

@ -0,0 +1,271 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
// Test that markup view event bubbles show the correct event info for jQuery
// and jQuery Live events (jQuery version 1.1).
const TEST_LIB = "lib_jquery_1.1.js";
const TEST_URL = URL_ROOT + "doc_markup_events_jquery.html?" + TEST_LIB;
loadHelperScript("helper_events_test_runner.js");
/*eslint-disable */
const TEST_DATA = [
{
selector: "html",
expected: [
{
type: "load",
filename: URL_ROOT + TEST_LIB,
attributes: [
"jQuery"
],
handler: "ready: function() {\n" +
" // Make sure that the DOM is not already loaded\n" +
" if (!jQuery.isReady) {\n" +
" // Remember that the DOM is ready\n" +
" jQuery.isReady = true;\n" +
"\n" +
" // If there are functions bound, to execute\n" +
" if (jQuery.readyList) {\n" +
" // Execute all of them\n" +
" jQuery.each(jQuery.readyList, function() {\n" +
" this.apply(document);\n" +
" });\n" +
"\n" +
" // Reset the list of functions\n" +
" jQuery.readyList = null;\n" +
" }\n" +
" // Remove event lisenter to avoid memory leak\n" +
" if (jQuery.browser.mozilla || jQuery.browser.opera)\n" +
" document.removeEventListener(\"DOMContentLoaded\", jQuery.ready, false);\n" +
" }\n" +
"}"
},
{
type: "load",
filename: TEST_URL,
attributes: [
"Bubbling",
"DOM0"
],
handler: "() => {\n" +
" var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
" };\n" +
" var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
" };\n" +
" var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
" };\n" +
" var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
" };\n" +
" var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
" };\n" +
" var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
" };\n" +
" var handler7 = function divClick1() {\n" +
" alert(7);\n" +
" };\n" +
" var handler8 = function divClick2() {\n" +
" alert(8);\n" +
" };\n" +
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
" $(\"#livediv\").live(\"dragstart\", handler2);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").delegate) {\n" +
" $(document).delegate(\"#livediv\", \"dragleave\", handler3);\n" +
" $(document).delegate(\"#livediv\", \"dragend\", handler4);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +
" $(div).click(handler7);\n" +
" $(div).click(handler8);\n" +
" $(div).keydown(handler9);\n" +
"}"
},
{
type: "load",
filename: URL_ROOT + TEST_LIB,
attributes: [
"Bubbling",
"DOM0"
],
handler: "handle: function(event) {\n" +
" if (typeof jQuery == \"undefined\") return false;\n" +
"\n" +
" // Empty object is for triggered events with no data\n" +
" event = jQuery.event.fix(event || window.event || {});\n" +
"\n" +
" // returned undefined or false\n" +
" var returnValue;\n" +
"\n" +
" var c = this.events[event.type];\n" +
"\n" +
" var args = [].slice.call(arguments, 1);\n" +
" args.unshift(event);\n" +
"\n" +
" for (var j in c) {\n" +
" // Pass in a reference to the handler function itself\n" +
" // So that we can later remove it\n" +
" args[0].handler = c[j];\n" +
" args[0].data = c[j].data;\n" +
"\n" +
" if (c[j].apply(this, args) === false) {\n" +
" event.preventDefault();\n" +
" event.stopPropagation();\n" +
" returnValue = false;\n" +
" }\n" +
" }\n" +
"\n" +
" // Clean up added properties in IE to prevent memory leak\n" +
" if (jQuery.browser.msie) event.target = event.preventDefault = event.stopPropagation = event.handler = event.data = null;\n" +
"\n" +
" return returnValue;\n" +
"}"
}
]
},
{
selector: "#testdiv",
expected: [
{
type: "click",
filename: TEST_URL + ":34",
attributes: [
"jQuery"
],
handler: "var handler7 = function divClick1() {\n" +
" alert(7);\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":35",
attributes: [
"jQuery"
],
handler: "var handler8 = function divClick2() {\n" +
" alert(8);\n" +
"}"
},
{
type: "click",
filename: URL_ROOT + TEST_LIB + ":1224",
attributes: [
"Bubbling",
"DOM2"
],
handler: "handle: function(event) {\n" +
" if (typeof jQuery == \"undefined\") return false;\n" +
"\n" +
" // Empty object is for triggered events with no data\n" +
" event = jQuery.event.fix(event || window.event || {});\n" +
"\n" +
" // returned undefined or false\n" +
" var returnValue;\n" +
"\n" +
" var c = this.events[event.type];\n" +
"\n" +
" var args = [].slice.call(arguments, 1);\n" +
" args.unshift(event);\n" +
"\n" +
" for (var j in c) {\n" +
" // Pass in a reference to the handler function itself\n" +
" // So that we can later remove it\n" +
" args[0].handler = c[j];\n" +
" args[0].data = c[j].data;\n" +
"\n" +
" if (c[j].apply(this, args) === false) {\n" +
" event.preventDefault();\n" +
" event.stopPropagation();\n" +
" returnValue = false;\n" +
" }\n" +
" }\n" +
"\n" +
" // Clean up added properties in IE to prevent memory leak\n" +
" if (jQuery.browser.msie) event.target = event.preventDefault = event.stopPropagation = event.handler = event.data = null;\n" +
"\n" +
" return returnValue;\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: URL_ROOT + TEST_LIB + ":1224",
attributes: [
"Bubbling",
"DOM2"
],
handler: "handle: function(event) {\n" +
" if (typeof jQuery == \"undefined\") return false;\n" +
"\n" +
" // Empty object is for triggered events with no data\n" +
" event = jQuery.event.fix(event || window.event || {});\n" +
"\n" +
" // returned undefined or false\n" +
" var returnValue;\n" +
"\n" +
" var c = this.events[event.type];\n" +
"\n" +
" var args = [].slice.call(arguments, 1);\n" +
" args.unshift(event);\n" +
"\n" +
" for (var j in c) {\n" +
" // Pass in a reference to the handler function itself\n" +
" // So that we can later remove it\n" +
" args[0].handler = c[j];\n" +
" args[0].data = c[j].data;\n" +
"\n" +
" if (c[j].apply(this, args) === false) {\n" +
" event.preventDefault();\n" +
" event.stopPropagation();\n" +
" returnValue = false;\n" +
" }\n" +
" }\n" +
"\n" +
" // Clean up added properties in IE to prevent memory leak\n" +
" if (jQuery.browser.msie) event.target = event.preventDefault = event.stopPropagation = event.handler = event.data = null;\n" +
"\n" +
" return returnValue;\n" +
"}"
}
]
}
];
/*eslint-enable */
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

View file

@ -0,0 +1,196 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
// Test that markup view event bubbles show the correct event info for jQuery
// and jQuery Live events (jQuery version 1.11.1).
const TEST_LIB = "lib_jquery_1.11.1_min.js";
const TEST_URL = URL_ROOT + "doc_markup_events_jquery.html?" + TEST_LIB;
loadHelperScript("helper_events_test_runner.js");
/*eslint-disable */
const TEST_DATA = [
{
selector: "html",
expected: [
{
type: "load",
filename: TEST_URL + ":27",
attributes: [
"Bubbling",
"DOM2"
],
handler: "() => {\n" +
" var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
" };\n" +
" var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
" };\n" +
" var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
" };\n" +
" var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
" };\n" +
" var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
" };\n" +
" var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
" };\n" +
" var handler7 = function divClick1() {\n" +
" alert(7);\n" +
" };\n" +
" var handler8 = function divClick2() {\n" +
" alert(8);\n" +
" };\n" +
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
" $(\"#livediv\").live(\"dragstart\", handler2);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").delegate) {\n" +
" $(document).delegate(\"#livediv\", \"dragleave\", handler3);\n" +
" $(document).delegate(\"#livediv\", \"dragend\", handler4);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +
" $(div).click(handler7);\n" +
" $(div).click(handler8);\n" +
" $(div).keydown(handler9);\n" +
"}"
}
]
},
{
selector: "#testdiv",
expected: [
{
type: "click",
filename: TEST_URL + ":34",
attributes: [
"jQuery"
],
handler: "var handler7 = function divClick1() {\n" +
" alert(7);\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":35",
attributes: [
"jQuery"
],
handler: "var handler8 = function divClick2() {\n" +
" alert(8);\n" +
"}"
},
{
type: "click",
filename: URL_ROOT + TEST_LIB + ":3",
attributes: [
"Bubbling",
"DOM2"
],
handler: "k = r.handle = function(a) {\n" +
" return typeof m === K || a && m.event.triggered === a.type ? void 0 : m.event.dispatch.apply(k.elem, arguments)\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: URL_ROOT + TEST_LIB + ":3",
attributes: [
"Bubbling",
"DOM2"
],
handler: "k = r.handle = function(a) {\n" +
" return typeof m === K || a && m.event.triggered === a.type ? void 0 : m.event.dispatch.apply(k.elem, arguments)\n" +
"}"
}
]
},
{
selector: "#livediv",
expected: [
{
type: "dragend",
filename: TEST_URL + ":31",
attributes: [
"jQuery",
"Live"
],
handler: "var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
"}"
},
{
type: "dragleave",
filename: TEST_URL + ":30",
attributes: [
"jQuery",
"Live"
],
handler: "var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
"}"
},
{
type: "dragover",
filename: TEST_URL + ":33",
attributes: [
"jQuery",
"Live"
],
handler: "var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
"}"
},
{
type: "drop",
filename: TEST_URL + ":32",
attributes: [
"jQuery",
"Live"
],
handler: "var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
"}"
}
]
},
];
/*eslint-enable */
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

View file

@ -0,0 +1,191 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
// Test that markup view event bubbles show the correct event info for jQuery
// and jQuery Live events (jQuery version 1.2).
const TEST_LIB = "lib_jquery_1.2_min.js";
const TEST_URL = URL_ROOT + "doc_markup_events_jquery.html?" + TEST_LIB;
loadHelperScript("helper_events_test_runner.js");
/*eslint-disable */
const TEST_DATA = [
{
selector: "html",
expected: [
{
type: "load",
filename: TEST_URL + ":27",
attributes: [
"Bubbling",
"DOM2"
],
handler: "() => {\n" +
" var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
" };\n" +
" var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
" };\n" +
" var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
" };\n" +
" var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
" };\n" +
" var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
" };\n" +
" var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
" };\n" +
" var handler7 = function divClick1() {\n" +
" alert(7);\n" +
" };\n" +
" var handler8 = function divClick2() {\n" +
" alert(8);\n" +
" };\n" +
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
" $(\"#livediv\").live(\"dragstart\", handler2);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").delegate) {\n" +
" $(document).delegate(\"#livediv\", \"dragleave\", handler3);\n" +
" $(document).delegate(\"#livediv\", \"dragend\", handler4);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +
" $(div).click(handler7);\n" +
" $(div).click(handler8);\n" +
" $(div).keydown(handler9);\n" +
"}"
},
{
type: "load",
filename: URL_ROOT + TEST_LIB,
attributes: [
"Bubbling",
"DOM0"
],
handler: "handle: function(event) {\n" +
" if (typeof jQuery == \"undefined\") return false;\n" +
"\n" +
" // Empty object is for triggered events with no data\n" +
" event = jQuery.event.fix(event || window.event || {});\n" +
"\n" +
" // returned undefined or false\n" +
" var returnValue;\n" +
"\n" +
" var c = this.events[event.type];\n" +
"\n" +
" var args = [].slice.call(arguments, 1);\n" +
" args.unshift(event);\n" +
"\n" +
" for (var j in c) {\n" +
" // Pass in a reference to the handler function itself\n" +
" // So that we can later remove it\n" +
" args[0].handler = c[j];\n" +
" args[0].data = c[j].data;\n" +
"\n" +
" if (c[j].apply(this, args) === false) {\n" +
" event.preventDefault();\n" +
" event.stopPropagation();\n" +
" returnValue = false;\n" +
" }\n" +
" }\n" +
"\n" +
" // Clean up added properties in IE to prevent memory leak\n" +
" if (jQuery.browser.msie) event.target = event.preventDefault = event.stopPropagation = event.handler = event.data = null;\n" +
"\n" +
" return returnValue;\n" +
"}"
}
]
},
{
selector: "#testdiv",
expected: [
{
type: "click",
filename: TEST_URL + ":34",
attributes: [
"jQuery"
],
handler: "var handler7 = function divClick1() {\n" +
" alert(7);\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":35",
attributes: [
"jQuery"
],
handler: "var handler8 = function divClick2() {\n" +
" alert(8);\n" +
"}"
},
{
type: "click",
filename: URL_ROOT + TEST_LIB + ":24",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function() {\n" +
" var val;\n" +
" if (typeof jQuery == \"undefined\" || jQuery.event.triggered) return val;\n" +
" val = jQuery.event.handle.apply(element, arguments);\n" +
" return val;\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: URL_ROOT + TEST_LIB + ":24",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function() {\n" +
" var val;\n" +
" if (typeof jQuery == \"undefined\" || jQuery.event.triggered) return val;\n" +
" val = jQuery.event.handle.apply(element, arguments);\n" +
" return val;\n" +
"}"
}
]
},
];
/*eslint-enable */
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

View file

@ -0,0 +1,224 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
// Test that markup view event bubbles show the correct event info for jQuery
// and jQuery Live events (jQuery version 1.3).
const TEST_LIB = "lib_jquery_1.3_min.js";
const TEST_URL = URL_ROOT + "doc_markup_events_jquery.html?" + TEST_LIB;
loadHelperScript("helper_events_test_runner.js");
/*eslint-disable */
const TEST_DATA = [
{
selector: "html",
expected: [
{
type: "load",
filename: URL_ROOT + TEST_LIB + ":19",
attributes: [
"jQuery"
],
handler: "ready: function() {\n" +
" if (!n.isReady) {\n" +
" n.isReady = true;\n" +
" if (n.readyList) {\n" +
" n.each(n.readyList, function() {\n" +
" this.call(document, n)\n" +
" });\n" +
" n.readyList = null\n" +
" }\n" +
" n(document).triggerHandler(\"ready\")\n" +
" }\n" +
"}"
},
{
type: "load",
filename: TEST_URL + ":27",
attributes: [
"Bubbling",
"DOM2"
],
handler: "() => {\n" +
" var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
" };\n" +
" var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
" };\n" +
" var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
" };\n" +
" var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
" };\n" +
" var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
" };\n" +
" var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
" };\n" +
" var handler7 = function divClick1() {\n" +
" alert(7);\n" +
" };\n" +
" var handler8 = function divClick2() {\n" +
" alert(8);\n" +
" };\n" +
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
" $(\"#livediv\").live(\"dragstart\", handler2);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").delegate) {\n" +
" $(document).delegate(\"#livediv\", \"dragleave\", handler3);\n" +
" $(document).delegate(\"#livediv\", \"dragend\", handler4);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +
" $(div).click(handler7);\n" +
" $(div).click(handler8);\n" +
" $(div).keydown(handler9);\n" +
"}"
},
{
type: "load",
filename: URL_ROOT + TEST_LIB + ":19",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function() {\n" +
" return typeof n !== \"undefined\" && !n.event.triggered ? n.event.handle.apply(arguments.callee.elem, arguments) : g\n" +
"}"
},
{
type: "unload",
filename: URL_ROOT + TEST_LIB + ":19",
attributes: [
"jQuery"
],
handler: "function(H) {\n" +
" n(this).unbind(H, D);\n" +
" return (E || G).apply(this, arguments)\n" +
"}"
},
{
type: "unload",
filename: URL_ROOT + TEST_LIB + ":19",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function() {\n" +
" return typeof n !== \"undefined\" && !n.event.triggered ? n.event.handle.apply(arguments.callee.elem, arguments) : g\n" +
"}"
}
]
},
{
selector: "#testdiv",
expected: [
{
type: "click",
filename: TEST_URL + ":34",
attributes: [
"jQuery"
],
handler: "var handler7 = function divClick1() {\n" +
" alert(7);\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":35",
attributes: [
"jQuery"
],
handler: "var handler8 = function divClick2() {\n" +
" alert(8);\n" +
"}"
},
{
type: "click",
filename: URL_ROOT + TEST_LIB + ":19",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function() {\n" +
" return typeof n !== \"undefined\" && !n.event.triggered ? n.event.handle.apply(arguments.callee.elem, arguments) : g\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: URL_ROOT + TEST_LIB + ":19",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function() {\n" +
" return typeof n !== \"undefined\" && !n.event.triggered ? n.event.handle.apply(arguments.callee.elem, arguments) : g\n" +
"}"
}
]
},
{
selector: "#livediv",
expected: [
{
type: "dblclick",
filename: TEST_URL + ":28",
attributes: [
"jQuery",
"Live"
],
handler: "var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
"}"
},
{
type: "dragstart",
filename: TEST_URL + ":29",
attributes: [
"jQuery",
"Live"
],
handler: "var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
"}"
}
]
},
];
/*eslint-enable */
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

View file

@ -0,0 +1,287 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
// Test that markup view event bubbles show the correct event info for jQuery
// and jQuery Live events (jQuery version 1.4).
const TEST_LIB = "lib_jquery_1.4_min.js";
const TEST_URL = URL_ROOT + "doc_markup_events_jquery.html?" + TEST_LIB;
loadHelperScript("helper_events_test_runner.js");
/*eslint-disable */
const TEST_DATA = [
{
selector: "html",
expected: [
{
type: "load",
filename: TEST_URL + ":27",
attributes: [
"Bubbling",
"DOM2"
],
handler: "() => {\n" +
" var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
" };\n" +
" var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
" };\n" +
" var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
" };\n" +
" var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
" };\n" +
" var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
" };\n" +
" var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
" };\n" +
" var handler7 = function divClick1() {\n" +
" alert(7);\n" +
" };\n" +
" var handler8 = function divClick2() {\n" +
" alert(8);\n" +
" };\n" +
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
" $(\"#livediv\").live(\"dragstart\", handler2);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").delegate) {\n" +
" $(document).delegate(\"#livediv\", \"dragleave\", handler3);\n" +
" $(document).delegate(\"#livediv\", \"dragend\", handler4);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +
" $(div).click(handler7);\n" +
" $(div).click(handler8);\n" +
" $(div).keydown(handler9);\n" +
"}"
},
{
type: "load",
filename: URL_ROOT + TEST_LIB + ":26",
attributes: [
"Bubbling",
"DOM2"
],
handler: "ready: function() {\n" +
" if (!c.isReady) {\n" +
" if (!s.body) return setTimeout(c.ready, 13);\n" +
" c.isReady = true;\n" +
" if (Q) {\n" +
" for (var a, b = 0; a = Q[b++];) a.call(s, c);\n" +
" Q = null\n" +
" }\n" +
" c.fn.triggerHandler && c(s).triggerHandler(\"ready\")\n" +
" }\n" +
"}"
}
]
},
{
selector: "#testdiv",
expected: [
{
type: "click",
filename: TEST_URL + ":34",
attributes: [
"jQuery"
],
handler: "var handler7 = function divClick1() {\n" +
" alert(7);\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":35",
attributes: [
"jQuery"
],
handler: "var handler8 = function divClick2() {\n" +
" alert(8);\n" +
"}"
},
{
type: "click",
filename: URL_ROOT + TEST_LIB + ":48",
attributes: [
"Bubbling",
"DOM2"
],
handler: "j = function() {\n" +
" return typeof c !== \"undefined\" && !c.event.triggered ? c.event.handle.apply(j.elem, arguments) : w\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: URL_ROOT + TEST_LIB + ":48",
attributes: [
"Bubbling",
"DOM2"
],
handler: "j = function() {\n" +
" return typeof c !== \"undefined\" && !c.event.triggered ? c.event.handle.apply(j.elem, arguments) : w\n" +
"}"
}
]
},
{
selector: "#livediv",
expected: [
{
type: "dblclick",
filename: TEST_URL + ":28",
attributes: [
"jQuery",
"Live"
],
handler: "var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
"}"
},
{
type: "dblclick",
filename: URL_ROOT + TEST_LIB + ":17",
attributes: [
"jQuery",
"Live"
],
handler: "function qa(a) {\n" +
" var b = true,\n" +
" d = [],\n" +
" f = [],\n" +
" e = arguments,\n" +
" i, j, o, p, n, t = c.extend({}, c.data(this, \"events\").live);\n" +
" for (p in t) {\n" +
" j = t[p];\n" +
" if (j.live === a.type || j.altLive && c.inArray(a.type, j.altLive) > -1) {\n" +
" i = j.data;\n" +
" i.beforeFilter && i.beforeFilter[a.type] && !i.beforeFilter[a.type](a) || f.push(j.selector)\n" +
" } else delete t[p]\n" +
" }\n" +
" i = c(a.target).closest(f, a.currentTarget);\n" +
" n = 0;\n" +
" for (l = i.length; n < l; n++)\n" +
" for (p in t) {\n" +
" j = t[p];\n" +
" o = i[n].elem;\n" +
" f = null;\n" +
" if (i[n].selector === j.selector) {\n" +
" if (j.live === \"mouseenter\" || j.live === \"mouseleave\") f = c(a.relatedTarget).closest(j.selector)[0];\n" +
" if (!f || f !== o) d.push({\n" +
" elem: o,\n" +
" fn: j\n" +
" })\n" +
" }\n" +
" }\n" +
" n = 0;\n" +
" for (l = d.length; n < l; n++) {\n" +
" i = d[n];\n" +
" a.currentTarget = i.elem;\n" +
" a.data = i.fn.data;\n" +
" if (i.fn.apply(i.elem, e) === false) {\n" +
" b = false;\n" +
" break\n" +
" }\n" +
" }\n" +
" return b\n" +
"}"
},
{
type: "dragstart",
filename: TEST_URL + ":29",
attributes: [
"jQuery",
"Live"
],
handler: "var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
"}"
},
{
type: "dragstart",
filename: URL_ROOT + TEST_LIB + ":17",
attributes: [
"jQuery",
"Live"
],
handler: "function qa(a) {\n" +
" var b = true,\n" +
" d = [],\n" +
" f = [],\n" +
" e = arguments,\n" +
" i, j, o, p, n, t = c.extend({}, c.data(this, \"events\").live);\n" +
" for (p in t) {\n" +
" j = t[p];\n" +
" if (j.live === a.type || j.altLive && c.inArray(a.type, j.altLive) > -1) {\n" +
" i = j.data;\n" +
" i.beforeFilter && i.beforeFilter[a.type] && !i.beforeFilter[a.type](a) || f.push(j.selector)\n" +
" } else delete t[p]\n" +
" }\n" +
" i = c(a.target).closest(f, a.currentTarget);\n" +
" n = 0;\n" +
" for (l = i.length; n < l; n++)\n" +
" for (p in t) {\n" +
" j = t[p];\n" +
" o = i[n].elem;\n" +
" f = null;\n" +
" if (i[n].selector === j.selector) {\n" +
" if (j.live === \"mouseenter\" || j.live === \"mouseleave\") f = c(a.relatedTarget).closest(j.selector)[0];\n" +
" if (!f || f !== o) d.push({\n" +
" elem: o,\n" +
" fn: j\n" +
" })\n" +
" }\n" +
" }\n" +
" n = 0;\n" +
" for (l = d.length; n < l; n++) {\n" +
" i = d[n];\n" +
" a.currentTarget = i.elem;\n" +
" a.data = i.fn.data;\n" +
" if (i.fn.apply(i.elem, e) === false) {\n" +
" b = false;\n" +
" break\n" +
" }\n" +
" }\n" +
" return b\n" +
"}"
}
]
},
];
/*eslint-enable */
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

View file

@ -0,0 +1,388 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
requestLongerTimeout(2);
// Test that markup view event bubbles show the correct event info for jQuery
// and jQuery Live events (jQuery version 1.6).
const TEST_LIB = "lib_jquery_1.6_min.js";
const TEST_URL = URL_ROOT + "doc_markup_events_jquery.html?" + TEST_LIB;
loadHelperScript("helper_events_test_runner.js");
/*eslint-disable */
const TEST_DATA = [
{
selector: "html",
expected: [
{
type: "load",
filename: TEST_URL + ":27",
attributes: [
"Bubbling",
"DOM2"
],
handler: "() => {\n" +
" var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
" };\n" +
" var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
" };\n" +
" var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
" };\n" +
" var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
" };\n" +
" var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
" };\n" +
" var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
" };\n" +
" var handler7 = function divClick1() {\n" +
" alert(7);\n" +
" };\n" +
" var handler8 = function divClick2() {\n" +
" alert(8);\n" +
" };\n" +
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
" $(\"#livediv\").live(\"dragstart\", handler2);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").delegate) {\n" +
" $(document).delegate(\"#livediv\", \"dragleave\", handler3);\n" +
" $(document).delegate(\"#livediv\", \"dragend\", handler4);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +
" $(div).click(handler7);\n" +
" $(div).click(handler8);\n" +
" $(div).keydown(handler9);\n" +
"}"
},
{
type: "load",
filename: URL_ROOT + TEST_LIB + ":16",
attributes: [
"Bubbling",
"DOM2"
],
handler: "ready: function(a) {\n" +
" if (a === !0 && !--e.readyWait || a !== !0 && !e.isReady) {\n" +
" if (!c.body) return setTimeout(e.ready, 1);\n" +
" e.isReady = !0;\n" +
" if (a !== !0 && --e.readyWait > 0) return;\n" +
" y.resolveWith(c, [e]), e.fn.trigger && e(c).trigger(\"ready\").unbind(\"ready\")\n" +
" }\n" +
"}"
}
]
},
{
selector: "#testdiv",
expected: [
{
type: "click",
filename: TEST_URL + ":34",
attributes: [
"jQuery"
],
handler: "var handler7 = function divClick1() {\n" +
" alert(7);\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":35",
attributes: [
"jQuery"
],
handler: "var handler8 = function divClick2() {\n" +
" alert(8);\n" +
"}"
},
{
type: "click",
filename: URL_ROOT + TEST_LIB + ":16",
attributes: [
"Bubbling",
"DOM2"
],
handler: "i.handle = k = function(a) {\n" +
" return typeof f != \"undefined\" && (!a || f.event.triggered !== a.type) ? f.event.handle.apply(k.elem, arguments) : b\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: URL_ROOT + TEST_LIB + ":16",
attributes: [
"Bubbling",
"DOM2"
],
handler: "i.handle = k = function(a) {\n" +
" return typeof f != \"undefined\" && (!a || f.event.triggered !== a.type) ? f.event.handle.apply(k.elem, arguments) : b\n" +
"}"
}
]
},
{
selector: "#livediv",
expected: [
{
type: "dblclick",
filename: TEST_URL + ":28",
attributes: [
"jQuery",
"Live"
],
handler: "var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
"}"
},
{
type: "dblclick",
filename: URL_ROOT + TEST_LIB + ":16",
attributes: [
"jQuery",
"Live"
],
handler: "function M(a) {\n" +
" var b, c, d, e, g, h, i, j, k, l, m, n, o, p = [],\n" +
" q = [],\n" +
" r = f._data(this, \"events\");\n" +
" if (!(a.liveFired === this || !r || !r.live || a.target.disabled || a.button && a.type === \"click\")) {\n" +
" a.namespace && (n = new RegExp(\"(^|\\\\.)\" + a.namespace.split(\".\").join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\")), a.liveFired = this;\n" +
" var s = r.live.slice(0);\n" +
" for (i = 0; i < s.length; i++) g = s[i], g.origType.replace(x, \"\") === a.type ? q.push(g.selector) : s.splice(i--, 1);\n" +
" e = f(a.target).closest(q, a.currentTarget);\n" +
" for (j = 0, k = e.length; j < k; j++) {\n" +
" m = e[j];\n" +
" for (i = 0; i < s.length; i++) {\n" +
" g = s[i];\n" +
" if (m.selector === g.selector && (!n || n.test(g.namespace)) && !m.elem.disabled) {\n" +
" h = m.elem, d = null;\n" +
" if (g.preType === \"mouseenter\" || g.preType === \"mouseleave\") a.type = g.preType, d = f(a.relatedTarget).closest(g.selector)[0], d && f.contains(h, d) && (d = h);\n" +
" (!d || d !== h) && p.push({\n" +
" elem: h,\n" +
" handleObj: g,\n" +
" level: m.level\n" +
" })\n" +
" }\n" +
" }\n" +
" }\n" +
" for (j = 0, k = p.length; j < k; j++) {\n" +
" e = p[j];\n" +
" if (c && e.level > c) break;\n" +
" a.currentTarget = e.elem, a.data = e.handleObj.data, a.handleObj = e.handleObj, o = e.handleObj.origHandler.apply(e.elem, arguments);\n" +
" if (o === !1 || a.isPropagationStopped()) {\n" +
" c = e.level, o === !1 && (b = !1);\n" +
" if (a.isImmediatePropagationStopped()) break\n" +
" }\n" +
" }\n" +
" return b\n" +
" }\n" +
"}"
},
{
type: "dragend",
filename: TEST_URL + ":31",
attributes: [
"jQuery",
"Live"
],
handler: "var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
"}"
},
{
type: "dragend",
filename: URL_ROOT + TEST_LIB + ":16",
attributes: [
"jQuery",
"Live"
],
handler: "function M(a) {\n" +
" var b, c, d, e, g, h, i, j, k, l, m, n, o, p = [],\n" +
" q = [],\n" +
" r = f._data(this, \"events\");\n" +
" if (!(a.liveFired === this || !r || !r.live || a.target.disabled || a.button && a.type === \"click\")) {\n" +
" a.namespace && (n = new RegExp(\"(^|\\\\.)\" + a.namespace.split(\".\").join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\")), a.liveFired = this;\n" +
" var s = r.live.slice(0);\n" +
" for (i = 0; i < s.length; i++) g = s[i], g.origType.replace(x, \"\") === a.type ? q.push(g.selector) : s.splice(i--, 1);\n" +
" e = f(a.target).closest(q, a.currentTarget);\n" +
" for (j = 0, k = e.length; j < k; j++) {\n" +
" m = e[j];\n" +
" for (i = 0; i < s.length; i++) {\n" +
" g = s[i];\n" +
" if (m.selector === g.selector && (!n || n.test(g.namespace)) && !m.elem.disabled) {\n" +
" h = m.elem, d = null;\n" +
" if (g.preType === \"mouseenter\" || g.preType === \"mouseleave\") a.type = g.preType, d = f(a.relatedTarget).closest(g.selector)[0], d && f.contains(h, d) && (d = h);\n" +
" (!d || d !== h) && p.push({\n" +
" elem: h,\n" +
" handleObj: g,\n" +
" level: m.level\n" +
" })\n" +
" }\n" +
" }\n" +
" }\n" +
" for (j = 0, k = p.length; j < k; j++) {\n" +
" e = p[j];\n" +
" if (c && e.level > c) break;\n" +
" a.currentTarget = e.elem, a.data = e.handleObj.data, a.handleObj = e.handleObj, o = e.handleObj.origHandler.apply(e.elem, arguments);\n" +
" if (o === !1 || a.isPropagationStopped()) {\n" +
" c = e.level, o === !1 && (b = !1);\n" +
" if (a.isImmediatePropagationStopped()) break\n" +
" }\n" +
" }\n" +
" return b\n" +
" }\n" +
"}"
},
{
type: "dragleave",
filename: TEST_URL + ":30",
attributes: [
"jQuery",
"Live"
],
handler: "var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
"}"
},
{
type: "dragleave",
filename: URL_ROOT + TEST_LIB + ":16",
attributes: [
"jQuery",
"Live"
],
handler: "function M(a) {\n" +
" var b, c, d, e, g, h, i, j, k, l, m, n, o, p = [],\n" +
" q = [],\n" +
" r = f._data(this, \"events\");\n" +
" if (!(a.liveFired === this || !r || !r.live || a.target.disabled || a.button && a.type === \"click\")) {\n" +
" a.namespace && (n = new RegExp(\"(^|\\\\.)\" + a.namespace.split(\".\").join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\")), a.liveFired = this;\n" +
" var s = r.live.slice(0);\n" +
" for (i = 0; i < s.length; i++) g = s[i], g.origType.replace(x, \"\") === a.type ? q.push(g.selector) : s.splice(i--, 1);\n" +
" e = f(a.target).closest(q, a.currentTarget);\n" +
" for (j = 0, k = e.length; j < k; j++) {\n" +
" m = e[j];\n" +
" for (i = 0; i < s.length; i++) {\n" +
" g = s[i];\n" +
" if (m.selector === g.selector && (!n || n.test(g.namespace)) && !m.elem.disabled) {\n" +
" h = m.elem, d = null;\n" +
" if (g.preType === \"mouseenter\" || g.preType === \"mouseleave\") a.type = g.preType, d = f(a.relatedTarget).closest(g.selector)[0], d && f.contains(h, d) && (d = h);\n" +
" (!d || d !== h) && p.push({\n" +
" elem: h,\n" +
" handleObj: g,\n" +
" level: m.level\n" +
" })\n" +
" }\n" +
" }\n" +
" }\n" +
" for (j = 0, k = p.length; j < k; j++) {\n" +
" e = p[j];\n" +
" if (c && e.level > c) break;\n" +
" a.currentTarget = e.elem, a.data = e.handleObj.data, a.handleObj = e.handleObj, o = e.handleObj.origHandler.apply(e.elem, arguments);\n" +
" if (o === !1 || a.isPropagationStopped()) {\n" +
" c = e.level, o === !1 && (b = !1);\n" +
" if (a.isImmediatePropagationStopped()) break\n" +
" }\n" +
" }\n" +
" return b\n" +
" }\n" +
"}"
},
{
type: "dragstart",
filename: TEST_URL + ":29",
attributes: [
"jQuery",
"Live"
],
handler: "var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
"}"
},
{
type: "dragstart",
filename: URL_ROOT + TEST_LIB + ":16",
attributes: [
"jQuery",
"Live"
],
handler: "function M(a) {\n" +
" var b, c, d, e, g, h, i, j, k, l, m, n, o, p = [],\n" +
" q = [],\n" +
" r = f._data(this, \"events\");\n" +
" if (!(a.liveFired === this || !r || !r.live || a.target.disabled || a.button && a.type === \"click\")) {\n" +
" a.namespace && (n = new RegExp(\"(^|\\\\.)\" + a.namespace.split(\".\").join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\")), a.liveFired = this;\n" +
" var s = r.live.slice(0);\n" +
" for (i = 0; i < s.length; i++) g = s[i], g.origType.replace(x, \"\") === a.type ? q.push(g.selector) : s.splice(i--, 1);\n" +
" e = f(a.target).closest(q, a.currentTarget);\n" +
" for (j = 0, k = e.length; j < k; j++) {\n" +
" m = e[j];\n" +
" for (i = 0; i < s.length; i++) {\n" +
" g = s[i];\n" +
" if (m.selector === g.selector && (!n || n.test(g.namespace)) && !m.elem.disabled) {\n" +
" h = m.elem, d = null;\n" +
" if (g.preType === \"mouseenter\" || g.preType === \"mouseleave\") a.type = g.preType, d = f(a.relatedTarget).closest(g.selector)[0], d && f.contains(h, d) && (d = h);\n" +
" (!d || d !== h) && p.push({\n" +
" elem: h,\n" +
" handleObj: g,\n" +
" level: m.level\n" +
" })\n" +
" }\n" +
" }\n" +
" }\n" +
" for (j = 0, k = p.length; j < k; j++) {\n" +
" e = p[j];\n" +
" if (c && e.level > c) break;\n" +
" a.currentTarget = e.elem, a.data = e.handleObj.data, a.handleObj = e.handleObj, o = e.handleObj.origHandler.apply(e.elem, arguments);\n" +
" if (o === !1 || a.isPropagationStopped()) {\n" +
" c = e.level, o === !1 && (b = !1);\n" +
" if (a.isImmediatePropagationStopped()) break\n" +
" }\n" +
" }\n" +
" return b\n" +
" }\n" +
"}"
}
]
},
];
/*eslint-enable */
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

View file

@ -0,0 +1,234 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
requestLongerTimeout(2);
// Test that markup view event bubbles show the correct event info for jQuery
// and jQuery Live events (jQuery version 1.7).
const TEST_LIB = "lib_jquery_1.7_min.js";
const TEST_URL = URL_ROOT + "doc_markup_events_jquery.html?" + TEST_LIB;
loadHelperScript("helper_events_test_runner.js");
/*eslint-disable */
const TEST_DATA = [
{
selector: "html",
expected: [
{
type: "load",
filename: TEST_URL + ":27",
attributes: [
"Bubbling",
"DOM2"
],
handler: "() => {\n" +
" var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
" };\n" +
" var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
" };\n" +
" var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
" };\n" +
" var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
" };\n" +
" var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
" };\n" +
" var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
" };\n" +
" var handler7 = function divClick1() {\n" +
" alert(7);\n" +
" };\n" +
" var handler8 = function divClick2() {\n" +
" alert(8);\n" +
" };\n" +
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
" $(\"#livediv\").live(\"dragstart\", handler2);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").delegate) {\n" +
" $(document).delegate(\"#livediv\", \"dragleave\", handler3);\n" +
" $(document).delegate(\"#livediv\", \"dragend\", handler4);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +
" $(div).click(handler7);\n" +
" $(div).click(handler8);\n" +
" $(div).keydown(handler9);\n" +
"}"
},
{
type: "load",
filename: URL_ROOT + TEST_LIB + ":2",
attributes: [
"Bubbling",
"DOM2"
],
handler: "ready: function(a) {\n" +
" if (a === !0 && !--e.readyWait || a !== !0 && !e.isReady) {\n" +
" if (!c.body) return setTimeout(e.ready, 1);\n" +
" e.isReady = !0;\n" +
" if (a !== !0 && --e.readyWait > 0) return;\n" +
" B.fireWith(c, [e]), e.fn.trigger && e(c).trigger(\"ready\").unbind(\"ready\")\n" +
" }\n" +
"}"
}
]
},
{
selector: "#testdiv",
expected: [
{
type: "click",
filename: TEST_URL + ":34",
attributes: [
"jQuery"
],
handler: "var handler7 = function divClick1() {\n" +
" alert(7);\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":35",
attributes: [
"jQuery"
],
handler: "var handler8 = function divClick2() {\n" +
" alert(8);\n" +
"}"
},
{
type: "click",
filename: URL_ROOT + TEST_LIB + ":3",
attributes: [
"Bubbling",
"DOM2"
],
handler: "h.handle = i = function(a) {\n" +
" return typeof f != \"undefined\" && (!a || f.event.triggered !== a.type) ? f.event.dispatch.apply(i.elem, arguments) : b\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: URL_ROOT + TEST_LIB + ":3",
attributes: [
"Bubbling",
"DOM2"
],
handler: "h.handle = i = function(a) {\n" +
" return typeof f != \"undefined\" && (!a || f.event.triggered !== a.type) ? f.event.dispatch.apply(i.elem, arguments) : b\n" +
"}"
}
]
},
{
selector: "#livediv",
expected: [
{
type: "dblclick",
filename: TEST_URL + ":28",
attributes: [
"jQuery",
"Live"
],
handler: "var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
"}"
},
{
type: "dragend",
filename: TEST_URL + ":31",
attributes: [
"jQuery",
"Live"
],
handler: "var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
"}"
},
{
type: "dragleave",
filename: TEST_URL + ":30",
attributes: [
"jQuery",
"Live"
],
handler: "var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
"}"
},
{
type: "dragover",
filename: TEST_URL + ":33",
attributes: [
"jQuery",
"Live"
],
handler: "var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
"}"
},
{
type: "dragstart",
filename: TEST_URL + ":29",
attributes: [
"jQuery",
"Live"
],
handler: "var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
"}"
},
{
type: "drop",
filename: TEST_URL + ":32",
attributes: [
"jQuery",
"Live"
],
handler: "var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
"}"
}
]
},
];
/*eslint-enable */
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

View file

@ -0,0 +1,196 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
requestLongerTimeout(2);
// Test that markup view event bubbles show the correct event info for jQuery
// and jQuery Live events (jQuery version 2.1.1).
const TEST_LIB = "lib_jquery_2.1.1_min.js";
const TEST_URL = URL_ROOT + "doc_markup_events_jquery.html?" + TEST_LIB;
loadHelperScript("helper_events_test_runner.js");
/*eslint-disable */
const TEST_DATA = [
{
selector: "html",
expected: [
{
type: "load",
filename: TEST_URL + ":27",
attributes: [
"Bubbling",
"DOM2"
],
handler: "() => {\n" +
" var handler1 = function liveDivDblClick() {\n" +
" alert(1);\n" +
" };\n" +
" var handler2 = function liveDivDragStart() {\n" +
" alert(2);\n" +
" };\n" +
" var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
" };\n" +
" var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
" };\n" +
" var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
" };\n" +
" var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
" };\n" +
" var handler7 = function divClick1() {\n" +
" alert(7);\n" +
" };\n" +
" var handler8 = function divClick2() {\n" +
" alert(8);\n" +
" };\n" +
" var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
" };\n" +
" var handler10 = function divDragOut() {\n" +
" alert(10);\n" +
" };\n" +
"\n" +
" if ($(\"#livediv\").live) {\n" +
" $(\"#livediv\").live(\"dblclick\", handler1);\n" +
" $(\"#livediv\").live(\"dragstart\", handler2);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").delegate) {\n" +
" $(document).delegate(\"#livediv\", \"dragleave\", handler3);\n" +
" $(document).delegate(\"#livediv\", \"dragend\", handler4);\n" +
" }\n" +
"\n" +
" if ($(\"#livediv\").on) {\n" +
" $(document).on(\"drop\", \"#livediv\", handler5);\n" +
" $(document).on(\"dragover\", \"#livediv\", handler6);\n" +
" $(document).on(\"dragout\", \"#livediv:xxxxx\", handler10);\n" +
" }\n" +
"\n" +
" var div = $(\"div\")[0];\n" +
" $(div).click(handler7);\n" +
" $(div).click(handler8);\n" +
" $(div).keydown(handler9);\n" +
"}"
}
]
},
{
selector: "#testdiv",
expected: [
{
type: "click",
filename: TEST_URL + ":34",
attributes: [
"jQuery"
],
handler: "var handler7 = function divClick1() {\n" +
" alert(7);\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":35",
attributes: [
"jQuery"
],
handler: "var handler8 = function divClick2() {\n" +
" alert(8);\n" +
"}"
},
{
type: "click",
filename: URL_ROOT + TEST_LIB + ":3",
attributes: [
"Bubbling",
"DOM2"
],
handler: "g = r.handle = function(b) {\n" +
" return typeof n !== U && n.event.triggered !== b.type ? n.event.dispatch.apply(a, arguments) : void 0\n" +
"}"
},
{
type: "keydown",
filename: TEST_URL + ":36",
attributes: [
"jQuery"
],
handler: "var handler9 = function divKeyDown() {\n" +
" alert(9);\n" +
"}"
},
{
type: "keydown",
filename: URL_ROOT + TEST_LIB + ":3",
attributes: [
"Bubbling",
"DOM2"
],
handler: "g = r.handle = function(b) {\n" +
" return typeof n !== U && n.event.triggered !== b.type ? n.event.dispatch.apply(a, arguments) : void 0\n" +
"}"
}
]
},
{
selector: "#livediv",
expected: [
{
type: "dragend",
filename: TEST_URL + ":31",
attributes: [
"jQuery",
"Live"
],
handler: "var handler4 = function liveDivDragEnd() {\n" +
" alert(4);\n" +
"}"
},
{
type: "dragleave",
filename: TEST_URL + ":30",
attributes: [
"jQuery",
"Live"
],
handler: "var handler3 = function liveDivDragLeave() {\n" +
" alert(3);\n" +
"}"
},
{
type: "dragover",
filename: TEST_URL + ":33",
attributes: [
"jQuery",
"Live"
],
handler: "var handler6 = function liveDivDragOver() {\n" +
" alert(6);\n" +
"}"
},
{
type: "drop",
filename: TEST_URL + ":32",
attributes: [
"jQuery",
"Live"
],
handler: "var handler5 = function liveDivDrop() {\n" +
" alert(5);\n" +
"}"
}
]
},
];
/*eslint-enable */
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

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/ */
/* import-globals-from helper_outerhtml_test_runner.js */
"use strict";
// Test outerHTML edition via the markup-view
requestLongerTimeout(2);
loadHelperScript("helper_outerhtml_test_runner.js");
const TEST_DATA = [{
selector: "#one",
oldHTML: '<div id="one">First <em>Div</em></div>',
newHTML: '<div id="one">First Div</div>',
validate: function* ({pageNodeFront, selectedNodeFront, testActor}) {
let text = yield testActor.getProperty("#one", "textContent");
is(text, "First Div", "New div has expected text content");
let num = yield testActor.getNumberOfElementMatches("#one em");
is(num, 0, "No em remaining");
}
}, {
selector: "#removedChildren",
oldHTML: "<div id=\"removedChildren\">removedChild " +
"<i>Italic <b>Bold <u>Underline</u></b></i> Normal</div>",
newHTML: "<div id=\"removedChildren\">removedChild</div>"
}, {
selector: "#addedChildren",
oldHTML: '<div id="addedChildren">addedChildren</div>',
newHTML: "<div id=\"addedChildren\">addedChildren " +
"<i>Italic <b>Bold <u>Underline</u></b></i> Normal</div>"
}, {
selector: "#addedAttribute",
oldHTML: '<div id="addedAttribute">addedAttribute</div>',
newHTML: "<div id=\"addedAttribute\" class=\"important\" disabled checked>" +
"addedAttribute</div>",
validate: function* ({pageNodeFront, selectedNodeFront, testActor}) {
is(pageNodeFront, selectedNodeFront, "Original element is selected");
let html = yield testActor.getProperty("#addedAttribute", "outerHTML");
is(html, "<div id=\"addedAttribute\" class=\"important\" disabled=\"\" " +
"checked=\"\">addedAttribute</div>", "Attributes have been added");
}
}, {
selector: "#changedTag",
oldHTML: '<div id="changedTag">changedTag</div>',
newHTML: '<p id="changedTag" class="important">changedTag</p>'
}, {
selector: "#siblings",
oldHTML: '<div id="siblings">siblings</div>',
newHTML: '<div id="siblings-before-sibling">before sibling</div>' +
'<div id="siblings">siblings (updated)</div>' +
'<div id="siblings-after-sibling">after sibling</div>',
validate: function* ({selectedNodeFront, inspector, testActor}) {
let beforeSiblingFront = yield getNodeFront("#siblings-before-sibling",
inspector);
is(beforeSiblingFront, selectedNodeFront, "Sibling has been selected");
let text = yield testActor.getProperty("#siblings", "textContent");
is(text, "siblings (updated)", "New div has expected text content");
let beforeText = yield testActor.getProperty("#siblings-before-sibling",
"textContent");
is(beforeText, "before sibling", "Sibling has been inserted");
let afterText = yield testActor.getProperty("#siblings-after-sibling",
"textContent");
is(afterText, "after sibling", "Sibling has been inserted");
}
}];
const TEST_URL = "data:text/html," +
"<!DOCTYPE html>" +
"<head><meta charset='utf-8' /></head>" +
"<body>" +
TEST_DATA.map(outer => outer.oldHTML).join("\n") +
"</body>" +
"</html>";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
inspector.markup._frame.focus();
yield runEditOuterHTMLTests(TEST_DATA, inspector, testActor);
});

View file

@ -0,0 +1,119 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_outerhtml_test_runner.js */
"use strict";
// Test outerHTML edition via the markup-view
loadHelperScript("helper_outerhtml_test_runner.js");
requestLongerTimeout(2);
const TEST_DATA = [
{
selector: "#badMarkup1",
oldHTML: "<div id=\"badMarkup1\">badMarkup1</div>",
newHTML: "<div id=\"badMarkup1\">badMarkup1</div> hanging</div>",
validate: function* ({pageNodeFront, selectedNodeFront, testActor}) {
is(pageNodeFront, selectedNodeFront, "Original element is selected");
let textNodeName = yield testActor.eval(`
content.document.querySelector("#badMarkup1").nextSibling.nodeName
`);
let textNodeData = yield testActor.eval(`
content.document.querySelector("#badMarkup1").nextSibling.data
`);
is(textNodeName, "#text", "Sibling is a text element");
is(textNodeData, " hanging", "New text node has expected text content");
}
},
{
selector: "#badMarkup2",
oldHTML: "<div id=\"badMarkup2\">badMarkup2</div>",
newHTML: "<div id=\"badMarkup2\">badMarkup2</div> hanging<div></div>" +
"</div></div></body>",
validate: function* ({pageNodeFront, selectedNodeFront, testActor}) {
is(pageNodeFront, selectedNodeFront, "Original element is selected");
let textNodeName = yield testActor.eval(`
content.document.querySelector("#badMarkup2").nextSibling.nodeName
`);
let textNodeData = yield testActor.eval(`
content.document.querySelector("#badMarkup2").nextSibling.data
`);
is(textNodeName, "#text", "Sibling is a text element");
is(textNodeData, " hanging", "New text node has expected text content");
}
},
{
selector: "#badMarkup3",
oldHTML: "<div id=\"badMarkup3\">badMarkup3</div>",
newHTML: "<div id=\"badMarkup3\">badMarkup3 <em>Emphasized <strong> " +
"and strong</div>",
validate: function* ({pageNodeFront, selectedNodeFront, testActor}) {
is(pageNodeFront, selectedNodeFront, "Original element is selected");
let emText = yield testActor.getProperty("#badMarkup3 em", "textContent");
let strongText = yield testActor.getProperty("#badMarkup3 strong",
"textContent");
is(emText, "Emphasized and strong", "<em> was auto created");
is(strongText, " and strong", "<strong> was auto created");
}
},
{
selector: "#badMarkup4",
oldHTML: "<div id=\"badMarkup4\">badMarkup4</div>",
newHTML: "<div id=\"badMarkup4\">badMarkup4</p>",
validate: function* ({pageNodeFront, selectedNodeFront, testActor}) {
is(pageNodeFront, selectedNodeFront, "Original element is selected");
let divText = yield testActor.getProperty("#badMarkup4", "textContent");
let divTag = yield testActor.getProperty("#badMarkup4", "tagName");
let pText = yield testActor.getProperty("#badMarkup4 p", "textContent");
let pTag = yield testActor.getProperty("#badMarkup4 p", "tagName");
is(divText, "badMarkup4", "textContent is correct");
is(divTag, "DIV", "did not change to <p> tag");
is(pText, "", "The <p> tag has no children");
is(pTag, "P", "Created an empty <p> tag");
}
},
{
selector: "#badMarkup5",
oldHTML: "<p id=\"badMarkup5\">badMarkup5</p>",
newHTML: "<p id=\"badMarkup5\">badMarkup5 <div>with a nested div</div></p>",
validate: function* ({pageNodeFront, selectedNodeFront, testActor}) {
is(pageNodeFront, selectedNodeFront, "Original element is selected");
let num = yield testActor.getNumberOfElementMatches("#badMarkup5 div");
let pText = yield testActor.getProperty("#badMarkup5", "textContent");
let pTag = yield testActor.getProperty("#badMarkup5", "tagName");
let divText = yield testActor.getProperty("#badMarkup5 ~ div",
"textContent");
let divTag = yield testActor.getProperty("#badMarkup5 ~ div", "tagName");
is(num, 0, "The invalid markup got created as a sibling");
is(pText, "badMarkup5 ", "The p tag does not take in the div content");
is(pTag, "P", "Did not change to a <div> tag");
is(divText, "with a nested div", "textContent is correct");
is(divTag, "DIV", "Did not change to <p> tag");
}
}
];
const TEST_URL = "data:text/html," +
"<!DOCTYPE html>" +
"<head><meta charset='utf-8' /></head>" +
"<body>" +
TEST_DATA.map(outer => outer.oldHTML).join("\n") +
"</body>" +
"</html>";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
inspector.markup._frame.focus();
yield runEditOuterHTMLTests(TEST_DATA, inspector, testActor);
});

View file

@ -0,0 +1,200 @@
/* 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 outerHTML editing keybindings work as expected and that *special*
// elements like <html>, <body> and <head> can be edited correctly.
const TEST_URL = "data:text/html," +
"<!DOCTYPE html>" +
"<head><meta charset='utf-8' /></head>" +
"<body>" +
"<div id=\"keyboard\"></div>" +
"</body>" +
"</html>";
const SELECTOR = "#keyboard";
const OLD_HTML = '<div id="keyboard"></div>';
const NEW_HTML = '<div id="keyboard">Edited</div>';
requestLongerTimeout(2);
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
inspector.markup._frame.focus();
info("Check that pressing escape cancels edits");
yield testEscapeCancels(inspector, testActor);
info("Check that pressing F2 commits edits");
yield testF2Commits(inspector, testActor);
info("Check that editing the <body> element works like other nodes");
yield testBody(inspector, testActor);
info("Check that editing the <head> element works like other nodes");
yield testHead(inspector, testActor);
info("Check that editing the <html> element works like other nodes");
yield testDocumentElement(inspector, testActor);
info("Check (again) that editing the <html> element works like other nodes");
yield testDocumentElement2(inspector, testActor);
});
function* testEscapeCancels(inspector, testActor) {
yield selectNode(SELECTOR, inspector);
let onEditorShown = once(inspector.markup.htmlEditor, "popupshown");
EventUtils.sendKey("F2", inspector.markup._frame.contentWindow);
yield onEditorShown;
ok(inspector.markup.htmlEditor._visible, "HTML Editor is visible");
is((yield testActor.getProperty(SELECTOR, "outerHTML")), OLD_HTML,
"The node is starting with old HTML.");
inspector.markup.htmlEditor.editor.setText(NEW_HTML);
let onEditorHiddem = once(inspector.markup.htmlEditor, "popuphidden");
EventUtils.sendKey("ESCAPE", inspector.markup.htmlEditor.doc.defaultView);
yield onEditorHiddem;
ok(!inspector.markup.htmlEditor._visible, "HTML Editor is not visible");
is((yield testActor.getProperty(SELECTOR, "outerHTML")), OLD_HTML,
"Escape cancels edits");
}
function* testF2Commits(inspector, testActor) {
let onEditorShown = once(inspector.markup.htmlEditor, "popupshown");
inspector.markup._frame.contentDocument.documentElement.focus();
EventUtils.sendKey("F2", inspector.markup._frame.contentWindow);
yield onEditorShown;
ok(inspector.markup.htmlEditor._visible, "HTML Editor is visible");
is((yield testActor.getProperty(SELECTOR, "outerHTML")), OLD_HTML,
"The node is starting with old HTML.");
let onMutations = inspector.once("markupmutation");
inspector.markup.htmlEditor.editor.setText(NEW_HTML);
EventUtils.sendKey("F2", inspector.markup._frame.contentWindow);
yield onMutations;
ok(!inspector.markup.htmlEditor._visible, "HTML Editor is not visible");
is((yield testActor.getProperty(SELECTOR, "outerHTML")), NEW_HTML,
"F2 commits edits - the node has new HTML.");
}
function* testBody(inspector, testActor) {
let currentBodyHTML = yield testActor.getProperty("body", "outerHTML");
let bodyHTML = '<body id="updated"><p></p></body>';
let bodyFront = yield getNodeFront("body", inspector);
let onUpdated = inspector.once("inspector-updated");
let onReselected = inspector.markup.once("reselectedonremoved");
yield inspector.markup.updateNodeOuterHTML(bodyFront, bodyHTML,
currentBodyHTML);
yield onReselected;
yield onUpdated;
let newBodyHTML = yield testActor.getProperty("body", "outerHTML");
is(newBodyHTML, bodyHTML, "<body> HTML has been updated");
let headsNum = yield testActor.getNumberOfElementMatches("head");
is(headsNum, 1, "no extra <head>s have been added");
}
function* testHead(inspector, testActor) {
yield selectNode("head", inspector);
let currentHeadHTML = yield testActor.getProperty("head", "outerHTML");
let headHTML = "<head id=\"updated\"><title>New Title</title>" +
"<script>window.foo=\"bar\";</script></head>";
let headFront = yield getNodeFront("head", inspector);
let onUpdated = inspector.once("inspector-updated");
let onReselected = inspector.markup.once("reselectedonremoved");
yield inspector.markup.updateNodeOuterHTML(headFront, headHTML,
currentHeadHTML);
yield onReselected;
yield onUpdated;
is((yield testActor.eval("content.document.title")), "New Title",
"New title has been added");
is((yield testActor.eval("content.foo")), undefined,
"Script has not been executed");
is((yield testActor.getProperty("head", "outerHTML")), headHTML,
"<head> HTML has been updated");
is((yield testActor.getNumberOfElementMatches("body")), 1,
"no extra <body>s have been added");
}
function* testDocumentElement(inspector, testActor) {
let currentDocElementOuterHMTL = yield testActor.eval(
"content.document.documentElement.outerHMTL");
let docElementHTML = "<html id=\"updated\" foo=\"bar\"><head>" +
"<title>Updated from document element</title>" +
"<script>window.foo=\"bar\";</script></head><body>" +
"<p>Hello</p></body></html>";
let docElementFront = yield inspector.markup.walker.documentElement();
let onReselected = inspector.markup.once("reselectedonremoved");
yield inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML,
currentDocElementOuterHMTL);
yield onReselected;
is((yield testActor.eval("content.document.title")),
"Updated from document element", "New title has been added");
is((yield testActor.eval("content.foo")),
undefined, "Script has not been executed");
is((yield testActor.getAttribute("html", "id")),
"updated", "<html> ID has been updated");
is((yield testActor.getAttribute("html", "class")),
null, "<html> class has been updated");
is((yield testActor.getAttribute("html", "foo")),
"bar", "<html> attribute has been updated");
is((yield testActor.getProperty("html", "outerHTML")),
docElementHTML, "<html> HTML has been updated");
is((yield testActor.getNumberOfElementMatches("head")),
1, "no extra <head>s have been added");
is((yield testActor.getNumberOfElementMatches("body")),
1, "no extra <body>s have been added");
is((yield testActor.getProperty("body", "textContent")),
"Hello", "document.body.textContent has been updated");
}
function* testDocumentElement2(inspector, testActor) {
let currentDocElementOuterHMTL = yield testActor.eval(
"content.document.documentElement.outerHMTL");
let docElementHTML = "<html id=\"somethingelse\" class=\"updated\"><head>" +
"<title>Updated again from document element</title>" +
"<script>window.foo=\"bar\";</script></head><body>" +
"<p>Hello again</p></body></html>";
let docElementFront = yield inspector.markup.walker.documentElement();
let onReselected = inspector.markup.once("reselectedonremoved");
inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML,
currentDocElementOuterHMTL);
yield onReselected;
is((yield testActor.eval("content.document.title")),
"Updated again from document element", "New title has been added");
is((yield testActor.eval("content.foo")),
undefined, "Script has not been executed");
is((yield testActor.getAttribute("html", "id")),
"somethingelse", "<html> ID has been updated");
is((yield testActor.getAttribute("html", "class")),
"updated", "<html> class has been updated");
is((yield testActor.getAttribute("html", "foo")),
null, "<html> attribute has been removed");
is((yield testActor.getProperty("html", "outerHTML")),
docElementHTML, "<html> HTML has been updated");
is((yield testActor.getNumberOfElementMatches("head")),
1, "no extra <head>s have been added");
is((yield testActor.getNumberOfElementMatches("body")),
1, "no extra <body>s have been added");
is((yield testActor.getProperty("body", "textContent")),
"Hello again", "document.body.textContent has been updated");
}

View file

@ -0,0 +1,60 @@
/* 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 image preview tooltips are shown on img and canvas tags in the
// markup-view and that the tooltip actually contains an image and shows the
// right dimension label
const TEST_NODES = [
{selector: "img.local", size: "192" + " \u00D7 " + "192"},
{selector: "img.data", size: "64" + " \u00D7 " + "64"},
{selector: "img.remote", size: "22" + " \u00D7 " + "23"},
{selector: ".canvas", size: "600" + " \u00D7 " + "600"}
];
add_task(function* () {
yield addTab(URL_ROOT + "doc_markup_image_and_canvas_2.html");
let {inspector} = yield openInspector();
info("Selecting the first <img> tag");
yield selectNode("img", inspector);
for (let testNode of TEST_NODES) {
let target = yield getImageTooltipTarget(testNode, inspector);
yield assertTooltipShownOn(target, inspector);
checkImageTooltip(testNode, inspector);
}
});
function* getImageTooltipTarget({selector}, inspector) {
let nodeFront = yield getNodeFront(selector, inspector);
let isImg = nodeFront.tagName.toLowerCase() === "img";
let container = getContainerForNodeFront(nodeFront, inspector);
let target = container.editor.tag;
if (isImg) {
target = container.editor.getAttributeElement("src").querySelector(".link");
}
return target;
}
function* assertTooltipShownOn(element, {markup}) {
info("Is the element a valid hover target");
let isValid = yield isHoverTooltipTarget(markup.imagePreviewTooltip, element);
ok(isValid, "The element is a valid hover target for the image tooltip");
}
function checkImageTooltip({selector, size}, {markup}) {
let panel = markup.imagePreviewTooltip.panel;
let images = panel.getElementsByTagName("img");
is(images.length, 1, "Tooltip for [" + selector + "] contains an image");
let label = panel.querySelector(".devtools-tooltip-caption");
is(label.textContent, size,
"Tooltip label for [" + selector + "] displays the right image size");
markup.imagePreviewTooltip.hide();
}

View file

@ -0,0 +1,83 @@
/* 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 image preview tooltip shows updated content when the image src
// changes.
/*eslint-disable */
const INITIAL_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAADI5JREFUeNrsWwuQFNUVPf1m5z87szv7HWSWj8CigBFMEFZKiQsB1PgJwUAZg1HBpIQsKmokEhNjWUnFVPnDWBT+KolJYbRMoqUVq0yCClpqiX8sCchPWFwVlt2db7+X93pez7zu6Vn2NxsVWh8987p7pu+9555z7+tZjTGGY3kjOMa34w447oBjfKsY7i/UNM3Y8eFSAkD50Plgw03K5P9gvGv7U5ieeR3PszeREiPNX3/0DL4hjslzhm8THh+OITfXk3dhiv4GDtGPVzCaeJmPLYzuu5qJuWfuw2QTlcN1X9pwQU7LhdZ/ZAseD45cOh9hHvDkc/yAF/DNhdb5Mrr3PvBMaAYW8fMSIi2G497IMEK/YutGtAYr6+ej+nxu/NN8Ks3N7AR6HgcLz0Eg1Ljg1UcxZzi5qewIkMYLRweTr2Kzp+nmyXAd5pS3XQDd+N/4h4zgu9FI7brlXf90nMEnuwQxlvv+hosE3TuexmWeysmT4W+WxkMaLzf9Y8ATgjcUn7T9H1gqrpFq8eV1gMn6t16NhngjfoX6q4DUP032Rd4LJgpSLwJ1yzFqBG69eRkah0MVyo0Acfe+yy9AG4nMiYCkeM53KKFXncBLAXqEm+wCqZwaueq7WCmuLTcKSJmj737ol2hurA9eq9VdyiO8yWa3NNyog+SB5CZodSsQq/dfu34tJpYbBaTMzvVddDZu16q5smXf4G8zEvqm4cyaAmJPuTJk3oJWdS4WzcVtfMZbThSQckb/pYfRGgo3zNOqZnEHbJPGK4abaDCQIIsT8V/qTaBqHkLh6LzXH8XZQhbLhYKyyCC/WeHYcNdmvOgfe8skzbWL270/T3wf7tSx/lGCbTu8xlzzmCSWLc5iwmgikcCHi3Mga0Ry913vBFvQwg90l6M4ImWKfsWOp7DSWxmfpPlCFuPFfsNfKrCnPYpQKIRgqBK7D0SxYaNHwkEiJMtl0ReDp3Lc5D3PGoTo/sKngCl7a5chFqvBatKwjBd7WwqIlzB/78NcoUcp5VSgGxm+7b8eqQRGnHMO634epO4S1EZww09/iFg5UmGoESDuznP1xVhTUX1WWHPzjpd25wyH0hRxI3LGM75nxmuNEEUVpAN0XgxmPoKralakbQnWlIMQyVBD/w+3orkq4lvualjKyWwzt4MaxqspQHVhPOWG64bxYuhZXSFGWhipbSDVragOu5Y9eAsmDDUKyBA703vemVhHoueD6e9wAzJK1WfmN0Umk5GGM4kEMZcuIECqgjm0nldAqmbjwtm4VxZH5AvlADP6mx9Eqy9Q0+KqW8Ch+47FaMMYmnNGfY1iPMshoC6qFxme4wQ+0p+ARE6H3+9veWEDWgUhDhUKyFARn4jM5BNxT0XsMg7bfymGK1ov3wtjDfhL4w0HVGUVBEjDaaE+QNdrcNWch1PG4W6xrjBUXECGivg++Cva3JUT4iQUz3V2RsSVaKLwOuDT89A3HdBQoxhNC+fnVm74ual2EG893P6G+PuP4SfiO4cCBWQooL9qCWKNXPbcI37Aa/lnlZxXRt4RFONGwSDCPAHqOuqjWct1QiEMw5mChM5X4K47FyNqcd3aK9AwFH0CGYLoe1ctxk2eWi57rg5JfGp9rzC6ggCdFlAgHBDw5Yxlcg6G8SyHCjMlsgmDD9zhSeHlF+JnAgWDTQUy2NxfdwOao1UVV3pi3+bE97YSbWpLAbn6zefHNQkp1PMpIBwwvslKgIYTKM2nEpNzrGcH3FXTEal0L38kJ4uDQgEZbO4vnI173LXf5NHZaiUxtaCxyZuo/rK6LpUg54yg3zTWRAArvDcRIPZ6BqzrQ1REpmL+DNw32OKIDCb3X1qPVn8wNNMT4w2bvs+q4bAZrqBh2skaL3yyhhIIZ4i6oHkUK0RckcB8GigEyRIH4A6Mgc8fatl0/+BkkQxC9gIT4ljna1rIZW9rEdNbjJcNjsnoYj7LHWCUwpITzEgzRQKZ3XAFHbTzA3hrz8TEUUZxFBhoKpABQt/97p+w0hMZG68I8R6FtlsJT3FELndZntjM+VMnylKYq8GJI3UZaRMpquGSGFVOEfv0YZBMNzz+uvjbfzS6xQERIhlI9FcvQWNdFVb7x1zCb+QNK8vb9NsiifmI5hBgVoOCBC1sb0ab5RomqENxLO3eA1/0NDRU47q2RQNbRCUDIb7lF2CNL3ZGxEV4n08TVvZWYG4pZyV0zUdS45tyCBByOHWiyvZmxFXDCyRo1ge5+Sy0TA+8lWMiP/6O0S32exGV9Jf4fr8azdUR3zL/CZz4MtvzdX5uOYs6NDOmpkuj5Huh+7qUQSYl0ThHzw0YQzcGo6bhzEqoYq5rN3yRiYiG3Vfe2Ybm/qKA9NNZ3nNm4F7/yDkg9AN+U1mHiBcXP8zuDN76jj8hg1QyiWQigalj02BJPhK8I0zxijAjhp5zhlpLUDvS+BCy2HMAvvB4XDgL9/SXC0g/ou/5+6/xLX8w0uJrOIkXfPvyhY0F6gr7M8H0KWFYikcqAXakB+xwD9CdREBLoau7Gz3cAdSIdLFxFtJTCqRChSjnutvhDcREtzjz2Tswtz+yeNRFUeXZXtWux7C1fuoVcbd3J//ipDX3uZZDLGrwweS+UBLL5TDliVBnF8P7H+XI8aRRGsIBJg/Zlslt1+W+D1JWoSyi+kD9jfhs78t7mhZhSl+fLfY1Bdyv3I8V/qpY3B1McgN7ZFT5/vNO0I5DPLLdPBIJA8qc4h2I0QplYfDpJwHT+aj0246r5S8rToG8OjCle8wk4OLvvYGa+Ovr84uo2qBSwJS9G5egoZFLTfiEqWDtbwGfHgKOdPHcS+ai7XDzMPW/FJRLGGcxnBbK4YJC2K+h+T6Bdu5CqHqCWERd3bawb7JI+iJ735+LNaHaprBLLHBm08U3XxShEsdt+f3eTh3v7aC95Dct4RCWL5OZWh/oXBZThxAIxyOXLzBk8aiEWJID8rK3CpPOmeHaGpvCS+7EHv5FujVHUSJPLXvIFeHcNc+9xrB2gws9KZdxuLFax/WLM5gzzSm/lTXF/OdAcapyvjxPqxqHjr2v4ckX2bS2dRBrc5lSdpKjEJ9/9tdwX2WMd53ZQ2IVo3RES+UwVSpCPvYepNx4gmTGDUKIMQ4eduPnD7mx9xOn/KZKOlFbStjONxHTtR+BYAPmnoZ1Zp8wkBRwP/EL3u0F/C2hGl7vpz7vW37T3vP7if8wroKuoh8ribknX9BK5rcF+mo1qKaKyRPJTgTDjbzY8szcuLb3bpH00u35T47j7prRpwDJTxzyG0dHgxPp5bPG8VdkpfPbUg3SgoOo2mwVukb98D5EqpswZTTulCggTk4gpYhv0++wIhCJxr0+Hq1sondis0SE2oxQe3qWXwWyO4DSQg9gJ8Iiw1VFcGqXxet0N9xE4ygIxv/9W6wo9WyROEX/R+eiobYSq2vHTOR631Eiv2lRfh9dvxkumkXh92Qsx8XrAJ+7YGbWuhxOi/U+31NQmzyqNYG8N/3wfo6CRtRHcN01FzkvojohwLu0VVvDa56IS/xcj2b7nN+O+m0jqpE1wMPXZxAN9iCVThtDvH7gmiRGRpU8Lspv1Uhq4wIVdQoyuGSLNYPKUCS8+CzNURbzMmjK3i8u0U793lmuV0ef9nWQ5MGC/DiUqEUSaCtXna9RJEspZS1lrXINK/pcq+SpT50t98QKMq1FRmDfx3vxty102k0PM4ssEnvuz5+G26Ij4yDpz6z9fV8bkyIkqBFkhej0Ib+ZQ34XJK9AfozaiimqIoX3Jp3tiISrcfYpuN2+iFph/02P36PNC9fVcCnp6H9jYouKyfaWufz5Tp9tVxcUniw7IohZv4dZz81/ns67z3AYPrc2n0+Ix2q8k0PWjgBy88XaibnfK9A+5LdDY2Ivhy36fbT8Zv3Lb1U1qLqUxorXEEXIs0mjjrtxoTZWtdvigNs2sgPiujTv6DIZLld6b/V5742JZV3fUsUVFy5gdsNtKWFzUCEVbNepD1MkSMVbsb6SZm7jI3/zODtQKgUMsOw8wDZ63t5xcV1TnaEAxoc6wrqY+Fj+N4DsqOnhOIdicrQSm1MPYCPlIqHn5bbHg8/bj2D3QfZnCX3mpAICDZV8jH5kpbZqTD0W+DxaA74CWzLN2nd14OlL72J38Lf7+TjC7dadZFDoZJQPrtaIKL/G0L6ktptPZVJ8fMqHYPZOKYPMyQGadIJfDvdXwAFiZOTvDBPydf5vk4rWA+RfdhBlaF/yDDBRoMu9pfnSjv/p7DG+HXfAcQcc49v/BBgAcFAO4DmB2GQAAAAASUVORK5CYII=";
/*eslint-enable */
const UPDATED_SRC = URL_ROOT + "doc_markup_tooltip.png";
const INITIAL_SRC_SIZE = "64" + " \u00D7 " + "64";
const UPDATED_SRC_SIZE = "22" + " \u00D7 " + "23";
add_task(function* () {
let { inspector } = yield openInspectorForURL(
"data:text/html,<p>markup view tooltip test</p><img>");
info("Retrieving NodeFront for the <img> element.");
let img = yield getNodeFront("img", inspector);
info("Selecting the <img> element");
yield selectNode(img, inspector);
info("Adding src attribute to the image.");
yield updateImageSrc(img, INITIAL_SRC, inspector);
let container = getContainerForNodeFront(img, inspector);
ok(container, "Found markup container for the image.");
let target = container.editor.getAttributeElement("src")
.querySelector(".link");
ok(target, "Found the src attribute in the markup view.");
info("Showing tooltip on the src link.");
yield isHoverTooltipTarget(inspector.markup.imagePreviewTooltip, target);
checkImageTooltip(INITIAL_SRC_SIZE, inspector);
info("Updating the image src.");
yield updateImageSrc(img, UPDATED_SRC, inspector);
target = container.editor.getAttributeElement("src").querySelector(".link");
ok(target, "Found the src attribute in the markup view after mutation.");
info("Showing tooltip on the src link.");
yield isHoverTooltipTarget(inspector.markup.imagePreviewTooltip, target);
info("Checking that the new image was shown.");
checkImageTooltip(UPDATED_SRC_SIZE, inspector);
});
/**
* Updates the src attribute of the image. Return a Promise.
*/
function updateImageSrc(img, newSrc, inspector) {
let onMutated = inspector.once("markupmutation");
let onModified = img.modifyAttributes([{
attributeName: "src",
newValue: newSrc
}]);
return Promise.all([onMutated, onModified]);
}
/**
* Checks that the markup view tooltip contains an image element with the given
* size.
*/
function checkImageTooltip(size, {markup}) {
let panel = markup.imagePreviewTooltip.panel;
let images = panel.getElementsByTagName("img");
is(images.length, 1, "Tooltip contains an image");
let label = panel.querySelector(".devtools-tooltip-caption");
is(label.textContent, size, "Tooltip label displays the right image size");
markup.imagePreviewTooltip.hide();
}

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";
requestLongerTimeout(2);
// Tests tabbing through attributes on a node
const TEST_URL = "data:text/html;charset=utf8,<div id='test' a b c d e></div>";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Focusing the tag editor of the test element");
let {editor} = yield focusNode("div", inspector);
editor.tag.focus();
info("Pressing tab and expecting to focus the ID attribute, always first");
EventUtils.sendKey("tab", inspector.panelWin);
checkFocusedAttribute("id");
info("Hit enter to turn the attribute to edit mode");
EventUtils.sendKey("return", inspector.panelWin);
checkFocusedAttribute("id", true);
// Check the order of the other attributes in the DOM to the check they appear
// correctly in the markup-view
let attributes = (yield getAttributesFromEditor("div", inspector)).slice(1);
info("Tabbing forward through attributes in edit mode");
for (let attribute of attributes) {
collapseSelectionAndTab(inspector);
checkFocusedAttribute(attribute, true);
}
info("Tabbing backward through attributes in edit mode");
// Just reverse the attributes other than id and remove the first one since
// it's already focused now.
let reverseAttributes = attributes.reverse();
reverseAttributes.shift();
for (let attribute of reverseAttributes) {
collapseSelectionAndShiftTab(inspector);
checkFocusedAttribute(attribute, true);
}
});

View file

@ -0,0 +1,32 @@
/* 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 when a node in the markup-view is focused toggles
// the split-console (see bug 988278)
const TEST_URL = "data:text/html;charset=utf8,<div></div>";
add_task(function* () {
let {inspector, toolbox} = yield openInspectorForURL(TEST_URL);
info("Focusing the tag editor of the test element");
let {editor} = yield getContainerForSelector("div", inspector);
editor.tag.focus();
info("Pressing ESC and wait for the split-console to open");
let onSplitConsole = toolbox.once("split-console");
let onConsoleReady = toolbox.once("webconsole-ready");
EventUtils.synthesizeKey("VK_ESCAPE", {}, inspector.panelWin);
yield onSplitConsole;
yield onConsoleReady;
ok(toolbox.splitConsole, "The split console is shown.");
info("Pressing ESC again and wait for the split-console to close");
onSplitConsole = toolbox.once("split-console");
EventUtils.synthesizeKey("VK_ESCAPE", {}, inspector.panelWin);
yield onSplitConsole;
ok(!toolbox.splitConsole, "The split console is hidden.");
});

View file

@ -0,0 +1,50 @@
/* 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 selecting a node with the mouse (by clicking on the line) focuses
// the first focusable element in the corresponding MarkupContainer so that the
// keyboard can be used immediately.
const TEST_URL = `data:text/html;charset=utf8,
<div class='test-class'></div>Text node`;
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
let {walker} = inspector;
info("Select the test node to have the 2 test containers visible");
yield selectNode("div", inspector);
let divFront = yield walker.querySelector(walker.rootNode, "div");
let textFront = yield walker.nextSibling(divFront);
info("Click on the MarkupContainer element for the text node");
yield clickContainer(textFront, inspector);
is(inspector.markup.doc.activeElement,
getContainerForNodeFront(textFront, inspector).editor.value,
"The currently focused element is the node's text content");
info("Click on the MarkupContainer element for the <div> node");
yield clickContainer(divFront, inspector);
is(inspector.markup.doc.activeElement,
getContainerForNodeFront(divFront, inspector).editor.tag,
"The currently focused element is the div's tagname");
info("Click on the test-class attribute, to make sure it gets focused");
let editor = getContainerForNodeFront(divFront, inspector).editor;
let attributeEditor = editor.attrElements.get("class")
.querySelector(".editable");
let onFocus = once(attributeEditor, "focus");
EventUtils.synthesizeMouseAtCenter(attributeEditor, {type: "mousedown"},
inspector.markup.doc.defaultView);
EventUtils.synthesizeMouseAtCenter(attributeEditor, {type: "mouseup"},
inspector.markup.doc.defaultView);
yield onFocus;
is(inspector.markup.doc.activeElement, attributeEditor,
"The currently focused element is the div's class attribute");
});

View file

@ -0,0 +1,58 @@
/* 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";
requestLongerTimeout(2);
// Tests that selecting a node using the browser context menu (inspect element)
// or the element picker focuses that node so that the keyboard can be used
// immediately.
const TEST_URL = "data:text/html;charset=utf8,<div>test element</div>";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("Select the test node with the browser ctx menu");
yield clickOnInspectMenuItem(testActor, "div");
assertNodeSelected(inspector, "div");
info("Press arrowUp to focus <body> " +
"(which works if the node was focused properly)");
yield selectPreviousNodeWithArrowUp(inspector);
assertNodeSelected(inspector, "body");
info("Select the test node with the element picker");
yield selectWithElementPicker(inspector, testActor);
assertNodeSelected(inspector, "div");
info("Press arrowUp to focus <body> " +
"(which works if the node was focused properly)");
yield selectPreviousNodeWithArrowUp(inspector);
assertNodeSelected(inspector, "body");
});
function assertNodeSelected(inspector, tagName) {
is(inspector.selection.nodeFront.tagName.toLowerCase(), tagName,
`The <${tagName}> node is selected`);
}
function selectPreviousNodeWithArrowUp(inspector) {
let onNodeHighlighted = inspector.toolbox.once("node-highlight");
let onUpdated = inspector.once("inspector-updated");
EventUtils.synthesizeKey("VK_UP", {});
return Promise.all([onUpdated, onNodeHighlighted]);
}
function* selectWithElementPicker(inspector, testActor) {
yield startPicker(inspector.toolbox);
yield BrowserTestUtils.synthesizeMouseAtCenter("div", {
type: "mousemove",
}, gBrowser.selectedBrowser);
yield testActor.synthesizeKey({key: "VK_RETURN", options: {}});
yield inspector.once("inspector-updated");
}

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";
// Tests that attributes can be deleted from the markup-view with the delete key
// when they are focused.
const HTML = '<div id="id" class="class" data-id="id"></div>';
const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
// List of all the test cases. Each item is an object with the following props:
// - selector: the css selector of the node that should be selected
// - attribute: the name of the attribute that should be focused. Do not
// specify an attribute that would make it impossible to find the node using
// selector.
// Note that after each test case, undo is called.
const TEST_DATA = [{
selector: "#id",
attribute: "class"
}, {
selector: "#id",
attribute: "data-id"
}];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
let {walker} = inspector;
for (let {selector, attribute} of TEST_DATA) {
info("Get the container for node " + selector);
let {editor} = yield getContainerForSelector(selector, inspector);
info("Focus attribute " + attribute);
let attr = editor.attrElements.get(attribute).querySelector(".editable");
attr.focus();
info("Delete the attribute by pressing delete");
let mutated = inspector.once("markupmutation");
EventUtils.sendKey("delete", inspector.panelWin);
yield mutated;
info("Check that the node is still here");
let node = yield walker.querySelector(walker.rootNode, selector);
ok(node, "The node hasn't been deleted");
info("Check that the attribute has been deleted");
node = yield walker.querySelector(walker.rootNode,
selector + "[" + attribute + "]");
ok(!node, "The attribute does not exist anymore in the DOM");
ok(!editor.attrElements.get(attribute),
"The attribute has been removed from the container");
info("Undo the change");
yield undoChange(inspector);
node = yield walker.querySelector(walker.rootNode,
selector + "[" + attribute + "]");
ok(node, "The attribute is back in the DOM");
ok(editor.attrElements.get(attribute),
"The attribute is back on the container");
}
});

View file

@ -0,0 +1,87 @@
/* 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 the keyboard shortcut "S" used to scroll to the selected node.
const HTML =
`<div style="width: 300px; height: 3000px; position:relative;">
<div id="scroll-top"
style="height: 50px; top: 0; position:absolute;">
TOP</div>
<div id="scroll-bottom"
style="height: 50px; bottom: 0; position:absolute;">
BOTTOM</div>
</div>`;
const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
add_task(function* () {
let { inspector, testActor } = yield openInspectorForURL(TEST_URL);
info("Make sure the markup frame has the focus");
inspector.markup._frame.focus();
info("Before test starts, #scroll-top is visible, #scroll-bottom is hidden");
yield checkElementIsInViewport("#scroll-top", true, testActor);
yield checkElementIsInViewport("#scroll-bottom", false, testActor);
info("Select the #scroll-bottom node");
yield selectNode("#scroll-bottom", inspector);
info("Press S to scroll to the bottom node");
let waitForScroll = testActor.waitForEventOnNode("scroll");
yield EventUtils.synthesizeKey("S", {}, inspector.panelWin);
yield waitForScroll;
ok(true, "Scroll event received");
info("#scroll-top should be scrolled out, #scroll-bottom should be visible");
yield checkElementIsInViewport("#scroll-top", false, testActor);
yield checkElementIsInViewport("#scroll-bottom", true, testActor);
info("Select the #scroll-top node");
yield selectNode("#scroll-top", inspector);
info("Press S to scroll to the top node");
waitForScroll = testActor.waitForEventOnNode("scroll");
yield EventUtils.synthesizeKey("S", {}, inspector.panelWin);
yield waitForScroll;
ok(true, "Scroll event received");
info("#scroll-top should be visible, #scroll-bottom should be scrolled out");
yield checkElementIsInViewport("#scroll-top", true, testActor);
yield checkElementIsInViewport("#scroll-bottom", false, testActor);
info("Select #scroll-bottom node");
yield selectNode("#scroll-bottom", inspector);
info("Press shift + S, nothing should happen due to the modifier");
yield EventUtils.synthesizeKey("S", {shiftKey: true}, inspector.panelWin);
info("Same state, #scroll-top is visible, #scroll-bottom is scrolled out");
yield checkElementIsInViewport("#scroll-top", true, testActor);
yield checkElementIsInViewport("#scroll-bottom", false, testActor);
});
/**
* Verify that the element matching the provided selector is either in or out
* of the viewport, depending on the provided "expected" argument.
* Returns a promise that will resolve when the test has been performed.
*
* @param {String} selector
* css selector for the element to test
* @param {Boolean} expected
* true if the element is expected to be in the viewport, false otherwise
* @param {TestActor} testActor
* current test actor
* @return {Promise} promise
*/
function* checkElementIsInViewport(selector, expected, testActor) {
let isInViewport = yield testActor.eval(`
let node = content.document.querySelector("${selector}");
let rect = node.getBoundingClientRect();
rect.bottom >= 0 && rect.right >= 0 &&
rect.top <= content.innerHeight && rect.left <= content.innerWidth;
`);
is(isInViewport, expected,
selector + " in the viewport: expected to be " + expected);
}

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";
// Tests that links are shown in attributes when the values (or part of the
// values) are URIs or pointers to IDs.
const TEST_URL = URL_ROOT + "doc_markup_links.html";
const TEST_DATA = [{
selector: "link",
attributes: [{
attributeName: "href",
links: [{type: "cssresource", value: "style.css"}]
}]
}, {
selector: "link[rel=icon]",
attributes: [{
attributeName: "href",
links: [{type: "uri",
value: "/media/img/firefox/favicon-196.223e1bcaf067.png"}]
}]
}, {
selector: "form",
attributes: [{
attributeName: "action",
links: [{type: "uri", value: "/post_message"}]
}]
}, {
selector: "label[for=name]",
attributes: [{
attributeName: "for",
links: [{type: "idref", value: "name"}]
}]
}, {
selector: "label[for=message]",
attributes: [{
attributeName: "for",
links: [{type: "idref", value: "message"}]
}]
}, {
selector: "output",
attributes: [{
attributeName: "form",
links: [{type: "idref", value: "message-form"}]
}, {
attributeName: "for",
links: [
{type: "idref", value: "name"},
{type: "idref", value: "message"},
{type: "idref", value: "invalid"}
]
}]
}, {
selector: "a",
attributes: [{
attributeName: "href",
links: [{type: "uri", value: "/go/somewhere/else"}]
}, {
attributeName: "ping",
links: [
{type: "uri", value: "/analytics?page=pageA"},
{type: "uri", value: "/analytics?user=test"}
]
}]
}, {
selector: "li[contextmenu=menu1]",
attributes: [{
attributeName: "contextmenu",
links: [{type: "idref", value: "menu1"}]
}]
}, {
selector: "li[contextmenu=menu2]",
attributes: [{
attributeName: "contextmenu",
links: [{type: "idref", value: "menu2"}]
}]
}, {
selector: "li[contextmenu=menu3]",
attributes: [{
attributeName: "contextmenu",
links: [{type: "idref", value: "menu3"}]
}]
}, {
selector: "video",
attributes: [{
attributeName: "poster",
links: [{type: "uri", value: "doc_markup_tooltip.png"}]
}, {
attributeName: "src",
links: [{type: "uri", value: "code-rush.mp4"}]
}]
}, {
selector: "script",
attributes: [{
attributeName: "src",
links: [{type: "jsresource", value: "lib_jquery_1.0.js"}]
}]
}];
requestLongerTimeout(2);
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
for (let {selector, attributes} of TEST_DATA) {
info("Testing attributes on node " + selector);
yield selectNode(selector, inspector);
let {editor} = yield getContainerForSelector(selector, inspector);
for (let {attributeName, links} of attributes) {
info("Testing attribute " + attributeName);
let linkEls = editor.attrElements.get(attributeName)
.querySelectorAll(".link");
is(linkEls.length, links.length, "The right number of links were found");
for (let i = 0; i < links.length; i++) {
is(linkEls[i].dataset.type, links[i].type,
`Link ${i} has the right type`);
is(linkEls[i].textContent, links[i].value,
`Link ${i} has the right value`);
}
}
}
});

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";
// Tests that attributes are linkified correctly when attributes are updated
// and created.
const TEST_URL = URL_ROOT + "doc_markup_links.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Adding a contextmenu attribute to the body node");
yield addNewAttributes("body", "contextmenu=\"menu1\"", inspector);
info("Checking for links in the new attribute");
let {editor} = yield getContainerForSelector("body", inspector);
let linkEls = editor.attrElements.get("contextmenu")
.querySelectorAll(".link");
is(linkEls.length, 1, "There is one link in the contextmenu attribute");
is(linkEls[0].dataset.type, "idref", "The link has the right type");
is(linkEls[0].textContent, "menu1", "The link has the right value");
info("Editing the contextmenu attribute on the body node");
let nodeMutated = inspector.once("markupmutation");
let attr = editor.attrElements.get("contextmenu").querySelector(".editable");
setEditableFieldValue(attr, "contextmenu=\"menu2\"", inspector);
yield nodeMutated;
info("Checking for links in the updated attribute");
({editor} = yield getContainerForSelector("body", inspector));
linkEls = editor.attrElements.get("contextmenu").querySelectorAll(".link");
is(linkEls.length, 1, "There is one link in the contextmenu attribute");
is(linkEls[0].dataset.type, "idref", "The link has the right type");
is(linkEls[0].textContent, "menu2", "The link has the right value");
});

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";
// Tests that links appear correctly in attributes created in content.
const TEST_URL = URL_ROOT + "doc_markup_links.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("Adding a contextmenu attribute to the body node via the content");
let onMutated = inspector.once("markupmutation");
yield testActor.setAttribute("body", "contextmenu", "menu1");
yield onMutated;
info("Checking for links in the new attribute");
let {editor} = yield getContainerForSelector("body", inspector);
let linkEls = editor.attrElements.get("contextmenu")
.querySelectorAll(".link");
is(linkEls.length, 1, "There is one link in the contextmenu attribute");
is(linkEls[0].dataset.type, "idref", "The link has the right type");
is(linkEls[0].textContent, "menu1", "The link has the right value");
info("Editing the contextmenu attribute on the body node");
onMutated = inspector.once("markupmutation");
yield testActor.setAttribute("body", "contextmenu", "menu2");
yield onMutated;
info("Checking for links in the updated attribute");
({editor} = yield getContainerForSelector("body", inspector));
linkEls = editor.attrElements.get("contextmenu").querySelectorAll(".link");
is(linkEls.length, 1, "There is one link in the contextmenu attribute");
is(linkEls[0].dataset.type, "idref", "The link has the right type");
is(linkEls[0].textContent, "menu2", "The link has the right value");
});

View file

@ -0,0 +1,116 @@
/* 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 the contextual menu shows the right items when clicking on a link
// in an attribute.
const TEST_URL = URL_ROOT + "doc_markup_links.html";
const TOOLBOX_L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
// The test case array contains objects with the following properties:
// - selector: css selector for the node to select in the inspector
// - attributeName: name of the attribute to test
// - popupNodeSelector: css selector for the element inside the attribute
// element to use as the contextual menu anchor
// - isLinkFollowItemVisible: is the follow-link item expected to be displayed
// - isLinkCopyItemVisible: is the copy-link item expected to be displayed
// - linkFollowItemLabel: the expected label of the follow-link item
// - linkCopyItemLabel: the expected label of the copy-link item
const TEST_DATA = [{
selector: "link",
attributeName: "href",
popupNodeSelector: ".link",
isLinkFollowItemVisible: true,
isLinkCopyItemVisible: true,
linkFollowItemLabel: TOOLBOX_L10N.getStr(
"toolbox.viewCssSourceInStyleEditor.label"),
linkCopyItemLabel: INSPECTOR_L10N.getStr(
"inspector.menu.copyUrlToClipboard.label")
}, {
selector: "link[rel=icon]",
attributeName: "href",
popupNodeSelector: ".link",
isLinkFollowItemVisible: true,
isLinkCopyItemVisible: true,
linkFollowItemLabel: INSPECTOR_L10N.getStr(
"inspector.menu.openUrlInNewTab.label"),
linkCopyItemLabel: INSPECTOR_L10N.getStr(
"inspector.menu.copyUrlToClipboard.label")
}, {
selector: "link",
attributeName: "rel",
popupNodeSelector: ".attr-value",
isLinkFollowItemVisible: false,
isLinkCopyItemVisible: false
}, {
selector: "output",
attributeName: "for",
popupNodeSelector: ".link",
isLinkFollowItemVisible: true,
isLinkCopyItemVisible: false,
linkFollowItemLabel: INSPECTOR_L10N.getFormatStr(
"inspector.menu.selectElement.label", "name")
}, {
selector: "script",
attributeName: "src",
popupNodeSelector: ".link",
isLinkFollowItemVisible: true,
isLinkCopyItemVisible: true,
linkFollowItemLabel: TOOLBOX_L10N.getStr(
"toolbox.viewJsSourceInDebugger.label"),
linkCopyItemLabel: INSPECTOR_L10N.getStr(
"inspector.menu.copyUrlToClipboard.label")
}, {
selector: "p[for]",
attributeName: "for",
popupNodeSelector: ".attr-value",
isLinkFollowItemVisible: false,
isLinkCopyItemVisible: false
}];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
for (let test of TEST_DATA) {
info("Selecting test node " + test.selector);
yield selectNode(test.selector, inspector);
info("Finding the popupNode to anchor the context-menu to");
let {editor} = yield getContainerForSelector(test.selector, inspector);
let popupNode = editor.attrElements.get(test.attributeName)
.querySelector(test.popupNodeSelector);
ok(popupNode, "Found the popupNode in attribute " + test.attributeName);
info("Simulating a context click on the popupNode");
let allMenuItems = openContextMenuAndGetAllItems(inspector, {
target: popupNode,
});
let linkFollow = allMenuItems.find(i => i.id === "node-menu-link-follow");
let linkCopy = allMenuItems.find(i => i.id === "node-menu-link-copy");
// The contextual menu setup is async, because it needs to know if the
// inspector has the resolveRelativeURL method first. So call actorHasMethod
// here too to make sure the first call resolves first and the menu is
// properly setup.
yield inspector.target.actorHasMethod("inspector", "resolveRelativeURL");
is(linkFollow.visible, test.isLinkFollowItemVisible,
"The follow-link item display is correct");
is(linkCopy.visible, test.isLinkCopyItemVisible,
"The copy-link item display is correct");
if (test.isLinkFollowItemVisible) {
is(linkFollow.label, test.linkFollowItemLabel,
"the follow-link label is correct");
}
if (test.isLinkCopyItemVisible) {
is(linkCopy.label, test.linkCopyItemLabel,
"the copy-link label is correct");
}
}
});

View file

@ -0,0 +1,69 @@
/* 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 the contextual menu items shown when clicking on links in
// attributes actually do the right things.
const TEST_URL = URL_ROOT + "doc_markup_links.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Select a node with a URI attribute");
yield selectNode("video", inspector);
info("Set the popupNode to the node that contains the uri");
let {editor} = yield getContainerForSelector("video", inspector);
openContextMenuAndGetAllItems(inspector, {
target: editor.attrElements.get("poster").querySelector(".link"),
});
info("Follow the link and wait for the new tab to open");
let onTabOpened = once(gBrowser.tabContainer, "TabOpen");
inspector.onFollowLink();
let {target: tab} = yield onTabOpened;
yield BrowserTestUtils.browserLoaded(tab.linkedBrowser);
ok(true, "A new tab opened");
is(tab.linkedBrowser.currentURI.spec, URL_ROOT + "doc_markup_tooltip.png",
"The URL for the new tab is correct");
gBrowser.removeTab(tab);
info("Select a node with a IDREF attribute");
yield selectNode("label", inspector);
info("Set the popupNode to the node that contains the ref");
({editor} = yield getContainerForSelector("label", inspector));
openContextMenuAndGetAllItems(inspector, {
target: editor.attrElements.get("for").querySelector(".link"),
});
info("Follow the link and wait for the new node to be selected");
let onSelection = inspector.selection.once("new-node-front");
inspector.onFollowLink();
yield onSelection;
ok(true, "A new node was selected");
is(inspector.selection.nodeFront.id, "name", "The right node was selected");
info("Select a node with an invalid IDREF attribute");
yield selectNode("output", inspector);
info("Set the popupNode to the node that contains the ref");
({editor} = yield getContainerForSelector("output", inspector));
openContextMenuAndGetAllItems(inspector, {
target: editor.attrElements.get("for").querySelectorAll(".link")[2],
});
info("Try to follow the link and check that no new node were selected");
let onFailed = inspector.once("idref-attribute-link-failed");
inspector.onFollowLink();
yield onFailed;
ok(true, "The node selection failed");
is(inspector.selection.nodeFront.tagName.toLowerCase(), "output",
"The <output> node is still selected");
});

View file

@ -0,0 +1,53 @@
/* 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 the contextual menu items shown when clicking on linked attributes
// for <script> and <link> tags actually open the right tools.
const TEST_URL = URL_ROOT + "doc_markup_links.html";
add_task(function* () {
let {toolbox, inspector} = yield openInspectorForURL(TEST_URL);
info("Select a node with a cssresource attribute");
yield selectNode("link", inspector);
info("Set the popupNode to the node that contains the uri");
let {editor} = yield getContainerForSelector("link", inspector);
openContextMenuAndGetAllItems(inspector, {
target: editor.attrElements.get("href").querySelector(".link"),
});
info("Follow the link and wait for the style-editor to open");
let onStyleEditorReady = toolbox.once("styleeditor-ready");
inspector.onFollowLink();
yield onStyleEditorReady;
// No real need to test that the editor opened on the right file here as this
// is already tested in /framework/test/browser_toolbox_view_source_*
ok(true, "The style-editor was open");
info("Switch back to the inspector");
yield toolbox.selectTool("inspector");
info("Select a node with a jsresource attribute");
yield selectNode("script", inspector);
info("Set the popupNode to the node that contains the uri");
({editor} = yield getContainerForSelector("script", inspector));
openContextMenuAndGetAllItems(inspector, {
target: editor.attrElements.get("src").querySelector(".link"),
});
info("Follow the link and wait for the debugger to open");
let onDebuggerReady = toolbox.once("jsdebugger-ready");
inspector.onFollowLink();
yield onDebuggerReady;
// No real need to test that the debugger opened on the right file here as
// this is already tested in /framework/test/browser_toolbox_view_source_*
ok(true, "The debugger was open");
});

View file

@ -0,0 +1,109 @@
/* 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 a middle-click or meta/ctrl-click on links in attributes actually
// do follows the link.
const TEST_URL = URL_ROOT + "doc_markup_links.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Select a node with a URI attribute");
yield selectNode("video", inspector);
info("Find the link element from the markup-view");
let {editor} = yield getContainerForSelector("video", inspector);
let linkEl = editor.attrElements.get("poster").querySelector(".link");
info("Follow the link with middle-click and wait for the new tab to open");
yield followLinkWaitForTab(linkEl, false,
URL_ROOT + "doc_markup_tooltip.png");
info("Follow the link with meta/ctrl-click and wait for the new tab to open");
yield followLinkWaitForTab(linkEl, true,
URL_ROOT + "doc_markup_tooltip.png");
info("Select a node with a IDREF attribute");
yield selectNode("label", inspector);
info("Find the link element from the markup-view that contains the ref");
({editor} = yield getContainerForSelector("label", inspector));
linkEl = editor.attrElements.get("for").querySelector(".link");
info("Follow link with middle-click, wait for new node to be selected.");
yield followLinkWaitForNewNode(linkEl, false, inspector);
// We have to re-select the label as the link switched the currently selected
// node.
yield selectNode("label", inspector);
info("Follow link with ctrl/meta-click, wait for new node to be selected.");
yield followLinkWaitForNewNode(linkEl, true, inspector);
info("Select a node with an invalid IDREF attribute");
yield selectNode("output", inspector);
info("Find the link element from the markup-view that contains the ref");
({editor} = yield getContainerForSelector("output", inspector));
linkEl = editor.attrElements.get("for").querySelectorAll(".link")[2];
info("Try to follow link wiith middle-click, check no new node selected");
yield followLinkNoNewNode(linkEl, false, inspector);
info("Try to follow link wiith meta/ctrl-click, check no new node selected");
yield followLinkNoNewNode(linkEl, true, inspector);
});
function performMouseDown(linkEl, metactrl) {
let evt = linkEl.ownerDocument.createEvent("MouseEvents");
let button = -1;
if (metactrl) {
info("Performing Meta/Ctrl+Left Click");
button = 0;
} else {
info("Performing Middle Click");
button = 1;
}
evt.initMouseEvent("mousedown", true, true,
linkEl.ownerDocument.defaultView, 1, 0, 0, 0, 0, metactrl,
false, false, metactrl, button, null);
linkEl.dispatchEvent(evt);
}
function* followLinkWaitForTab(linkEl, isMetaClick, expectedTabURI) {
let onTabOpened = once(gBrowser.tabContainer, "TabOpen");
performMouseDown(linkEl, isMetaClick);
let {target} = yield onTabOpened;
yield BrowserTestUtils.browserLoaded(target.linkedBrowser);
ok(true, "A new tab opened");
is(target.linkedBrowser.currentURI.spec, expectedTabURI,
"The URL for the new tab is correct");
gBrowser.removeTab(target);
}
function* followLinkWaitForNewNode(linkEl, isMetaClick, inspector) {
let onSelection = inspector.selection.once("new-node-front");
performMouseDown(linkEl, isMetaClick);
yield onSelection;
ok(true, "A new node was selected");
is(inspector.selection.nodeFront.id, "name", "The right node was selected");
}
function* followLinkNoNewNode(linkEl, isMetaClick, inspector) {
let onFailed = inspector.once("idref-attribute-link-failed");
performMouseDown(linkEl, isMetaClick);
yield onFailed;
ok(true, "The node selection failed");
is(inspector.selection.nodeFront.tagName.toLowerCase(), "output",
"The <output> node is still selected");
}

View file

@ -0,0 +1,71 @@
/* 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 selecting an element with the 'Inspect Element' context
// menu during a page reload doesn't cause the markup view to become empty.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1036324
const server = createTestHTTPServer();
// Register a slow image handler so we can simulate a long time between
// a reload and the load event firing.
server.registerContentType("gif", "image/gif");
server.registerPathHandler("/slow.gif", function (metadata, response) {
info("Image has been requested");
response.processAsync();
setTimeout(() => {
info("Image is responding");
response.finish();
}, 500);
});
// Test page load events.
const TEST_URL = "data:text/html," +
"<!DOCTYPE html>" +
"<head><meta charset='utf-8' /></head>" +
"<body>" +
"<p>Slow script</p>" +
"<img src='http://localhost:" + server.identity.primaryPort + "/slow.gif' /></script>" +
"</body>" +
"</html>";
add_task(function* () {
let {inspector, testActor, tab} = yield openInspectorForURL(TEST_URL);
let domContentLoaded = waitForLinkedBrowserEvent(tab, "DOMContentLoaded");
let pageLoaded = waitForLinkedBrowserEvent(tab, "load");
ok(inspector.markup, "There is a markup view");
// Select an element while the tab is in the middle of a slow reload.
testActor.eval("location.reload()");
yield domContentLoaded;
yield chooseWithInspectElementContextMenu("img", testActor);
yield pageLoaded;
yield inspector.once("markuploaded");
yield waitForMultipleChildrenUpdates(inspector);
ok(inspector.markup, "There is a markup view");
is(inspector.markup._elt.children.length, 1, "The markup view is rendering");
});
function* chooseWithInspectElementContextMenu(selector, testActor) {
yield BrowserTestUtils.synthesizeMouseAtCenter(selector, {
type: "contextmenu",
button: 2
}, gBrowser.selectedBrowser);
yield EventUtils.synthesizeKey("Q", {});
}
function waitForLinkedBrowserEvent(tab, event) {
let def = defer();
tab.linkedBrowser.addEventListener(event, function cb() {
tab.linkedBrowser.removeEventListener(event, cb, true);
def.resolve();
}, true);
return def.promise;
}

View file

@ -0,0 +1,340 @@
/* 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 various mutations to the dom update the markup view correctly.
const TEST_URL = URL_ROOT + "doc_markup_mutation.html";
// Mutation tests. Each entry in the array has the following properties:
// - desc: for logging only
// - numMutations: how many mutations are expected to come happen due to the
// test case. Defaults to 1 if not set.
// - test: a function supposed to mutate the DOM
// - check: a function supposed to test that the mutation was handled
const TEST_DATA = [
{
desc: "Adding an attribute",
test: function* (testActor) {
yield testActor.setAttribute("#node1", "newattr", "newattrval");
},
check: function* (inspector) {
let {editor} = yield getContainerForSelector("#node1", inspector);
ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
return attr.textContent.trim() === "newattr=\"newattrval\""
&& attr.dataset.value === "newattrval"
&& attr.dataset.attr === "newattr";
}), "newattr attribute found");
}
},
{
desc: "Removing an attribute",
test: function* (testActor) {
yield testActor.removeAttribute("#node1", "newattr");
},
check: function* (inspector) {
let {editor} = yield getContainerForSelector("#node1", inspector);
ok(![...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
return attr.textContent.trim() === "newattr=\"newattrval\"";
}), "newattr attribute removed");
}
},
{
desc: "Re-adding an attribute",
test: function* (testActor) {
yield testActor.setAttribute("#node1", "newattr", "newattrval");
},
check: function* (inspector) {
let {editor} = yield getContainerForSelector("#node1", inspector);
ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
return attr.textContent.trim() === "newattr=\"newattrval\""
&& attr.dataset.value === "newattrval"
&& attr.dataset.attr === "newattr";
}), "newattr attribute found");
}
},
{
desc: "Changing an attribute",
test: function* (testActor) {
yield testActor.setAttribute("#node1", "newattr", "newattrchanged");
},
check: function* (inspector) {
let {editor} = yield getContainerForSelector("#node1", inspector);
ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
return attr.textContent.trim() === "newattr=\"newattrchanged\""
&& attr.dataset.value === "newattrchanged"
&& attr.dataset.attr === "newattr";
}), "newattr attribute found");
}
},
{
desc: "Adding another attribute does not rerender unchanged attributes",
test: function* (testActor, inspector) {
let {editor} = yield getContainerForSelector("#node1", inspector);
// This test checks the impact on the markup-view nodes after setting attributes on
// content nodes.
info("Expect attribute-container for 'new-attr' from the previous test");
let attributeContainer = editor.attrList.querySelector("[data-attr=newattr]");
ok(attributeContainer, "attribute-container for 'newattr' found");
info("Set a flag on the attribute-container to check after the mutation");
attributeContainer.beforeMutationFlag = true;
info("Add the attribute 'otherattr' on the content node to trigger the mutation");
yield testActor.setAttribute("#node1", "otherattr", "othervalue");
},
check: function* (inspector) {
let {editor} = yield getContainerForSelector("#node1", inspector);
info("Check the attribute-container for the new attribute mutation was created");
let otherAttrContainer = editor.attrList.querySelector("[data-attr=otherattr]");
ok(otherAttrContainer, "attribute-container for 'otherattr' found");
info("Check the attribute-container for 'new-attr' is the same node as earlier.");
let newAttrContainer = editor.attrList.querySelector("[data-attr=newattr]");
ok(newAttrContainer, "attribute-container for 'newattr' found");
ok(newAttrContainer.beforeMutationFlag, "attribute-container same as earlier");
}
},
{
desc: "Adding ::after element",
numMutations: 2,
test: function* (testActor) {
yield testActor.eval(`
let node1 = content.document.querySelector("#node1");
node1.classList.add("pseudo");
`);
},
check: function* (inspector) {
let {children} = yield getContainerForSelector("#node1", inspector);
is(children.childNodes.length, 2,
"Node1 now has 2 children (text child and ::after");
}
},
{
desc: "Removing ::after element",
numMutations: 2,
test: function* (testActor) {
yield testActor.eval(`
let node1 = content.document.querySelector("#node1");
node1.classList.remove("pseudo");
`);
},
check: function* (inspector) {
let container = yield getContainerForSelector("#node1", inspector);
ok(container.inlineTextChild, "Has single text child.");
}
},
{
desc: "Updating the text-content",
test: function* (testActor) {
yield testActor.setProperty("#node1", "textContent", "newtext");
},
check: function* (inspector) {
let container = yield getContainerForSelector("#node1", inspector);
ok(container.inlineTextChild, "Has single text child.");
ok(!container.canExpand, "Can't expand container with inlineTextChild.");
ok(!container.inlineTextChild.canExpand, "Can't expand inlineTextChild.");
is(container.editor.elt.querySelector(".text").textContent.trim(),
"newtext", "Single text child editor updated.");
}
},
{
desc: "Adding a second text child",
test: function* (testActor) {
yield testActor.eval(`
let node1 = content.document.querySelector("#node1");
let newText = node1.ownerDocument.createTextNode("more");
node1.appendChild(newText);
`);
},
check: function* (inspector) {
let container = yield getContainerForSelector("#node1", inspector);
ok(!container.inlineTextChild, "Does not have single text child.");
ok(container.canExpand, "Can expand container with child nodes.");
ok(container.editor.elt.querySelector(".text") == null,
"Single text child editor removed.");
},
},
{
desc: "Go from 2 to 1 text child",
test: function* (testActor) {
yield testActor.setProperty("#node1", "textContent", "newtext");
},
check: function* (inspector) {
let container = yield getContainerForSelector("#node1", inspector);
ok(container.inlineTextChild, "Has single text child.");
ok(!container.canExpand, "Can't expand container with inlineTextChild.");
ok(!container.inlineTextChild.canExpand, "Can't expand inlineTextChild.");
ok(container.editor.elt.querySelector(".text").textContent.trim(),
"newtext", "Single text child editor updated.");
},
},
{
desc: "Removing an only text child",
test: function* (testActor) {
yield testActor.setProperty("#node1", "innerHTML", "");
},
check: function* (inspector) {
let container = yield getContainerForSelector("#node1", inspector);
ok(!container.inlineTextChild, "Does not have single text child.");
ok(!container.canExpand, "Can't expand empty container.");
ok(container.editor.elt.querySelector(".text") == null,
"Single text child editor removed.");
},
},
{
desc: "Go from 0 to 1 text child",
test: function* (testActor) {
yield testActor.setProperty("#node1", "textContent", "newtext");
},
check: function* (inspector) {
let container = yield getContainerForSelector("#node1", inspector);
ok(container.inlineTextChild, "Has single text child.");
ok(!container.canExpand, "Can't expand container with inlineTextChild.");
ok(!container.inlineTextChild.canExpand, "Can't expand inlineTextChild.");
ok(container.editor.elt.querySelector(".text").textContent.trim(),
"newtext", "Single text child editor updated.");
},
},
{
desc: "Updating the innerHTML",
test: function* (testActor) {
yield testActor.setProperty("#node2", "innerHTML",
"<div><span>foo</span></div>");
},
check: function* (inspector) {
let container = yield getContainerForSelector("#node2", inspector);
let openTags = container.children.querySelectorAll(".open .tag");
is(openTags.length, 2, "There are 2 tags in node2");
is(openTags[0].textContent.trim(), "div", "The first tag is a div");
is(openTags[1].textContent.trim(), "span", "The second tag is a span");
is(container.children.querySelector(".text").textContent.trim(), "foo",
"The span's textcontent is correct");
}
},
{
desc: "Removing child nodes",
test: function* (testActor) {
yield testActor.eval(`
let node4 = content.document.querySelector("#node4");
while (node4.firstChild) {
node4.removeChild(node4.firstChild);
}
`);
},
check: function* (inspector) {
let {children} = yield getContainerForSelector("#node4", inspector);
is(children.innerHTML, "", "Children have been removed");
}
},
{
desc: "Appending a child to a different parent",
test: function* (testActor) {
yield testActor.eval(`
let node17 = content.document.querySelector("#node17");
let node2 = content.document.querySelector("#node2");
node2.appendChild(node17);
`);
},
check: function* (inspector) {
let {children} = yield getContainerForSelector("#node16", inspector);
is(children.innerHTML, "",
"Node17 has been removed from its node16 parent");
let container = yield getContainerForSelector("#node2", inspector);
let openTags = container.children.querySelectorAll(".open .tag");
is(openTags.length, 3, "There are now 3 tags in node2");
is(openTags[2].textContent.trim(), "p", "The third tag is node17");
}
},
{
desc: "Swapping a parent and child element, putting them in the same tree",
// body
// node1
// node18
// node19
// node20
// node21
// will become:
// body
// node1
// node20
// node21
// node18
// node19
test: function* (testActor) {
yield testActor.eval(`
let node18 = content.document.querySelector("#node18");
let node20 = content.document.querySelector("#node20");
let node1 = content.document.querySelector("#node1");
node1.appendChild(node20);
node20.appendChild(node18);
`);
},
check: function* (inspector) {
yield inspector.markup.expandAll();
let {children} = yield getContainerForSelector("#node1", inspector);
is(children.childNodes.length, 2,
"Node1 now has 2 children (textnode and node20)");
let node20 = children.childNodes[1];
let node20Children = node20.container.children;
is(node20Children.childNodes.length, 2,
"Node20 has 2 children (21 and 18)");
let node21 = node20Children.childNodes[0];
is(node21.container.editor.elt.querySelector(".text").textContent.trim(),
"line21", "Node21 has a single text child");
let node18 = node20Children.childNodes[1];
is(node18.querySelector(".open .attreditor .attr-value")
.textContent.trim(),
"node18", "Node20's second child is indeed node18");
}
}
];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("Expanding all markup-view nodes");
yield inspector.markup.expandAll();
for (let {desc, test, check, numMutations} of TEST_DATA) {
info("Starting test: " + desc);
numMutations = numMutations || 1;
info("Executing the test markup mutation");
// If a test expects more than one mutation it may come through in a single
// event or possibly in multiples.
let def = defer();
let seenMutations = 0;
inspector.on("markupmutation", function onmutation(e, mutations) {
seenMutations += mutations.length;
info("Receieved " + seenMutations +
" mutations, expecting at least " + numMutations);
if (seenMutations >= numMutations) {
inspector.off("markupmutation", onmutation);
def.resolve();
}
});
yield test(testActor, inspector);
yield def.promise;
info("Expanding all markup-view nodes to make sure new nodes are imported");
yield inspector.markup.expandAll();
info("Checking the markup-view content");
yield check(inspector);
}
});

View file

@ -0,0 +1,159 @@
/* 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 markup-containers in the markup-view do flash when their
// corresponding DOM nodes mutate
// Have to use the same timer functions used by the inspector.
const {clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
const TEST_URL = URL_ROOT + "doc_markup_flashing.html";
// The test data contains a list of mutations to test.
// Each item is an object:
// - desc: a description of the test step, for better logging
// - mutate: a generator function that should make changes to the content DOM
// - attribute: if set, the test will expect the corresponding attribute to
// flash instead of the whole node
// - flashedNode: [optional] the css selector of the node that is expected to
// flash in the markup-view as a result of the mutation.
// If missing, the rootNode (".list") will be expected to flash
const TEST_DATA = [{
desc: "Adding a new node should flash the new node",
mutate: function* (testActor) {
yield testActor.eval(`
let newLi = content.document.createElement("LI");
newLi.textContent = "new list item";
content.document.querySelector(".list").appendChild(newLi);
`);
},
flashedNode: ".list li:nth-child(3)"
}, {
desc: "Removing a node should flash its parent",
mutate: function* (testActor) {
yield testActor.eval(`
let root = content.document.querySelector(".list");
root.removeChild(root.lastElementChild);
`);
}
}, {
desc: "Re-appending an existing node should only flash this node",
mutate: function* (testActor) {
yield testActor.eval(`
let root = content.document.querySelector(".list");
root.appendChild(root.firstElementChild);
`);
},
flashedNode: ".list .item:last-child"
}, {
desc: "Adding an attribute should flash the attribute",
attribute: "test-name",
mutate: function* (testActor) {
yield testActor.setAttribute(".list", "test-name", "value-" + Date.now());
}
}, {
desc: "Adding an attribute with css reserved characters should flash the " +
"attribute",
attribute: "one:two",
mutate: function* (testActor) {
yield testActor.setAttribute(".list", "one:two", "value-" + Date.now());
}
}, {
desc: "Editing an attribute should flash the attribute",
attribute: "class",
mutate: function* (testActor) {
yield testActor.setAttribute(".list", "class", "list value-" + Date.now());
}
}, {
desc: "Multiple changes to an attribute should flash the attribute",
attribute: "class",
mutate: function* (testActor) {
yield testActor.eval(`
let root = content.document.querySelector(".list");
root.removeAttribute("class");
root.setAttribute("class", "list value-" + Date.now());
root.setAttribute("class", "list value-" + Date.now());
root.removeAttribute("class");
root.setAttribute("class", "list value-" + Date.now());
root.setAttribute("class", "list value-" + Date.now());
`);
}
}, {
desc: "Removing an attribute should flash the node",
mutate: function* (testActor) {
yield testActor.eval(`
let root = content.document.querySelector(".list");
root.removeAttribute("class");
`);
}
}];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
// Make sure mutated nodes flash for a very long time so we can more easily
// assert they do
inspector.markup.CONTAINER_FLASHING_DURATION = 1000 * 60 * 60;
info("Getting the <ul.list> root node to test mutations on");
let rootNodeFront = yield getNodeFront(".list", inspector);
info("Selecting the last element of the root node before starting");
yield selectNode(".list .item:nth-child(2)", inspector);
for (let {mutate, flashedNode, desc, attribute} of TEST_DATA) {
info("Starting test: " + desc);
info("Mutating the DOM and listening for markupmutation event");
let onMutation = inspector.once("markupmutation");
yield mutate(testActor);
let mutations = yield onMutation;
info("Wait for the breadcrumbs widget to update if it needs to");
if (inspector.breadcrumbs._hasInterestingMutations(mutations)) {
yield inspector.once("breadcrumbs-updated");
}
info("Asserting that the correct markup-container is flashing");
let flashingNodeFront = rootNodeFront;
if (flashedNode) {
flashingNodeFront = yield getNodeFront(flashedNode, inspector);
}
if (attribute) {
yield assertAttributeFlashing(flashingNodeFront, attribute, inspector);
} else {
yield assertNodeFlashing(flashingNodeFront, inspector);
}
}
});
function* assertNodeFlashing(nodeFront, inspector) {
let container = getContainerForNodeFront(nodeFront, inspector);
ok(container, "Markup container for node found");
ok(container.tagState.classList.contains("theme-bg-contrast"),
"Markup container for node is flashing");
// Clear the mutation flashing timeout now that we checked the node was
// flashing.
clearTimeout(container._flashMutationTimer);
container._flashMutationTimer = null;
container.tagState.classList.remove("theme-bg-contrast");
}
function* assertAttributeFlashing(nodeFront, attribute, inspector) {
let container = getContainerForNodeFront(nodeFront, inspector);
ok(container, "Markup container for node found");
ok(container.editor.attrElements.get(attribute),
"Attribute exists on editor");
let attributeElement = container.editor.getAttributeElement(attribute);
ok(attributeElement.classList.contains("theme-bg-contrast"),
"Element for " + attribute + " attribute is flashing");
attributeElement.classList.remove("theme-bg-contrast");
}

View file

@ -0,0 +1,147 @@
/* 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 markup-view nodes can be navigated to with the keyboard
const TEST_URL = URL_ROOT + "doc_markup_navigation.html";
const TEST_DATA = [
["pageup", "*doctype*"],
["down", "html"],
["down", "head"],
["down", "body"],
["down", "node0"],
["right", "node0"],
["down", "node1"],
["down", "node2"],
["down", "node3"],
["down", "*comment*"],
["down", "node4"],
["right", "node4"],
["down", "*text*"],
["down", "node5"],
["down", "*text*"],
["down", "node6"],
["down", "*text*"],
["down", "*comment*"],
["down", "node7"],
["right", "node7"],
["down", "*text*"],
["down", "node8"],
["left", "node7"],
["left", "node7"],
["right", "node7"],
["right", "*text*"],
["down", "node8"],
["down", "*text*"],
["down", "node9"],
["down", "*text*"],
["down", "node10"],
["down", "*text*"],
["down", "node11"],
["down", "*text*"],
["down", "node12"],
["right", "node12"],
["down", "*text*"],
["down", "node13"],
["down", "node14"],
["down", "node15"],
["down", "node15"],
["down", "node15"],
["up", "node14"],
["up", "node13"],
["up", "*text*"],
["up", "node12"],
["left", "node12"],
["down", "node14"],
["home", "*doctype*"],
["pagedown", "*text*"],
["down", "node5"],
["down", "*text*"],
["down", "node6"],
["down", "*text*"],
["down", "*comment*"],
["down", "node7"],
["left", "node7"],
["down", "*text*"],
["down", "node9"],
["down", "*text*"],
["down", "node10"],
["pageup", "*text*"],
["pageup", "*doctype*"],
["down", "html"],
["left", "html"],
["down", "head"]
];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Making sure the markup-view frame is focused");
inspector.markup._frame.focus();
info("Starting to iterate through the test data");
for (let [key, className] of TEST_DATA) {
info("Testing step: " + key + " to navigate to " + className);
pressKey(key);
info("Making sure markup-view children get updated");
yield waitForChildrenUpdated(inspector);
info("Checking the right node is selected");
checkSelectedNode(key, className, inspector);
}
// In theory, we should wait for the inspector-updated event at each iteration
// of the previous loop where we expect the current node to change (because
// changing the current node ends up refreshing the rule-view, breadcrumbs,
// ...), but this would make this test a *lot* slower. Instead, having a final
// catch-all event works too.
yield inspector.once("inspector-updated");
});
function pressKey(key) {
switch (key) {
case "right":
EventUtils.synthesizeKey("VK_RIGHT", {});
break;
case "down":
EventUtils.synthesizeKey("VK_DOWN", {});
break;
case "left":
EventUtils.synthesizeKey("VK_LEFT", {});
break;
case "up":
EventUtils.synthesizeKey("VK_UP", {});
break;
case "pageup":
EventUtils.synthesizeKey("VK_PAGE_UP", {});
break;
case "pagedown":
EventUtils.synthesizeKey("VK_PAGE_DOWN", {});
break;
case "home":
EventUtils.synthesizeKey("VK_HOME", {});
break;
}
}
function checkSelectedNode(key, className, inspector) {
let node = inspector.selection.nodeFront;
if (className == "*comment*") {
is(node.nodeType, Node.COMMENT_NODE,
"Found a comment after pressing " + key);
} else if (className == "*text*") {
is(node.nodeType, Node.TEXT_NODE,
"Found text after pressing " + key);
} else if (className == "*doctype*") {
is(node.nodeType, Node.DOCUMENT_TYPE_NODE,
"Found the doctype after pressing " + key);
} else {
is(node.className, className,
"Found node: " + className + " after pressing " + key);
}
}

View file

@ -0,0 +1,28 @@
/* 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 element node name in the markupview
const TEST_URL = URL_ROOT + "doc_markup_html_mixed_case.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
// Get and open the svg element to show its children
let svgNodeFront = yield getNodeFront("svg", inspector);
yield inspector.markup.expandNode(svgNodeFront);
yield waitForMultipleChildrenUpdates(inspector);
let clipPathContainer = yield getContainerForSelector("clipPath", inspector);
info("Checking the clipPath element");
ok(clipPathContainer.editor.tag.textContent === "clipPath",
"clipPath node name is not lowercased");
let divContainer = yield getContainerForSelector("div", inspector);
info("Checking the div element");
ok(divContainer.editor.tag.textContent === "div",
"div node name is lowercased");
});

View file

@ -0,0 +1,43 @@
/* 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 namespaced element node names in the markupview.
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);
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URI);
// Get and open the svg element to show its children.
let svgNodeFront = yield getNodeFront("svg", inspector);
yield inspector.markup.expandNode(svgNodeFront);
yield waitForMultipleChildrenUpdates(inspector);
let clipPathContainer = yield getContainerForSelector("clipPath", inspector);
info("Checking the clipPath element");
ok(clipPathContainer.editor.tag.textContent === "svg:clipPath",
"svg:clipPath node is correctly displayed");
let circlePathContainer = yield getContainerForSelector("circle", inspector);
info("Checking the circle element");
ok(circlePathContainer.editor.tag.textContent === "svg:circle",
"svg:circle node is correctly displayed");
});

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";
// Tests that nodes that are not displayed appear differently in the markup-view
// when these nodes are imported in the view.
// Note that nodes inside a display:none parent are obviously not displayed too
// but the markup-view uses css inheritance to mark those as hidden instead of
// having to visit each and every child of a hidden node. So there's no sense
// testing children nodes.
const TEST_URL = URL_ROOT + "doc_markup_not_displayed.html";
const TEST_DATA = [
{selector: "#normal-div", isDisplayed: true},
{selector: "head", isDisplayed: false},
{selector: "#display-none", isDisplayed: false},
{selector: "#hidden-true", isDisplayed: false},
{selector: "#visibility-hidden", isDisplayed: true},
{selector: "#hidden-via-hide-shortcut", isDisplayed: false},
];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
for (let {selector, isDisplayed} of TEST_DATA) {
info("Getting node " + selector);
let nodeFront = yield getNodeFront(selector, inspector);
let container = getContainerForNodeFront(nodeFront, inspector);
is(!container.elt.classList.contains("not-displayed"), isDisplayed,
`The container for ${selector} is marked as displayed ${isDisplayed}`);
}
});

View file

@ -0,0 +1,150 @@
/* 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 nodes are marked as displayed and not-displayed dynamically, when
// their display changes
const TEST_URL = URL_ROOT + "doc_markup_not_displayed.html";
const TEST_DATA = [
{
desc: "Hiding a node by creating a new stylesheet",
selector: "#normal-div",
before: true,
changeStyle: function* (testActor) {
yield testActor.eval(`
let div = content.document.createElement("div");
div.id = "new-style";
div.innerHTML = "<style>#normal-div {display:none;}</style>";
content.document.body.appendChild(div);
`);
},
after: false
},
{
desc: "Showing a node by deleting an existing stylesheet",
selector: "#normal-div",
before: false,
changeStyle: function* (testActor) {
yield testActor.eval(`
content.document.getElementById("new-style").remove();
`);
},
after: true
},
{
desc: "Hiding a node by changing its style property",
selector: "#display-none",
before: false,
changeStyle: function* (testActor) {
yield testActor.eval(`
let node = content.document.querySelector("#display-none");
node.style.display = "block";
`);
},
after: true
},
{
desc: "Showing a node by removing its hidden attribute",
selector: "#hidden-true",
before: false,
changeStyle: function* (testActor) {
yield testActor.eval(`
content.document.querySelector("#hidden-true")
.removeAttribute("hidden");
`);
},
after: true
},
{
desc: "Hiding a node by adding a hidden attribute",
selector: "#hidden-true",
before: true,
changeStyle: function* (testActor) {
yield testActor.setAttribute("#hidden-true", "hidden", "true");
},
after: false
},
{
desc: "Showing a node by changin a stylesheet's rule",
selector: "#hidden-via-stylesheet",
before: false,
changeStyle: function* (testActor) {
yield testActor.eval(`
content.document.styleSheets[0]
.cssRules[0].style
.setProperty("display", "inline");
`);
},
after: true
},
{
desc: "Hiding a node by adding a new rule to a stylesheet",
selector: "#hidden-via-stylesheet",
before: true,
changeStyle: function* (testActor) {
yield testActor.eval(`
content.document.styleSheets[0].insertRule(
"#hidden-via-stylesheet {display: none;}", 1);
`);
},
after: false
},
{
desc: "Hiding a node by adding a class that matches an existing rule",
selector: "#normal-div",
before: true,
changeStyle: function* (testActor) {
yield testActor.eval(`
content.document.styleSheets[0].insertRule(
".a-new-class {display: none;}", 2);
content.document.querySelector("#normal-div")
.classList.add("a-new-class");
`);
},
after: false
}
];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
for (let data of TEST_DATA) {
info("Running test case: " + data.desc);
yield runTestData(inspector, testActor, data);
}
});
function* runTestData(inspector, testActor,
{selector, before, changeStyle, after}) {
info("Getting the " + selector + " test node");
let nodeFront = yield getNodeFront(selector, inspector);
let container = getContainerForNodeFront(nodeFront, inspector);
is(!container.elt.classList.contains("not-displayed"), before,
"The container is marked as " + (before ? "shown" : "hidden"));
info("Listening for the display-change event");
let onDisplayChanged = defer();
inspector.markup.walker.once("display-change", onDisplayChanged.resolve);
info("Making style changes");
yield changeStyle(testActor);
let nodes = yield onDisplayChanged.promise;
info("Verifying that the list of changed nodes include our container");
ok(nodes.length, "The display-change event was received with a nodes");
let foundContainer = false;
for (let node of nodes) {
if (getContainerForNodeFront(node, inspector) === container) {
foundContainer = true;
break;
}
}
ok(foundContainer, "Container is part of the list of changed nodes");
is(!container.elt.classList.contains("not-displayed"), after,
"The container is marked as " + (after ? "shown" : "hidden"));
}

View file

@ -0,0 +1,86 @@
/* 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 the markup view loads only as many nodes as specified by the
// devtools.markup.pagesize preference.
Services.prefs.setIntPref("devtools.markup.pagesize", 5);
const TEST_URL = URL_ROOT + "doc_markup_pagesize_01.html";
const TEST_DATA = [{
desc: "Select the last item",
selector: "#z",
expected: "*more*vwxyz"
}, {
desc: "Select the first item",
selector: "#a",
expected: "abcde*more*"
}, {
desc: "Select the last item",
selector: "#z",
expected: "*more*vwxyz"
}, {
desc: "Select an already-visible item",
selector: "#v",
// Because "v" was already visible, we shouldn't have loaded
// a different page.
expected: "*more*vwxyz"
}, {
desc: "Verify childrenDirty reloads the page",
selector: "#w",
forceReload: true,
// But now that we don't already have a loaded page, selecting
// w should center around w.
expected: "*more*uvwxy*more*"
}];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Start iterating through the test data");
for (let step of TEST_DATA) {
info("Start test: " + step.desc);
if (step.forceReload) {
yield forceReload(inspector);
}
info("Selecting the node that corresponds to " + step.selector);
yield selectNode(step.selector, inspector);
info("Checking that the right nodes are shwon");
yield assertChildren(step.expected, inspector);
}
info("Checking that clicking the more button loads everything");
yield clickShowMoreNodes(inspector);
yield inspector.markup._waitForChildren();
yield assertChildren("abcdefghijklmnopqrstuvwxyz", inspector);
});
function* assertChildren(expected, inspector) {
let container = yield getContainerForSelector("body", inspector);
let found = "";
for (let child of container.children.children) {
if (child.classList.contains("more-nodes")) {
found += "*more*";
} else {
found += child.container.node.getAttribute("id");
}
}
is(found, expected, "Got the expected children.");
}
function* forceReload(inspector) {
let container = yield getContainerForSelector("body", inspector);
container.childrenDirty = true;
}
function* clickShowMoreNodes(inspector) {
let container = yield getContainerForSelector("body", inspector);
let button = container.elt.querySelector("button");
let win = button.ownerDocument.defaultView;
EventUtils.sendMouseEvent({type: "click"}, button, win);
}

View file

@ -0,0 +1,47 @@
/* 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 the markup view loads only as many nodes as specified
// by the devtools.markup.pagesize preference and that pressing the "show all
// nodes" actually shows the nodes
const TEST_URL = URL_ROOT + "doc_markup_pagesize_02.html";
// Make sure nodes are hidden when there are more than 5 in a row
Services.prefs.setIntPref("devtools.markup.pagesize", 5);
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("Selecting the UL node");
yield clickContainer("ul", inspector);
info("Reloading the page with the UL node selected will expand its children");
yield reloadPage(inspector, testActor);
yield inspector.markup._waitForChildren();
info("Click on the 'show all nodes' button in the UL's list of children");
yield showAllNodes(inspector);
yield assertAllNodesAreVisible(inspector, testActor);
});
function* showAllNodes(inspector) {
let container = yield getContainerForSelector("ul", inspector);
let button = container.elt.querySelector("button");
ok(button, "All nodes button is here");
let win = button.ownerDocument.defaultView;
EventUtils.sendMouseEvent({type: "click"}, button, win);
yield inspector.markup._waitForChildren();
}
function* assertAllNodesAreVisible(inspector, testActor) {
let container = yield getContainerForSelector("ul", inspector);
ok(!container.elt.querySelector("button"),
"All nodes button isn't here anymore");
let numItems = yield testActor.getNumberOfElementMatches("ul > *");
is(container.children.childNodes.length, numItems);
}

View file

@ -0,0 +1,28 @@
/* 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 confirms that XUL attributes don't show up as empty
// attributes after being deleted
const TEST_URL = URL_ROOT + "doc_markup_xul.xul";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
let panelFront = yield getNodeFront("#test", inspector);
ok(panelFront.hasAttribute("id"),
"panelFront has id attribute in the beginning");
info("Removing panel's id attribute");
let onMutation = inspector.once("markupmutation");
yield testActor.removeAttribute("#test", "id");
info("Waiting for markupmutation");
yield onMutation;
is(panelFront.hasAttribute("id"), false,
"panelFront doesn't have id attribute anymore");
});

View file

@ -0,0 +1,51 @@
/* 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 searching for nodes using the selector-search input expands and
// selects the right nodes in the markup-view, even when those nodes are deeply
// nested (and therefore not attached yet when the markup-view is initialized).
const TEST_URL = URL_ROOT + "doc_markup_search.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
let container = yield getContainerForSelector("em", inspector);
ok(!container, "The <em> tag isn't present yet in the markup-view");
// Searching for the innermost element first makes sure that the inspector
// back-end is able to attach the resulting node to the tree it knows at the
// moment. When the inspector is started, the <body> is the default selected
// node, and only the parents up to the ROOT are known, and its direct
// children.
info("searching for the innermost child: <em>");
yield searchFor("em", inspector);
container = yield getContainerForSelector("em", inspector);
ok(container, "The <em> tag is now imported in the markup-view");
let nodeFront = yield getNodeFront("em", inspector);
is(inspector.selection.nodeFront, nodeFront,
"The <em> tag is the currently selected node");
info("searching for other nodes too");
for (let node of ["span", "li", "ul"]) {
yield searchFor(node, inspector);
nodeFront = yield getNodeFront(node, inspector);
is(inspector.selection.nodeFront, nodeFront,
"The <" + node + "> tag is the currently selected node");
}
});
function* searchFor(selector, inspector) {
let onNewNodeFront = inspector.selection.once("new-node-front");
searchUsingSelectorSearch(selector, inspector);
yield onNewNodeFront;
yield inspector.once("inspector-updated");
}

View file

@ -0,0 +1,68 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_attributes_test_runner.js */
"use strict";
// Test editing various markup-containers' attribute fields
loadHelperScript("helper_attributes_test_runner.js");
const TEST_URL = URL_ROOT + "doc_markup_edit.html";
var TEST_DATA = [{
desc: "Change an attribute",
node: "#node1",
originalAttributes: {
id: "node1",
class: "node1"
},
name: "class",
value: 'class="changednode1"',
expectedAttributes: {
id: "node1",
class: "changednode1"
}
}, {
desc: "Try changing an attribute to a quote (\") - this should result " +
"in it being set to an empty string",
node: "#node22",
originalAttributes: {
id: "node22",
class: "unchanged"
},
name: "class",
value: 'class="""',
expectedAttributes: {
id: "node22",
class: ""
}
}, {
desc: "Remove an attribute",
node: "#node4",
originalAttributes: {
id: "node4",
class: "node4"
},
name: "class",
value: "",
expectedAttributes: {
id: "node4"
}
}, {
desc: "Try add attributes by adding to an existing attribute's entry",
node: "#node24",
originalAttributes: {
id: "node24"
},
name: "id",
value: 'id="node24" class="""',
expectedAttributes: {
id: "node24",
class: ""
}
}];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
yield runEditAttributesTests(TEST_DATA, inspector, testActor);
});

View file

@ -0,0 +1,44 @@
/* 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 an existing attribute can be modified
const TEST_URL = `data:text/html,
<div id='test-div'>Test modifying my ID attribute</div>`;
add_task(function* () {
info("Opening the inspector on the test page");
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("Selecting the test node");
yield focusNode("#test-div", inspector);
info("Verify attributes, only ID should be there for now");
yield assertAttributes("#test-div", {
id: "test-div"
}, testActor);
info("Focus the ID attribute and change its content");
let {editor} = yield getContainerForSelector("#test-div", inspector);
let attr = editor.attrElements.get("id").querySelector(".editable");
let mutated = inspector.once("markupmutation");
setEditableFieldValue(attr,
attr.textContent + ' class="newclass" style="color:green"', inspector);
yield mutated;
info("Verify attributes, should have ID, class and style");
yield assertAttributes("#test-div", {
id: "test-div",
class: "newclass",
style: "color:green"
}, testActor);
info("Trying to undo the change");
yield undoChange(inspector);
yield assertAttributes("#test-div", {
id: "test-div"
}, testActor);
});

View file

@ -0,0 +1,51 @@
/* 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 a node's tagname can be edited in the markup-view
const TEST_URL = `data:text/html;charset=utf-8,
<div id='retag-me'><div id='retag-me-2'></div></div>`;
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
yield inspector.markup.expandAll();
info("Selecting the test node");
yield focusNode("#retag-me", inspector);
info("Getting the markup-container for the test node");
let container = yield getContainerForSelector("#retag-me", inspector);
ok(container.expanded, "The container is expanded");
let parentInfo = yield testActor.getNodeInfo("#retag-me");
is(parentInfo.tagName.toLowerCase(), "div",
"We've got #retag-me element, it's a DIV");
is(parentInfo.numChildren, 1, "#retag-me has one child");
let childInfo = yield testActor.getNodeInfo("#retag-me > *");
is(childInfo.attributes[0].value, "retag-me-2",
"#retag-me's only child is #retag-me-2");
info("Changing #retag-me's tagname in the markup-view");
let mutated = inspector.once("markupmutation");
let tagEditor = container.editor.tag;
setEditableFieldValue(tagEditor, "p", inspector);
yield mutated;
info("Checking that the markup-container exists and is correct");
container = yield getContainerForSelector("#retag-me", inspector);
ok(container.expanded, "The container is still expanded");
ok(container.selected, "The container is still selected");
info("Checking that the tagname change was done");
parentInfo = yield testActor.getNodeInfo("#retag-me");
is(parentInfo.tagName.toLowerCase(), "p",
"The #retag-me element is now a P");
is(parentInfo.numChildren, 1, "#retag-me still has one child");
childInfo = yield testActor.getNodeInfo("#retag-me > *");
is(childInfo.attributes[0].value, "retag-me-2",
"#retag-me's only child is #retag-me-2");
});

View file

@ -0,0 +1,59 @@
/* 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 a node can be deleted from the markup-view with the backspace key.
// Also checks that after deletion the correct element is highlighted.
// The previous sibling is preferred, but the parent is a fallback.
const HTML = `<style type="text/css">
#pseudo::before { content: 'before'; }
#pseudo::after { content: 'after'; }
</style>
<div id="parent">
<div id="first"></div>
<div id="second"></div>
<div id="third"></div>
</div>
<div id="only-child">
<div id="fourth"></div>
</div>
<div id="pseudo">
<div id="fifth"></div>
</div>`;
const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
// List of all the test cases. Each item is an object with the following props:
// - selector: the css selector of the node that should be selected
// - focusedSelector: the css selector of the node we expect to be selected as
// a result of the deletion
// - pseudo: (optional) if the focused node is actually supposed to be a pseudo element
// of the specified selector.
// Note that after each test case, undo is called.
const TEST_DATA = [{
selector: "#first",
focusedSelector: "#second"
}, {
selector: "#second",
focusedSelector: "#first"
}, {
selector: "#third",
focusedSelector: "#second"
}, {
selector: "#fourth",
focusedSelector: "#only-child"
}, {
selector: "#fifth",
focusedSelector: "#pseudo",
pseudo: "before"
}];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
for (let data of TEST_DATA) {
yield checkDeleteAndSelection(inspector, "back_space", data);
}
});

View file

@ -0,0 +1,59 @@
/* 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 a node can be deleted from the markup-view with the delete key.
// Also checks that after deletion the correct element is highlighted.
// The next sibling is preferred, but the parent is a fallback.
const HTML = `<style type="text/css">
#pseudo::before { content: 'before'; }
#pseudo::after { content: 'after'; }
</style>
<div id="parent">
<div id="first"></div>
<div id="second"></div>
<div id="third"></div>
</div>
<div id="only-child">
<div id="fourth"></div>
</div>
<div id="pseudo">
<div id="fifth"></div>
</div>`;
const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
// List of all the test cases. Each item is an object with the following props:
// - selector: the css selector of the node that should be selected
// - focusedSelector: the css selector of the node we expect to be selected as
// a result of the deletion
// - pseudo: (optional) if the focused node is actually supposed to be a pseudo element
// of the specified selector.
// Note that after each test case, undo is called.
const TEST_DATA = [{
selector: "#first",
focusedSelector: "#second"
}, {
selector: "#second",
focusedSelector: "#third"
}, {
selector: "#third",
focusedSelector: "#second"
}, {
selector: "#fourth",
focusedSelector: "#only-child"
}, {
selector: "#fifth",
focusedSelector: "#pseudo",
pseudo: "after"
}];
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
for (let data of TEST_DATA) {
yield checkDeleteAndSelection(inspector, "delete", data);
}
});

View file

@ -0,0 +1,77 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_attributes_test_runner.js */
"use strict";
// Tests that adding various types of attributes to nodes in the markup-view
// works as expected. Also checks that the changes are properly undoable and
// redoable. For each step in the test, we:
// - Create a new DIV
// - Make the change, check that the change was made as we expect
// - Undo the change, check that the node is back in its original state
// - Redo the change, check that the node change was made again correctly.
loadHelperScript("helper_attributes_test_runner.js");
var TEST_URL = "data:text/html,<div>markup-view attributes addition test</div>";
var TEST_DATA = [{
desc: "Add an attribute value without closing \"",
text: 'style="display: block;',
expectedAttributes: {
style: "display: block;"
}
}, {
desc: "Add an attribute value without closing '",
text: "style='display: inline;",
expectedAttributes: {
style: "display: inline;"
}
}, {
desc: "Add an attribute wrapped with with double quotes double quote in it",
text: 'style="display: "inline',
expectedAttributes: {
style: "display: ",
inline: ""
}
}, {
desc: "Add an attribute wrapped with single quotes with single quote in it",
text: "style='display: 'inline",
expectedAttributes: {
style: "display: ",
inline: ""
}
}, {
desc: "Add an attribute with no value",
text: "disabled",
expectedAttributes: {
disabled: ""
}
}, {
desc: "Add multiple attributes with no value",
text: "disabled autofocus",
expectedAttributes: {
disabled: "",
autofocus: ""
}
}, {
desc: "Add multiple attributes with no value, and some with value",
text: "disabled name='name' data-test='test' autofocus",
expectedAttributes: {
disabled: "",
autofocus: "",
name: "name",
"data-test": "test"
}
}, {
desc: "Add attribute with xmlns",
text: "xmlns:edi='http://ecommerce.example.org/schema'",
expectedAttributes: {
"xmlns:edi": "http://ecommerce.example.org/schema"
}
}];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
yield runAddAttributesTests(TEST_DATA, "div", inspector, testActor);
});

View file

@ -0,0 +1,85 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_attributes_test_runner.js */
"use strict";
// Tests that adding various types of attributes to nodes in the markup-view
// works as expected. Also checks that the changes are properly undoable and
// redoable. For each step in the test, we:
// - Create a new DIV
// - Make the change, check that the change was made as we expect
// - Undo the change, check that the node is back in its original state
// - Redo the change, check that the node change was made again correctly.
loadHelperScript("helper_attributes_test_runner.js");
var TEST_URL = "data:text/html,<div>markup-view attributes addition test</div>";
var TEST_DATA = [{
desc: "Mixed single and double quotes",
text: "name=\"hi\" maxlength='not a number'",
expectedAttributes: {
maxlength: "not a number",
name: "hi"
}
}, {
desc: "Invalid attribute name",
text: "x='y' <why-would-you-do-this>=\"???\"",
expectedAttributes: {
x: "y"
}
}, {
desc: "Double quote wrapped in single quotes",
text: "x='h\"i'",
expectedAttributes: {
x: "h\"i"
}
}, {
desc: "Single quote wrapped in double quotes",
text: "x=\"h'i\"",
expectedAttributes: {
x: "h'i"
}
}, {
desc: "No quote wrapping",
text: "a=b x=y data-test=Some spaced data",
expectedAttributes: {
a: "b",
x: "y",
"data-test": "Some",
spaced: "",
data: ""
}
}, {
desc: "Duplicate Attributes",
text: "a=b a='c' a=\"d\"",
expectedAttributes: {
a: "b"
}
}, {
desc: "Inline styles",
text: "style=\"font-family: 'Lucida Grande', sans-serif; font-size: 75%;\"",
expectedAttributes: {
style: "font-family: 'Lucida Grande', sans-serif; font-size: 75%;"
}
}, {
desc: "Object attribute names",
text: "toString=\"true\" hasOwnProperty=\"false\"",
expectedAttributes: {
tostring: "true",
hasownproperty: "false"
}
}, {
desc: "Add event handlers",
text: "onclick=\"javascript: throw new Error('wont fire');\" " +
"onload=\"alert('here');\"",
expectedAttributes: {
onclick: "javascript: throw new Error('wont fire');",
onload: "alert('here');"
}
}];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
yield runAddAttributesTests(TEST_DATA, "div", inspector, testActor);
});

View file

@ -0,0 +1,135 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_attributes_test_runner.js */
"use strict";
// One more test testing various add-attributes configurations
// Some of the test data below asserts that long attributes get collapsed
loadHelperScript("helper_attributes_test_runner.js");
/*eslint-disable */
const LONG_ATTRIBUTE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const LONG_ATTRIBUTE_COLLAPSED = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEF\u2026UVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const DATA_URL_INLINE_STYLE='color: red; background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC");';
const DATA_URL_INLINE_STYLE_COLLAPSED='color: red; background: url("data:image/png;base64,iVBORw0KG\u2026NDDeNGe4Ug9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC");';
const DATA_URL_ATTRIBUTE = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC";
const DATA_URL_ATTRIBUTE_COLLAPSED = "data:image/png;base64,iVBORw0K\u20269/AFGGFyjOXZtQAAAAAElFTkSuQmCC";
/*eslint-enable */
var TEST_URL = "data:text/html,<div>markup-view attributes addition test</div>";
var TEST_DATA = [{
desc: "Add an attribute value containing < > &uuml; \" & '",
text: 'src="somefile.html?param1=<a>&param2=&uuml;&param3=\'&quot;\'"',
expectedAttributes: {
src: "somefile.html?param1=<a>&param2=\xfc&param3='\"'"
}
}, {
desc: "Add an attribute by clicking the empty space after a node",
text: 'class="newclass" style="color:green"',
expectedAttributes: {
class: "newclass",
style: "color:green"
}
}, {
desc: "Try add an attribute containing a quote (\") attribute by " +
"clicking the empty space after a node - this should result " +
"in it being set to an empty string",
text: 'class="newclass" style="""',
expectedAttributes: {
class: "newclass",
style: ""
}
}, {
desc: "Try to add long data URL to make sure it is collapsed in attribute " +
"editor.",
text: `style='${DATA_URL_INLINE_STYLE}'`,
expectedAttributes: {
"style": DATA_URL_INLINE_STYLE
},
validate: (container, inspector) => {
let editor = container.editor;
let visibleAttrText = editor.attrElements.get("style")
.querySelector(".attr-value")
.textContent;
is(visibleAttrText, DATA_URL_INLINE_STYLE_COLLAPSED);
}
}, {
desc: "Try to add long attribute to make sure it is collapsed in attribute " +
"editor.",
text: `data-long="${LONG_ATTRIBUTE}"`,
expectedAttributes: {
"data-long": LONG_ATTRIBUTE
},
validate: (container, inspector) => {
let editor = container.editor;
let visibleAttrText = editor.attrElements.get("data-long")
.querySelector(".attr-value")
.textContent;
is(visibleAttrText, LONG_ATTRIBUTE_COLLAPSED);
}
}, {
desc: "Try to add long data URL to make sure it is collapsed in attribute " +
"editor.",
text: `src="${DATA_URL_ATTRIBUTE}"`,
expectedAttributes: {
"src": DATA_URL_ATTRIBUTE
},
validate: (container, inspector) => {
let editor = container.editor;
let visibleAttrText = editor.attrElements.get("src")
.querySelector(".attr-value").textContent;
is(visibleAttrText, DATA_URL_ATTRIBUTE_COLLAPSED);
}
}, {
desc: "Try to add long attribute with collapseAttributes == false" +
"to make sure it isn't collapsed in attribute editor.",
text: `data-long="${LONG_ATTRIBUTE}"`,
expectedAttributes: {
"data-long": LONG_ATTRIBUTE
},
setUp: function (inspector) {
Services.prefs.setBoolPref("devtools.markup.collapseAttributes", false);
},
validate: (container, inspector) => {
let editor = container.editor;
let visibleAttrText = editor.attrElements
.get("data-long")
.querySelector(".attr-value")
.textContent;
is(visibleAttrText, LONG_ATTRIBUTE);
},
tearDown: function (inspector) {
Services.prefs.clearUserPref("devtools.markup.collapseAttributes");
}
}, {
desc: "Try to collapse attributes with collapseAttributeLength == 5",
text: `data-long="${LONG_ATTRIBUTE}"`,
expectedAttributes: {
"data-long": LONG_ATTRIBUTE
},
setUp: function (inspector) {
Services.prefs.setIntPref("devtools.markup.collapseAttributeLength", 2);
},
validate: (container, inspector) => {
let firstChar = LONG_ATTRIBUTE[0];
let lastChar = LONG_ATTRIBUTE[LONG_ATTRIBUTE.length - 1];
let collapsed = firstChar + "\u2026" + lastChar;
let editor = container.editor;
let visibleAttrText = editor.attrElements
.get("data-long")
.querySelector(".attr-value")
.textContent;
is(visibleAttrText, collapsed);
},
tearDown: function (inspector) {
Services.prefs.clearUserPref("devtools.markup.collapseAttributeLength");
}
}];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
yield runAddAttributesTests(TEST_DATA, "div", inspector, testActor);
});

View file

@ -0,0 +1,132 @@
/* 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 editing various markup-containers' attribute fields, in particular
// attributes with long values and quotes
const TEST_URL = URL_ROOT + "doc_markup_edit.html";
/*eslint-disable */
const LONG_ATTRIBUTE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const LONG_ATTRIBUTE_COLLAPSED = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEF\u2026UVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ-ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/*eslint-enable */
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
yield inspector.markup.expandAll();
yield testCollapsedLongAttribute(inspector, testActor);
yield testModifyInlineStyleWithQuotes(inspector, testActor);
yield testEditingAttributeWithMixedQuotes(inspector, testActor);
});
function* testCollapsedLongAttribute(inspector, testActor) {
info("Try to modify the collapsed long attribute, making sure it expands.");
info("Adding test attributes to the node");
let onMutated = inspector.once("markupmutation");
yield testActor.setAttribute("#node24", "class", "");
yield testActor.setAttribute("#node24", "data-long", LONG_ATTRIBUTE);
yield onMutated;
yield assertAttributes("#node24", {
id: "node24",
"class": "",
"data-long": LONG_ATTRIBUTE
}, testActor);
let {editor} = yield focusNode("#node24", inspector);
let attr = editor.attrElements.get("data-long").querySelector(".editable");
// Check to make sure it has expanded after focus
attr.focus();
EventUtils.sendKey("return", inspector.panelWin);
let input = inplaceEditor(attr).input;
is(input.value, `data-long="${LONG_ATTRIBUTE}"`);
EventUtils.sendKey("escape", inspector.panelWin);
setEditableFieldValue(attr, input.value + ' data-short="ABC"', inspector);
yield inspector.once("markupmutation");
let visibleAttrText = editor.attrElements.get("data-long")
.querySelector(".attr-value").textContent;
is(visibleAttrText, LONG_ATTRIBUTE_COLLAPSED);
yield assertAttributes("#node24", {
id: "node24",
class: "",
"data-long": LONG_ATTRIBUTE,
"data-short": "ABC"
}, testActor);
}
function* testModifyInlineStyleWithQuotes(inspector, testActor) {
info("Modify inline style containing \"");
yield assertAttributes("#node26", {
id: "node26",
style: 'background-image: url("moz-page-thumb://thumbnail?url=http%3A%2F%2Fwww.mozilla.org%2F");'
}, testActor);
let onMutated = inspector.once("markupmutation");
let {editor} = yield focusNode("#node26", inspector);
let attr = editor.attrElements.get("style").querySelector(".editable");
attr.focus();
EventUtils.sendKey("return", inspector.panelWin);
let input = inplaceEditor(attr).input;
let value = input.value;
is(value,
"style='background-image: url(\"moz-page-thumb://thumbnail?url=http%3A%2F%2Fwww.mozilla.org%2F\");'",
"Value contains actual double quotes"
);
value = value.replace(/mozilla\.org/, "mozilla.com");
input.value = value;
EventUtils.sendKey("return", inspector.panelWin);
yield onMutated;
yield assertAttributes("#node26", {
id: "node26",
style: 'background-image: url("moz-page-thumb://thumbnail?url=http%3A%2F%2Fwww.mozilla.com%2F");'
}, testActor);
}
function* testEditingAttributeWithMixedQuotes(inspector, testActor) {
info("Modify class containing \" and \'");
yield assertAttributes("#node27", {
"id": "node27",
"class": 'Double " and single \''
}, testActor);
let onMutated = inspector.once("markupmutation");
let {editor} = yield focusNode("#node27", inspector);
let attr = editor.attrElements.get("class").querySelector(".editable");
attr.focus();
EventUtils.sendKey("return", inspector.panelWin);
let input = inplaceEditor(attr).input;
let value = input.value;
is(value, "class=\"Double &quot; and single '\"", "Value contains &quot;");
value = value.replace(/Double/, "&quot;").replace(/single/, "'");
input.value = value;
EventUtils.sendKey("return", inspector.panelWin);
yield onMutated;
yield assertAttributes("#node27", {
id: "node27",
class: '" " and \' \''
}, testActor);
}

View file

@ -0,0 +1,71 @@
/* 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 editing a mixed-case attribute preserves the case
const TEST_URL = URL_ROOT + "doc_markup_svg_attributes.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
yield inspector.markup.expandAll();
yield selectNode("svg", inspector);
yield testWellformedMixedCase(inspector, testActor);
yield testMalformedMixedCase(inspector, testActor);
});
function* testWellformedMixedCase(inspector, testActor) {
info("Modifying a mixed-case attribute, " +
"expecting the attribute's case to be preserved");
info("Listening to markup mutations");
let onMutated = inspector.once("markupmutation");
info("Focusing the viewBox attribute editor");
let {editor} = yield focusNode("svg", inspector);
let attr = editor.attrElements.get("viewBox").querySelector(".editable");
attr.focus();
EventUtils.sendKey("return", inspector.panelWin);
info("Editing the attribute value and waiting for the mutation event");
let input = inplaceEditor(attr).input;
input.value = "viewBox=\"0 0 1 1\"";
EventUtils.sendKey("return", inspector.panelWin);
yield onMutated;
yield assertAttributes("svg", {
"viewBox": "0 0 1 1",
"width": "200",
"height": "200"
}, testActor);
}
function* testMalformedMixedCase(inspector, testActor) {
info("Modifying a malformed, mixed-case attribute, " +
"expecting the attribute's case to be preserved");
info("Listening to markup mutations");
let onMutated = inspector.once("markupmutation");
info("Focusing the viewBox attribute editor");
let {editor} = yield focusNode("svg", inspector);
let attr = editor.attrElements.get("viewBox").querySelector(".editable");
attr.focus();
EventUtils.sendKey("return", inspector.panelWin);
info("Editing the attribute value and waiting for the mutation event");
let input = inplaceEditor(attr).input;
input.value = "viewBox=\"<>\"";
EventUtils.sendKey("return", inspector.panelWin);
yield onMutated;
yield assertAttributes("svg", {
"viewBox": "<>",
"width": "200",
"height": "200"
}, testActor);
}

View file

@ -0,0 +1,34 @@
/* 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 invalid tagname updates are handled correctly
const TEST_URL = "data:text/html;charset=utf-8,<div></div>";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
yield inspector.markup.expandAll();
info("Updating the DIV tagname to an invalid value");
let container = yield focusNode("div", inspector);
let onCancelReselect = inspector.markup.once("canceledreselectonremoved");
let tagEditor = container.editor.tag;
setEditableFieldValue(tagEditor, "<<<", inspector);
yield onCancelReselect;
ok(true, "The markup-view emitted the canceledreselectonremoved event");
is(inspector.selection.nodeFront, container.node,
"The test DIV is still selected");
info("Updating the DIV tagname to a valid value this time");
let onReselect = inspector.markup.once("reselectedonremoved");
setEditableFieldValue(tagEditor, "span", inspector);
yield onReselect;
ok(true, "The markup-view emitted the reselectedonremoved event");
let spanFront = yield getNodeFront("span", inspector);
is(inspector.selection.nodeFront, spanFront,
"The selected node is now the SPAN");
});

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";
// Bug 1090874 - Tests that a node is not recreated when it's tagname editor
// is blurred and no changes were done.
const TEST_URL = "data:text/html;charset=utf-8,<div></div>";
add_task(function* () {
let isEditTagNameCalled = false;
let {inspector} = yield openInspectorForURL(TEST_URL);
// Overriding the editTagName walkerActor method here to check that it isn't
// called when blurring the tagname field.
inspector.walker.editTagName = function () {
isEditTagNameCalled = true;
};
let container = yield focusNode("div", inspector);
let tagEditor = container.editor.tag;
info("Blurring the tagname field");
tagEditor.blur();
is(isEditTagNameCalled, false, "The editTagName method wasn't called");
info("Updating the tagname to uppercase");
yield focusNode("div", inspector);
setEditableFieldValue(tagEditor, "DIV", inspector);
is(isEditTagNameCalled, false, "The editTagName method wasn't called");
info("Updating the tagname to a different value");
setEditableFieldValue(tagEditor, "SPAN", inspector);
is(isEditTagNameCalled, true, "The editTagName method was called");
});

View file

@ -0,0 +1,98 @@
/* 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 focus position is correct when tabbing through and editing
// attributes.
const TEST_URL = "data:text/html;charset=utf8," +
"<div id='attr' a='1' b='2' c='3'></div>" +
"<div id='delattr' tobeinvalid='1' last='2'></div>";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
yield testAttributeEditing(inspector);
yield testAttributeDeletion(inspector);
});
function* testAttributeEditing(inspector) {
info("Testing focus position after attribute editing");
info("Setting the first non-id attribute in edit mode");
// focuses id
yield activateFirstAttribute("#attr", inspector);
// focuses the first attr after id
collapseSelectionAndTab(inspector);
let attrs = yield getAttributesFromEditor("#attr", inspector);
info("Editing this attribute, keeping the same name, " +
"and tabbing to the next");
yield editAttributeAndTab(attrs[1] + '="99"', inspector);
checkFocusedAttribute(attrs[2], true);
info("Editing the new focused attribute, keeping the name, " +
"and tabbing to the previous");
yield editAttributeAndTab(attrs[2] + '="99"', inspector, true);
checkFocusedAttribute(attrs[1], true);
info("Editing attribute name, changes attribute order");
yield editAttributeAndTab("d='4'", inspector);
checkFocusedAttribute("id", true);
// Escape of the currently focused field for the next test
EventUtils.sendKey("escape", inspector.panelWin);
}
function* testAttributeDeletion(inspector) {
info("Testing focus position after attribute deletion");
info("Setting the first non-id attribute in edit mode");
// focuses id
yield activateFirstAttribute("#delattr", inspector);
// focuses the first attr after id
collapseSelectionAndTab(inspector);
let attrs = yield getAttributesFromEditor("#delattr", inspector);
info("Entering an invalid attribute to delete the attribute");
yield editAttributeAndTab('"', inspector);
checkFocusedAttribute(attrs[2], true);
info("Deleting the last attribute");
yield editAttributeAndTab(" ", inspector);
// Check we're on the newattr element
let focusedAttr = Services.focus.focusedElement;
ok(focusedAttr.classList.contains("styleinspector-propertyeditor"),
"in newattr");
is(focusedAttr.tagName, "textarea", "newattr is active");
}
function* editAttributeAndTab(newValue, inspector, goPrevious) {
let onEditMutation = inspector.markup.once("refocusedonedit");
inspector.markup.doc.activeElement.value = newValue;
if (goPrevious) {
EventUtils.synthesizeKey("VK_TAB", { shiftKey: true },
inspector.panelWin);
} else {
EventUtils.sendKey("tab", inspector.panelWin);
}
yield onEditMutation;
}
/**
* Given a markup container, focus and turn in edit mode its first attribute
* field.
*/
function* activateFirstAttribute(container, inspector) {
let {editor} = yield focusNode(container, inspector);
editor.tag.focus();
// Go to "id" attribute and trigger edit mode.
EventUtils.sendKey("tab", inspector.panelWin);
EventUtils.sendKey("return", inspector.panelWin);
}

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";
// Tests that doesn't fit into any specific category.
const TEST_URL = `data:text/html;charset=utf8,
<div a b id='order' c class></div>`;
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
yield testOriginalAttributesOrder(inspector);
yield testOrderAfterAttributeChange(inspector, testActor);
});
function* testOriginalAttributesOrder(inspector) {
info("Testing order of attributes on initial node render");
let attributes = yield getAttributesFromEditor("#order", inspector);
ok(isEqual(attributes, ["id", "class", "a", "b", "c"]), "ordered correctly");
}
function* testOrderAfterAttributeChange(inspector, testActor) {
info("Testing order of attributes after attribute is change by setAttribute");
yield testActor.setAttribute("#order", "a", "changed");
let attributes = yield getAttributesFromEditor("#order", inspector);
ok(isEqual(attributes, ["id", "class", "a", "b", "c"]),
"order isn't changed");
}
function isEqual(a, b) {
return a.toString() === b.toString();
}

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 editing long classnames shows the whole class attribute without scrollbars.
const classname = "this-long-class-attribute-should-be-displayed " +
"without-overflow-when-switching-to-edit-mode " +
"AAAAAAAAAAAA-BBBBBBBBBBBBB-CCCCCCCCCCCCC-DDDDDDDDDDDDDD-EEEEEEEEEEEEE";
const TEST_URL = `data:text/html;charset=utf8, <div class="${classname}"></div>`;
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
yield selectNode("div", inspector);
yield clickContainer("div", inspector);
let container = yield focusNode("div", inspector);
ok(container && container.editor, "The markup-container was found");
info("Listening for the markupmutation event");
let nodeMutated = inspector.once("markupmutation");
let attr = container.editor.attrElements.get("class").querySelector(".editable");
attr.focus();
EventUtils.sendKey("return", inspector.panelWin);
let input = inplaceEditor(attr).input;
ok(input, "Found editable field for class attribute");
is(input.scrollHeight, input.clientHeight, "input should not have vertical scrollbars");
is(input.scrollWidth, input.clientWidth, "input should not have horizontal scrollbars");
input.value = "class=\"other value\"";
info("Commit the new class value");
EventUtils.sendKey("return", inspector.panelWin);
info("Wait for the markup-mutation event");
yield nodeMutated;
});

View file

@ -0,0 +1,89 @@
/* 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 the rendering of text nodes in the markup view.
const LONG_VALUE = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do " +
"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.";
const SCHEMA = "data:text/html;charset=UTF-8,";
const TEST_URL = `${SCHEMA}<!DOCTYPE html>
<html>
<body>
<div id="shorttext">Short text</div>
<div id="longtext">${LONG_VALUE}</div>
<div id="shortcomment"><!--Short comment--></div>
<div id="longcomment"><!--${LONG_VALUE}--></div>
<div id="shorttext-and-node">Short text<span>Other element</span></div>
<div id="longtext-and-node">${LONG_VALUE}<span>Other element</span></div>
</body>
</html>`;
const TEST_DATA = [{
desc: "Test node containing a short text, short text nodes can be inlined.",
selector: "#shorttext",
inline: true,
value: "Short text",
}, {
desc: "Test node containing a long text, long text nodes are not inlined.",
selector: "#longtext",
inline: false,
value: LONG_VALUE,
}, {
desc: "Test node containing a short comment, comments are not inlined.",
selector: "#shortcomment",
inline: false,
value: "Short comment",
}, {
desc: "Test node containing a long comment, comments are not inlined.",
selector: "#longcomment",
inline: false,
value: LONG_VALUE,
}, {
desc: "Test node containing a short text and a span.",
selector: "#shorttext-and-node",
inline: false,
value: "Short text",
}, {
desc: "Test node containing a long text and a span.",
selector: "#longtext-and-node",
inline: false,
value: LONG_VALUE,
}];
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
for (let data of TEST_DATA) {
yield checkNode(inspector, testActor, data);
}
});
function* checkNode(inspector, testActor, {desc, selector, inline, value}) {
info(desc);
let container = yield getContainerForSelector(selector, inspector);
let nodeValue = yield getFirstChildNodeValue(selector, testActor);
is(nodeValue, value, "The test node's text content is correct");
is(!!container.inlineTextChild, inline, "Container inlineTextChild is as expected");
is(!container.canExpand, inline, "Container canExpand property is as expected");
let textContainer;
if (inline) {
textContainer = container.elt.querySelector("pre");
ok(!!textContainer, "Text container is already rendered for inline text elements");
} else {
textContainer = container.elt.querySelector("pre");
ok(!textContainer, "Text container is not rendered for collapsed text nodes");
yield inspector.markup.expandNode(container.node);
yield waitForMultipleChildrenUpdates(inspector);
textContainer = container.elt.querySelector("pre");
ok(!!textContainer, "Text container is rendered after expanding the container");
}
is(textContainer.textContent, value, "The complete text node is rendered.");
}

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 editing a node's text content
const TEST_URL = URL_ROOT + "doc_markup_edit.html";
const {DEFAULT_VALUE_SUMMARY_LENGTH} = require("devtools/server/actors/inspector");
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("Expanding all nodes");
yield inspector.markup.expandAll();
yield waitForMultipleChildrenUpdates(inspector);
yield editContainer(inspector, testActor, {
selector: ".node6",
newValue: "New text",
oldValue: "line6"
});
yield editContainer(inspector, testActor, {
selector: "#node17",
newValue: "LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT. " +
"DONEC POSUERE PLACERAT MAGNA ET IMPERDIET.",
oldValue: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
"Donec posuere placerat magna et imperdiet."
});
yield editContainer(inspector, testActor, {
selector: "#node17",
newValue: "New value",
oldValue: "LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT. " +
"DONEC POSUERE PLACERAT MAGNA ET IMPERDIET."
});
yield editContainer(inspector, testActor, {
selector: "#node17",
newValue: "LOREM IPSUM DOLOR SIT AMET, CONSECTETUR ADIPISCING ELIT. " +
"DONEC POSUERE PLACERAT MAGNA ET IMPERDIET.",
oldValue: "New value"
});
});
function* editContainer(inspector, testActor,
{selector, newValue, oldValue}) {
let nodeValue = yield getFirstChildNodeValue(selector, testActor);
is(nodeValue, oldValue, "The test node's text content is correct");
info("Changing the text content");
let onMutated = inspector.once("markupmutation");
let container = yield focusNode(selector, inspector);
let isOldValueInline = oldValue.length <= DEFAULT_VALUE_SUMMARY_LENGTH;
is(!!container.inlineTextChild, isOldValueInline, "inlineTextChild is as expected");
is(!container.canExpand, isOldValueInline, "canExpand property is as expected");
let field = container.elt.querySelector("pre");
is(field.textContent, oldValue,
"The text node has the correct original value after selecting");
setEditableFieldValue(field, newValue, inspector);
info("Listening to the markupmutation event");
yield onMutated;
nodeValue = yield getFirstChildNodeValue(selector, testActor);
is(nodeValue, newValue, "The test node's text content has changed");
let isNewValueInline = newValue.length <= DEFAULT_VALUE_SUMMARY_LENGTH;
is(!!container.inlineTextChild, isNewValueInline, "inlineTextChild is as expected");
is(!container.canExpand, isNewValueInline, "canExpand property is as expected");
if (isOldValueInline != isNewValueInline) {
is(container.expanded, !isNewValueInline,
"Container was automatically expanded/collapsed");
}
info("Selecting the <body> to reset the selection");
let bodyContainer = yield getContainerForSelector("body", inspector);
inspector.markup.markNodeAsSelected(bodyContainer.node);
}

View file

@ -0,0 +1,116 @@
/* 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 using UP/DOWN next to a number when editing a text node does not
// increment or decrement but simply navigates inside the editable field.
const TEST_URL = URL_ROOT + "doc_markup_edit.html";
const SELECTOR = ".node6";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("Expanding all nodes");
yield inspector.markup.expandAll();
yield waitForMultipleChildrenUpdates(inspector);
let nodeValue = yield getFirstChildNodeValue(SELECTOR, testActor);
let expectedValue = "line6";
is(nodeValue, expectedValue, "The test node's text content is correct");
info("Open editable field for .node6");
let container = yield focusNode(SELECTOR, inspector);
let field = container.elt.querySelector("pre");
field.focus();
EventUtils.sendKey("return", inspector.panelWin);
let editor = inplaceEditor(field);
info("Initially, all the input content should be selected");
checkSelectionPositions(editor, 0, expectedValue.length);
info("Navigate using 'RIGHT': move the caret to the end");
yield sendKey("VK_RIGHT", {}, editor, inspector.panelWin);
is(editor.input.value, expectedValue, "Value should not have changed");
checkSelectionPositions(editor, expectedValue.length, expectedValue.length);
info("Navigate using 'DOWN': no effect, already at the end");
yield sendKey("VK_DOWN", {}, editor, inspector.panelWin);
is(editor.input.value, expectedValue, "Value should not have changed");
checkSelectionPositions(editor, expectedValue.length, expectedValue.length);
info("Navigate using 'UP': move to the start");
yield sendKey("VK_UP", {}, editor, inspector.panelWin);
is(editor.input.value, expectedValue, "Value should not have changed");
checkSelectionPositions(editor, 0, 0);
info("Navigate using 'DOWN': move to the end");
yield sendKey("VK_DOWN", {}, editor, inspector.panelWin);
is(editor.input.value, expectedValue, "Value should not have changed");
checkSelectionPositions(editor, expectedValue.length, expectedValue.length);
info("Type 'b' in the editable field");
yield sendKey("b", {}, editor, inspector.panelWin);
expectedValue += "b";
is(editor.input.value, expectedValue, "Value should be updated");
info("Type 'a' in the editable field");
yield sendKey("a", {}, editor, inspector.panelWin);
expectedValue += "a";
is(editor.input.value, expectedValue, "Value should be updated");
info("Create a new line using shift+RETURN");
yield sendKey("VK_RETURN", {shiftKey: true}, editor, inspector.panelWin);
expectedValue += "\n";
is(editor.input.value, expectedValue, "Value should have a new line");
checkSelectionPositions(editor, expectedValue.length, expectedValue.length);
info("Type '1' in the editable field");
yield sendKey("1", {}, editor, inspector.panelWin);
expectedValue += "1";
is(editor.input.value, expectedValue, "Value should be updated");
checkSelectionPositions(editor, expectedValue.length, expectedValue.length);
info("Navigate using 'UP': move back to the first line");
yield sendKey("VK_UP", {}, editor, inspector.panelWin);
is(editor.input.value, expectedValue, "Value should not have changed");
info("Caret should be back on the first line");
checkSelectionPositions(editor, 1, 1);
info("Commit the new value with RETURN, wait for the markupmutation event");
let onMutated = inspector.once("markupmutation");
yield sendKey("VK_RETURN", {}, editor, inspector.panelWin);
yield onMutated;
nodeValue = yield getFirstChildNodeValue(SELECTOR, testActor);
is(nodeValue, expectedValue, "The test node's text content is correct");
});
/**
* Check that the editor selection is at the expected positions.
*/
function checkSelectionPositions(editor, expectedStart, expectedEnd) {
is(editor.input.selectionStart, expectedStart,
"Selection should start at " + expectedStart);
is(editor.input.selectionEnd, expectedEnd,
"Selection should end at " + expectedEnd);
}
/**
* Send a key and expect to receive a keypress event on the editor's input.
*/
function sendKey(key, options, editor, win) {
return new Promise(resolve => {
info("Adding event listener for down|left|right|back_space|return keys");
editor.input.addEventListener("keypress", function onKeypress() {
if (editor.input) {
editor.input.removeEventListener("keypress", onKeypress);
}
executeSoon(resolve);
});
EventUtils.synthesizeKey(key, options, win);
});
}

View file

@ -0,0 +1,58 @@
/* 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 toggling (expand/collapse) elements by clicking on twisties
const TEST_URL = URL_ROOT + "doc_markup_toggle.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("Getting the container for the html element");
let container = yield getContainerForSelector("html", inspector);
ok(container.mustExpand, "HTML element mustExpand");
ok(container.canExpand, "HTML element canExpand");
is(container.expander.style.visibility, "hidden", "HTML twisty is hidden");
info("Getting the container for the UL parent element");
container = yield getContainerForSelector("ul", inspector);
ok(!container.mustExpand, "UL element !mustExpand");
ok(container.canExpand, "UL element canExpand");
is(container.expander.style.visibility, "visible", "HTML twisty is visible");
info("Clicking on the UL parent expander, and waiting for children");
let onChildren = waitForChildrenUpdated(inspector);
let onUpdated = inspector.once("inspector-updated");
EventUtils.synthesizeMouseAtCenter(container.expander, {},
inspector.markup.doc.defaultView);
yield onChildren;
yield onUpdated;
info("Checking that child LI elements have been created");
let numLi = yield testActor.getNumberOfElementMatches("li");
for (let i = 0; i < numLi; i++) {
let liContainer = yield getContainerForSelector(
`li:nth-child(${i + 1})`, inspector);
ok(liContainer, "A container for the child LI element was created");
}
ok(container.expanded, "Parent UL container is expanded");
info("Clicking again on the UL expander");
// No need to wait, this is a local, synchronous operation where nodes are
// only hidden from the view, not destroyed
EventUtils.synthesizeMouseAtCenter(container.expander, {},
inspector.markup.doc.defaultView);
info("Checking that child LI elements have been hidden");
numLi = yield testActor.getNumberOfElementMatches("li");
for (let i = 0; i < numLi; i++) {
let liContainer = yield getContainerForSelector(
`li:nth-child(${i + 1})`, inspector);
is(liContainer.elt.getClientRects().length, 0,
"The container for the child LI element was hidden");
}
ok(!container.expanded, "Parent UL container is collapsed");
});

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 toggling (expand/collapse) elements by dbl-clicking on tag lines
const TEST_URL = URL_ROOT + "doc_markup_toggle.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
info("Getting the container for the UL parent element");
let container = yield getContainerForSelector("ul", inspector);
info("Dbl-clicking on the UL parent expander, and waiting for children");
let onChildren = waitForChildrenUpdated(inspector);
let onUpdated = inspector.once("inspector-updated");
EventUtils.synthesizeMouseAtCenter(container.tagLine, {clickCount: 2},
inspector.markup.doc.defaultView);
yield onChildren;
yield onUpdated;
info("Checking that child LI elements have been created");
let numLi = yield testActor.getNumberOfElementMatches("li");
for (let i = 0; i < numLi; i++) {
let liContainer = yield getContainerForSelector(
"li:nth-child(" + (i + 1) + ")", inspector);
ok(liContainer, "A container for the child LI element was created");
}
ok(container.expanded, "Parent UL container is expanded");
info("Dbl-clicking again on the UL expander");
// No need to wait, this is a local, synchronous operation where nodes are
// only hidden from the view, not destroyed
EventUtils.synthesizeMouseAtCenter(container.tagLine, {clickCount: 2},
inspector.markup.doc.defaultView);
info("Checking that child LI elements have been hidden");
numLi = yield testActor.getNumberOfElementMatches("li");
for (let i = 0; i < numLi; i++) {
let liContainer = yield getContainerForSelector(
"li:nth-child(" + (i + 1) + ")", inspector);
is(liContainer.elt.getClientRects().length, 0,
"The container for the child LI element was hidden");
}
ok(!container.expanded, "Parent UL container is collapsed");
});

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 toggling (expand/collapse) elements by alt-clicking on twisties, which
// should expand all the descendants
const TEST_URL = URL_ROOT + "doc_markup_toggle.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
info("Getting the container for the UL parent element");
let container = yield getContainerForSelector("ul", inspector);
info("Alt-clicking on the UL parent expander, and waiting for children");
let onUpdated = inspector.once("inspector-updated");
EventUtils.synthesizeMouseAtCenter(container.expander, {altKey: true},
inspector.markup.doc.defaultView);
yield onUpdated;
yield waitForMultipleChildrenUpdates(inspector);
info("Checking that all nodes exist and are expanded");
let nodeList = yield inspector.walker.querySelectorAll(
inspector.walker.rootNode, "ul, li, span, em");
let nodeFronts = yield nodeList.items();
for (let nodeFront of nodeFronts) {
let nodeContainer = getContainerForNodeFront(nodeFront, inspector);
ok(nodeContainer, "Container for node " + nodeFront.tagName + " exists");
ok(nodeContainer.expanded,
"Container for node " + nodeFront.tagName + " is expanded");
}
});

View file

@ -0,0 +1,44 @@
/* 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 markup view handles page navigation correctly.
const SCHEMA = "data:text/html;charset=UTF-8,";
const URL_1 = SCHEMA + "<div id='one' style='color:red;'>ONE</div>";
const URL_2 = SCHEMA + "<div id='two' style='color:green;'>TWO</div>";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(URL_1);
assertMarkupViewIsLoaded();
yield selectNode("#one", inspector);
let willNavigate = inspector.target.once("will-navigate");
yield testActor.eval(`content.location = "${URL_2}"`);
info("Waiting for will-navigate");
yield willNavigate;
info("Navigation to page 2 has started, the inspector should be empty");
assertMarkupViewIsEmpty();
info("Waiting for new-root");
yield inspector.once("new-root");
info("Navigation to page 2 was done, the inspector should be back up");
assertMarkupViewIsLoaded();
yield selectNode("#two", inspector);
function assertMarkupViewIsLoaded() {
let markupViewBox = inspector.panelDoc.getElementById("markup-box");
is(markupViewBox.childNodes.length, 1, "The markup-view is loaded");
}
function assertMarkupViewIsEmpty() {
let markupViewBox = inspector.panelDoc.getElementById("markup-box");
is(markupViewBox.childNodes.length, 0, "The markup-view is unloaded");
}
});

View file

@ -0,0 +1,44 @@
/* 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 void element display in the markupview.
const TEST_URL = URL_ROOT + "doc_markup_void_elements.html";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
let {win} = inspector.markup;
info("check non-void element closing tag is displayed");
let {editor} = yield getContainerForSelector("h1", inspector);
ok(!editor.elt.classList.contains("void-element"),
"h1 element does not have void-element class");
ok(!editor.elt.querySelector(".close").style.display !== "none",
"h1 element tag is not hidden");
info("check void element closing tag is hidden in HTML document");
let container = yield getContainerForSelector("img", inspector);
ok(container.editor.elt.classList.contains("void-element"),
"img element has the expected class");
let closeElement = container.editor.elt.querySelector(".close");
let computedStyle = win.getComputedStyle(closeElement, null);
ok(computedStyle.display === "none", "img closing tag is hidden");
info("check void element with pseudo element");
let hrNodeFront = yield getNodeFront("hr.before", inspector);
container = getContainerForNodeFront(hrNodeFront, inspector);
ok(container.editor.elt.classList.contains("void-element"),
"hr element has the expected class");
closeElement = container.editor.elt.querySelector(".close");
computedStyle = win.getComputedStyle(closeElement, null);
ok(computedStyle.display === "none", "hr closing tag is hidden");
info("check expanded void element closing tag is not hidden");
yield inspector.markup.expandNode(hrNodeFront);
yield waitForMultipleChildrenUpdates(inspector);
ok(container.expanded, "hr container is expanded");
computedStyle = win.getComputedStyle(closeElement, null);
ok(computedStyle.display === "none", "hr closing tag is not hidden anymore");
});

View file

@ -0,0 +1,28 @@
/* 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 void element display in the markupview.
const TEST_URL = URL_ROOT + "doc_markup_void_elements.xhtml";
add_task(function* () {
let {inspector} = yield openInspectorForURL(TEST_URL);
let {win} = inspector.markup;
info("check non-void element closing tag is displayed");
let {editor} = yield getContainerForSelector("h1", inspector);
ok(!editor.elt.classList.contains("void-element"),
"h1 element does not have void-element class");
ok(!editor.elt.querySelector(".close").style.display !== "none",
"h1 element tag is not hidden");
info("check void element closing tag is not hidden in XHTML document");
let container = yield getContainerForSelector("br", inspector);
ok(!container.editor.elt.classList.contains("void-element"),
"br element does not have void-element class");
let closeElement = container.editor.elt.querySelector(".close");
let computedStyle = win.getComputedStyle(closeElement, null);
ok(computedStyle.display !== "none", "br closing tag is not hidden");
});

View file

@ -0,0 +1,66 @@
/* 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 whitespace text nodes do show up in the markup-view when needed.
const TEST_URL = URL_ROOT + "doc_markup_whitespace.html";
add_task(function* () {
let {inspector, testActor} = yield openInspectorForURL(TEST_URL);
let {markup} = inspector;
yield markup.expandAll();
info("Verify the number of child nodes and child elements in body");
// Body has 5 element children, but there are 6 text nodes in there too, they come from
// the HTML file formatting (spaces and carriage returns).
let {numNodes, numChildren} = yield testActor.getNodeInfo("body");
is(numNodes, 11, "The body node has 11 child nodes (includes text nodes)");
is(numChildren, 5, "The body node has 5 child elements (only element nodes)");
// In body, there are only block-level elements, so whitespace text nodes do not have
// layout, so they should be skipped in the markup-view.
info("Check that the body's whitespace text node children aren't shown");
let bodyContainer = markup.getContainer(inspector.selection.nodeFront);
let childContainers = bodyContainer.getChildContainers();
is(childContainers.length, 5,
"Only the element nodes are shown in the markup view");
// div#inline has 3 element children, but there are 4 text nodes in there too, like in
// body, they come from spaces and carriage returns in the HTML file.
info("Verify the number of child nodes and child elements in div#inline");
({numNodes, numChildren} = yield testActor.getNodeInfo("#inline"));
is(numNodes, 7, "The div#inline node has 7 child nodes (includes text nodes)");
is(numChildren, 3, "The div#inline node has 3 child elements (only element nodes)");
// Within the inline formatting context in div#inline, the whitespace text nodes between
// the images have layout, so they should appear in the markup-view.
info("Check that the div#inline's whitespace text node children are shown");
yield selectNode("#inline", inspector);
let divContainer = markup.getContainer(inspector.selection.nodeFront);
childContainers = divContainer.getChildContainers();
is(childContainers.length, 5,
"Both the element nodes and some text nodes are shown in the markup view");
// div#pre has 2 element children, but there are 3 text nodes in there too, like in
// div#inline, they come from spaces and carriage returns in the HTML file.
info("Verify the number of child nodes and child elements in div#pre");
({numNodes, numChildren} = yield testActor.getNodeInfo("#pre"));
is(numNodes, 5, "The div#pre node has 5 child nodes (includes text nodes)");
is(numChildren, 2, "The div#pre node has 2 child elements (only element nodes)");
// Within the inline formatting context in div#pre, the whitespace text nodes between
// the images have layout, so they should appear in the markup-view, but since
// white-space is set to pre, then the whitespace text nodes before and after the first
// and last image should also appear.
info("Check that the div#pre's whitespace text node children are shown");
yield selectNode("#pre", inspector);
divContainer = markup.getContainer(inspector.selection.nodeFront);
childContainers = divContainer.getChildContainers();
is(childContainers.length, 5,
"Both the element nodes and all text nodes are shown in the markup view");
});

View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Anonymous content test</title>
<style type="text/css">
#pseudo::before {
content: "before";
}
#pseudo::after {
content: "after";
}
#shadow::before {
content: "Testing ::before on a shadow host";
}
</style>
</head>
<body>
<div id="pseudo"><span>middle</span></div>
<div id="shadow">light dom</div>
<div id="native"><video controls></video></div>
<script>
"use strict";
var host = document.querySelector("#shadow");
if (host.createShadowRoot) {
var root = host.createShadowRoot();
root.innerHTML = "<h3>Shadow DOM</h3><select multiple></select>";
}
</script>
</body>
</html>

View file

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=858038
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 858038</title>
<style>
#test::before {
content: 'This should not be draggable';
}
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=858038">Mozilla Bug 858038</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<input id="anonymousParent" /><span id="before">Before<!-- Force not-inline --></span>
<pre id="test"><span id="firstChild">First</span><span id="middleChild">Middle</span><span id="lastChild">Last</span></pre> <span id="after">After</span>
</body>
</html>

View file

@ -0,0 +1,87 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=858038
https://bugzilla.mozilla.org/show_bug.cgi?id=1226898
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 858038 and 1226898 - Autoscroll</title>
</head>
<body>
<div id="first"></div>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=858038">Mozilla Bug 858038</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1226898">Mozilla Bug 1226898</a>
<p id="display">Test</p>
<div id="content" style="display: none">
</div>
<!-- Make sure the markup-view has enough nodes shown by default that it has a scrollbar -->
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</body>
</html>

View file

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=858038
https://bugzilla.mozilla.org/show_bug.cgi?id=1226898
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 858038 and 1226898 - Autoscroll</title>
</head>
<body>
<div id="first"></div>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=858038">Mozilla Bug 858038</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1226898">Mozilla Bug 1226898</a>
<p id="display">Test</p>
<div id="content" style="display: none">
</div>
<!-- Make sure the markup-view has enough nodes shown by default that it has a scrollbar -->
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</body>
</html>

View file

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html class="html">
<body class="body">
<div class="node0">
<div id="node1" class="node1">line1</div>
<div id="node2" class="node2">line2</div>
<p class="node3">line3</p>
<!-- A comment -->
<p id="node4" class="node4">line4
<span class="node5">line5</span>
<span class="node6">line6</span>
<!-- A comment -->
<a class="node7">line7<span class="node8">line8</span></a>
<span class="node9">line9</span>
<span class="node10">line10</span>
<span class="node11">line11</span>
<a class="node12">line12<span class="node13">line13</span></a>
</p>
<p id="node14">line14</p>
<p class="node15">line15</p>
</div>
<div id="node16">
<p id="node17">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec posuere placerat magna et imperdiet.</p>
</div>
<div id="node18">
<div id="node19">
<div id="node20">
<div id="node21">
line21
</div>
</div>
</div>
</div>
<div id="node22" class="unchanged"></div>
<div id="node23"></div>
<div id="node24"></div>
<div id="retag-me">
<div id="retag-me-2"></div>
</div>
<div id="node25"></div>
<div id="node26" style='background-image: url("moz-page-thumb://thumbnail?url=http%3A%2F%2Fwww.mozilla.org%2F");'></div>
<div id="node27" class="Double &quot; and single &apos;"></div>
<img id="node-data-url" />
<div id="node-data-url-style"></div>
</body>
</html>

View file

@ -0,0 +1,19 @@
<html>
<head>
<meta charset="UTF-8">
<title>doc_markup_events-overflow.html</title>
</head>
<body>
<h1>doc_markup_events-overflow.html</h1>
<span id="events">Inspect me!</span>
<script>
"use strict";
var el = document.getElementById("events");
for (var i = 50; i > 0; i--) {
el.addEventListener("click", function onClick() {
alert("click");
});
}
</script>
</body>
</html>

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